ラベル php の投稿を表示しています。 すべての投稿を表示
ラベル php の投稿を表示しています。 すべての投稿を表示

2012年9月21日金曜日

PHPのarrayの入れ子を作るのに苦労して=&とunsetを使って何とかした話

PHPで、

こんな感じのDBから読んできたデータから、


こんな構造を作りたいなと思ったのです。

こんな感じかな。
<?php
//ここから
function row($type,$typeName,$value1,$value2){
    return array("type" => $type,
                 "typeName" => $typeName,
                 "value1" => $value1,
                 "value2" => $value2);
}
$rows = array(row(1,"あ","ABC","DEF"),
            row(1,"あ","AAA","BBB"),
            row(1,"あ","XXX","YYY"),
            row(2,"い","BEEF","PORK"),
            row(2,"い","COFFEE","TEA"),
            row(2,"い","MILK","COCOA"));
//ここまではサンプルデータを作っているところなので本題とは関係なし。
//データはソートはされているものとする。

$tree = array();    // $treeが最終的なルート配列オブジェクト
$prevType = null;   // Typeが変わったらこの処理をする…というためのもの
foreach($rows as $r){  //1行ずつ読む
    if($prevType !== $r["type"]){ //もしTypeが変わったら
        // 変更チェック用の変数を更新し
     $prevType = $r["type"];
        // 親のノードを新規作成し、$typenodeを差し替え
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array()); // 親のノードは子を格納する配列を持つ
        // 作った親のノードをルート配列に追加
        $tree[] = $typenode;
    }
    // 子のノードを作成
    $valuenode = array("value1" => $r["value1"],
                        "value2" => $r["value2"]);
    // 今の時点で $typenode で親ノードが参照出来るはずで、
    // それに対して"values"で引ける子ノード格納用配列に、
    // 子のノードを追加
    $typenode["values"][] = $valuenode;
}
実行してみた結果。
( ಠ益ಠ)
ステップ実行してみると、
        :
        // 作った親のノードをルート配列に追加
        $tree[] = $typenode;
    }
        :
    // 今の時点で $typenode で親ノードが参照出来るはずで、
    // それに対して"values"で引ける子ノード格納用配列に、
    // 子のノードを追加
    $typenode["values"][] = $valuenode;
}
この下の方の$valuenodeを追加しているところで、
「$typenode」には追加されるものの、
「$treeからたどれる『$typenodeと同じものであるはずのもの』」
には追加されているように見えない。
        $tree[] = $typenode;
で、$typenodeそのものがコピーされてしまっているように見える。
本当は違っててその後変更が発生しそうになった時にコピーされるんだろうけど。

なのでこうしてみた。=&で参照渡し的な何かになるはずと聞いて。
        $tree[] =& $typenode;
実行してみた結果。
(╬ಠ益ಠ)

今度は、二週目の
        // 親のノードを新規作成し、$typenodeを差し替え
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array()); // 親のノードは子を格納する配列を持つ
        // 作った親のノードをルート配列に追加
        $tree[] =& $typenode;
の上の方のところで「新しいノードを作って$typenodeを差し替えた」だけのつもりが、
既に一周目でセットした$tree[0]の要素までも差し替わってしまった。

参照渡し…ってそこまで参照なの!?
これ、そもそもマインドモデルが上の図と違ってて、模式図で表せない。

最終的にこうしたら何とかなった。
$tree = array();
$prevType = null;
foreach($rows as $r){
    if($prevType !== $r["type"]){
        $prevType = $r["type"];
        unset($typenode);
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array());
        $tree[] =& $typenode;
    }
    $valuenode = array("value1" => $r["value1"],
                        "value2" => $r["value2"]);
    $typenode["values"][] = $valuenode;
}
差し替える前にunsetをする事で、
$typenodeというシンボルと実体との紐付けが解放されるので、
あらためて作ったarrayをセットしても既存のデータ構造に影響を与えない。

なんだこの仕様。

array関数で新たに配列作って変数に代入する、って
「mallocしてそのポインタを返す」的な感覚かと思ってたら、
「返す先のポインタがあったら指している領域に上書きする」みたいな
日本語すら怪しくなるような動きもするとは。
理解に苦しむ。

2012年6月14日木曜日

ubuntuにapache-google-apps-ssoをインストール

https://github.com/epotocko/apache-google-apps-sso
ApacheのレイヤーでGoogle Apps認証かけちゃうというもの。
mod_auth_memcookieというモジュールとphpを使ってる。

まずapt関係で必要なものをゲット。
apt-get install memcached php5-memcache
apt-get install apache2-prefork-dev libmemcache-dev
次に、mod_auth_memcookieをビルド。
http://sourceforge.net/projects/authmemcookie/files/
からソースをDLし展開。
tar zf mod_authmemcookie_v1.0.2.tar.gz
cd mod_authmemcookie_v1.0.2
ubuntuの場合apxs2のインストールパスが違うので、Makefileを修正。
MY_APXS=/usr/sbin/apxs2
        ↓
MY_APXS=/usr/bin/apxs2
ビルド&インストール。
make
sudo make install
apacheのロードスクリプトを書く。
/etc/apache2/mods-available/auth_memcookie.load
#一行で書く
LoadModule mod_auth_memcookie_module /usr/lib/apache2/modules/mod_auth_memcookie.so
有効化。
sudo a2enmod auth_memcookie

引き続き、phpなどの設定。

/var/www/auth ディレクトリを認証モジュール用に使い、
その他サイト全体を認証の対象とすることにする。

https://github.com/epotocko/apache-google-apps-sso
の中のsrc/public直下のphpファイルと、src/GAppsディレクトリ自体を
/var/www/auth/下にコピー。
git clone https://github.com/epotocko/apache-google-apps-sso.git
cd apache-google-apps-sso/src
sudo mkdir /var/www/auth
sudo cp -rf GApps /var/www/auth/
sudo cp -rf public/* /var/www/auth/.
次にphp-openid。
12.04ならばaptで入れたものでもOKだった。
apt-get install php-openid
10.04だとバージョンが古くてうまく動かなかったので、公式から落としてきて
その中のAuthディレクトリを/var/www/auth/以下にコピーする。
git clone https://github.com/openid/php-openid.git
cp -rf php-openid/Auth /var/www/auth/
ここから下は https://github.com/epotocko/apache-google-apps-sso の
公式の情報と基本的に同じ。

/var/www/auth/settings.phpファイルを更新。
コメントアウトされていない二行を編集。
GApps_Session::$BASE_URL = 'http://【ホスト名】/auth/'; //動かすホスト名
GApps_Session::$DOMAIN_NAME = '【Google Appsドメイン名】';
apacheの設定を書き足す。
default編集するなり、別ファイル作ってVirtualHostに入れるなり。
<IfModule mod_auth_memcookie.c>
    <Location />
        Auth_memCookie_CookieName GOOG_SESSIONID
        Auth_memCookie_Memcached_AddrPort 127.0.0.1:11211
        ErrorDocument 401 "/auth/login.php"
        Auth_memCookie_Authoritative on
        AuthType Cookie
        AuthName "GApps Login"
    </Location>
</IfModule>

<LocationMatch "^/(?!auth)">
    Require valid-user
</LocationMatch>
apache再起動。
sudo /etc/init.d/apache restart

2012年3月28日水曜日

Zend_Db_Tableでinsert時に新しいidが返ってこなかったけど解決

Zend_Db_Table使ってるモデルクラスではinsertすると
新しく振られた主キーが帰ってくるという説明になっているが
なぜか0が返ってくる。

調べてみる。これだ。
http://www.refreshinglyblue.com/2008/11/03/zend_db_table-not-returning-last_insert_id/

渡す連想配列に"id" => nullを付けたらうまくいった。

2012年2月24日金曜日

Aptana Studio 3は結局イマイチ

Aptana Studio 3をスタンドアロンでインストールしたら
xdebugでのPHPがデバッグ出来なくて残念だったのですが。

Eclipseのプラグイン版もあったなーと思ってそれを入れてみたところ、
やっぱりデバッグできなくなってしまいました。
ブレークポイントで止まってくれません。
「先頭でデバッグ」は止まるのですがそれじゃどうにも。

coffeeとかlessのシンタックスハイライトだけ出来りゃいいんだけどなあ。

ちなみにプラグインをアンインストールしたらとりあえず元の状態に戻れました。
PHPのデバッグは出来るようになっても、なにやら起動時に
An internal error occurred during: "Loading bundle: /home/XXXXXX/.eclipse/org.eclipse.platform_3.7.0_155965261/configuration/org.eclipse.osgi/bundles/174/1/.cp/bundles/coffeescript.ruble".
(LoadError) no such file to load -- ruble/ui
とか出たりPreferencesの画面やメニューバー[Window][Help]のところに「Aptana」みたいなのが残って
とても気持ちが悪い。

以下、自己責任で。
1.Eclipseを終了。
2.ホームディレクトリ以下にある
 .eclipse/org.eclipse.platform_3.7.0_155965261/plugins
 以下の、「com.aptana」で始まるディレクトリを全消し。
3.Eclipseを起動。
4.落ちたらeclipseに関するプロセスが動いていないか確認して動いていたら殺す。
5.3に戻る

2011年8月22日月曜日

phpでGoogle appsアカウントのOpenID

この概要は表示できません。投稿を閲覧するには ここをクリック してください。

2011年8月19日金曜日

h2o-phpにifequal追加してみた


h2o-php テンプレートエンジン。

ifequalテンプレートタグが無かった。

別に if x == y で済むけど。適当に実装してみる。
tags.phpの最後にでも追加する。
class Ifequal_Tag extends H2o_Node {
    private $body;
    private $else;
   
    function __construct($argstring, $parser, $position = 0) {
        $this->body = $parser->parse(‘endifequal’, ‘else’);
        if ($parser->token->content === ‘else’)
            $this->else = $parser->parse(‘endifequal’);
         $this->args = H2o_Parser::parseArguments($argstring);
    }

    function render($context, $stream) {
        $argleft = $context->resolve($this->args[0]);
        $argright = $context->resolve($this->args[1]);
        if ($argleft != $argright) {
            if($this->else)
                $this->else->render($context, $stream);
        } else{
            $this->body->render($context, $stream);
        }
    }
}
はい適当。
あと最後のH2o::addTagにも’ifequal’を追加する。