CakePHPでログインフォームを作る

<?php
if($this->Session->check('Message.auth')){
    echo $this->Session->flash();// error msg
    echo $this->Session->flash('auth');// error msg
}
echo $form->create(
    'Admin',
    array(
        'url' => array(
            'controller' => 'users',
            'action'     => 'login'
        )
    )
);
?>
<div data-role="fieldcontain">
<dl>
<dt><label for="name">ユーザ名</label></dt>
<dd><?php
echo $form->input(
    'name',
    array(
        'div'   => false,
        'label' => false,
        'id'    => 'name'
    )
);
?></dd>
</dl>
</div>
<div data-role="fieldcontain">
<dl>
<dt><label for="password">パスワード</label></dt>
<dd><?php
echo $form->input(
    'password',
    array(
        'div'   => false,
        'label' => false,
        'id'    => 'password',
        'value' => ''
    )
);
?></dd>
</dl>
<p><?php
echo $form->submit(
    'ログイン',
    array(
        'div'   => false,
        'label' => false,
    )
);
?></p>
<?php
echo $form->end();
?>

MacのXAMPPにXdebugを入れる

UNIXベースなので以下のコマンドでインストールしてみる。

/Applications/XAMPP/xamppfiles/bin/pear upgrade pear channel-update pear.php.net
/Applications/XAMPP/xamppfiles/bin/pear upgrade pear upgrade PEAR
/Applications/XAMPP/xamppfiles/bin/pecl install xdebug

コンパイルで大量のエラーが出て上手くいかないはずだ。

■解決策

Komodo Remote Debugging Package Downloadsで、「Downloads > PHP Remote Debugging Client > Mac OS X (universal)」をクリックしてダウンロードし、PHPのバージョンに合ったファイルを以下のコマンドでコピーする。

cp /Users/[user]/Downloads/Komodo-PHPRemoteDebugging-6.1.0-60797-macosx/5.x/xdebug.so /Applications/XAMPP/xamppfiles/lib/php/php-5.x.x/extensions/no-debug-non-zts-20xxxxxx/xdebug.so

設定ファイル

以下のコマンドを実行する。

vi /Applications/XAMPP/xamppfiles/etc/php.ini

次に、以下の一行を加える。

[xdebug]
zend_extension ="/Application/XAMPP/xamppfiles/lib/php/php-5.x.x/extensions/no-debug-non-zts-20xxxxxx/xdebug.so"
xdebug.remote_enable = 1
xdebug.remote_host = 127.0.0.1
xdebug.remote_port = 9000
xdebug.remote_handler = dbgp
xdebug.profiler_enable = 1
xdebug.profiler_output_dir = "/Applications/XAMPP/xamppfiles/htdocs/_xdebug_profiler"
xdebug.profiler_output_name = cachegrind.out.%s
基本設定

ついでにマルチバイト系の設定をし忘れてたのでやっておく。

mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_output = UTF-8
expose_php = Off

500個めの記事でしたーσ°▽°)σ

eclipseでPHPの開発環境を構築する

忘れちゃうから書いておくことにしたφ(-ω-。`)。新しいマシンにを使うたびに古いマシンを見ながらセットアップするのは意外に手間だったり省エネでもないし。。。そんな感じで本年も宜しくお願いします。

■ダウンロード

eclipseのサイトから、Eclipse for PHP Developersを選んでダウンロードする。別のパッケージでもイイんだけど簡単にできるにこしたことはない。また、個人的にはPHP用のeclipseとしてJava用とは別にセットアップするのをお勧めする。

■起動

解凍後、eclipse.exeをクリックして起動する。workspaceはxamppのhtdocsディレクトリを指定するのが良いと思う。起動後、workbenchをクリックする。

■プラグイン

日本語化

まず、Pleiadesからプラグインをダウンロードする。

次に、ダウンロードしたファイルを解凍し、含まれているディレクトリ(plugins、featuresの二つ)をeclipse本体の同名ディレクトリに上書きする。

最後に、eclipseのディレクトリにあるeclipse.iniに以下のラインを追記する。

-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
Macの場合

eclipse/Eclipse.app/Contents/MacOS/eclipse.iniのファイルに以下を追記する。

-javaagent:../../../plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
日本語化の別解1:All in oneパッケージを使う

PleiadesからAll in Oneパッケージをインストールすると最初から日本語化されている。但し、現時点では32bit版のwindowsパッケージしかない。

日本語化の別解2:Babelを使う

まず、BabelのBabel Update Sitesの中から、eclipseのバージョンに合ったURLをコピーする。

次に、Eclipseに戻り「help > Install New Software」を選択し、Work withの欄に上述でコピーしたURLをペーストすると、各種言語が表示されるので「Japanese」だけ選んでインストールする。

但し、Windows Vista(32bit版)と7(64bit版)のPCを使用しeclipse 3.6の場合、ビューが開かなくなるという致命的な不具合が起こった。また、日本語化されていない部分がPleiadesより多い。

subversive

Gitブームだけど、まだまだ実際のプロジェクトでは現役なのでプラグインをインストールする。

まず、「ヘルプ > 新規ソフトウェアのインストール > 有効なソフトウェア・サイト」を選択し、フィルタに「subversive」と入力する。

次に、ピックアップされたURLのチェックボックスにチェックを入れOKをクリックしたら、作業対象の欄に「http://download.eclipse.org/technology/subversive/0.7/update-site/」と入力する。一覧にパッケージが表示されたら、全部選択しインストールする。

egit

やっぱりGit環境も必要なので以下のサイトを使用してプラグインをインストールする。

http://download.eclipse.org/egit/updates/

拡張フォーマット

より細かいフォーマット設定をPDTで行うためのプラグイン。sourceforgeからダウンロードしてインストールする。

Quantum Database Utility

データベースを操作するプラグイン。phpMyAdminがあるから必須というわけでもない。

まず、Quantum Database Utilityのサイトからダウンロードし、解凍したファイルをeclipseのプラグインディレクトリに配置する。

次に、MySQL JDBC(MySQLのJava用ドライバ)が必要なので、サイトからダウンロード・解凍したファイルの中の「mysql-connector-java-5.x.xx-bin.jar」を「C:\xampp\mysql\bin」に配置する。

MakeGood

PHPでテスト駆動開発をしたいのでインストールする。

ます、作業対象の欄に「http://eclipse.piece-framework.com/」と入力する。一覧にパッケージが表示されたら、「MakeGood」を選択しインストールする。

MakeGoodでのユニットテスト

Eclipse PDT 上でユニットテストを実行するためのテストランナーで、PHPUnitにも対応している。

ユニットテストのコード例

PHPUnitでは、例えば以下のようなテストコードでユニットテストをすることができる。今回の開発環境の構築には直接関係しないがなんとなく掲載しておく。

require_once 'PHPUnit/Framework.php';
require_once 'Shain.php';

class ShainTest extends PHPUnit_Framework_TestCase
{
    /**
     * testGetName
     * 社員の名前でインスタンス化し
     * getNameしたときに正しく名前を返すかチェックする
     */
    public function testGetName()
    {
        $shain = new Shain('yamada');
        $this->assertEquals('yamada', $shain->getName());
        $shain = new Shain('tanaka');
        $this->assertEquals('tanaka', $shain->getName());
    }
}

上述のテストコードは以下のコードに対応する。

class Shain
{
    private $_name;

    /**
     * __construct
     * @param string $name
     */
    public function __construct($name)
    {
        $this->_name = $name;
    }

    /**
     * getName
     * @return string
     */
    public function getName()
    {
        return $this->_name;
    }
}

ちなみにテストコードのコメントは丁寧に細かく書くこと。

■設定

「ウィンドウ > 設定」をクリックする。

テキスト・エディター

「一般 > エディター > テキスト・エディター」で「行番号の表示」と「空白文字の表示」にチェックを入れる。

文字コード

「一般 > ワークスペース > テキスト・ファイルのエンコード」で「その他 > UTF-8」を選択する。

タブ

「PHP > コード・スタイル > フォーマッター」でタブポリシーをスペースに、サイズを4にする。

PHP Executables

「PHP > PHP 実行可能ファイル」で「追加」をクリックし、以下のように設定する。

名前
PHP_5.3.1
実行可能ファイル・パス
C:\xampp\php\php.exe
/Applications/XAMPP/xamppfiles/bin/php
PHP ini ファイル
C:\xampp\php\php.ini
/Applications/XAMPP/etc/php.ini
SAPI Type
CLI
PHP デバッガー
XDebug

PHP インタープリター

「PHP > インタープリター」でデフォルトを設定する。新しくプロジェクトを作るときにも設定できるのでプロジェクトごとにバージョンが違ったりしている場合はそちらでも設定する。

PHP マニュアル

「PHP > PHP マニュアル」で「新規」をクリックし、以下のように日本語マニュアルを追加する。

名前
PHP.net/ja
リモートサイト
http://www.php.net/manual/ja

追加したら選択状態で「デフォルト」をクリックする。

デバッグ

「PHP > デバッグ」で以下のように設定する。

PHP デバッガー
XDebug
サーバー
Default PHP Web Server
PHP 実行可能ファイル
PHP_5.3.1

PHPライブラリー

「PHP > PHPライブラリー」で「新規」をクリックし、「PEAR」と入力し「Add to enviironment」にチェックを入れた後、「外部フォルダーの追加」をクリックし「C:\xampp\php\PEAR」を指定する。

但し、このままでは「MakeGood」でインクルードしてくれないので、プロジェクトで右クリックし「プロパティ > PHPインクルード・パス > ライブラリー > ライブラリーの追加」で上述の「PEAR」を追加し、パスを通す必要がある。

アウトラインビュー

メソッドの戻り型を表示したいので、「PHP > 外観」の「メソッド戻り型の表示」にチェックを入れる。

■表示

タスク

//TODOなどのコメントを一覧表示してくれるプロジェクトの味方。

「ウィンドウ > ビュー > タスク」をクリックして表示させておく。

テンプレートファイル

CakePHPの.ctpファイルなどPHPとして表示して欲しい場合は以下のように設定する。

  • 「一般 > コンテンツタイプ」の「PHP Content Type」に*.ctpを追加する。
  • 「一般 > エディタ > File Associations」の「PHP Content Type」に*.ctpを追加しPHP Editorをデフォルトに指定する。

再起動すると.ctpファイルがPHPと同じようにカラーリングされる。

■XDebug

xamppに含まれているXDebugを前回の記事を参考にして有効にすればPHPのステップ実行も可能になる。

PHPで並列通信を行う

何年か前のドキュメントが出てきたので一応、書きとめておくよ(「・ω・)「がおー

■コード

以下のようにすることで並列通信を行うことができる。

$i   = 0;
$ch  = array();
$cmh = curl_multi_init();
foreach($urls as $url){
    $ch[$i] = curl_init($url);
    curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch[$i], CURLOPT_FAILONERROR, true);
    curl_setopt($ch[$i], CURLOPT_TIMEOUT, 10);
    curl_multi_add_handle($cmh, $ch[$i]);
    $i++;
}

// execute
$active = null;
do{
    $mrc = curl_multi_exec($cmh, $active);
}
while($mrc === CURLM_CALL_MULTI_PERFORM);
while($active && $mrc === CURLM_OK){
    if(curl_multi_select($cmh) !== false){
        do{
            $mrc = curl_multi_exec($cmh, $active);
        }
        while($mrc === CURLM_CALL_MULTI_PERFORM);
    }
}

//read the data from the result in handler
if($mrc === CURLM_OK){
    for($s = 0; $s < $i; $s++){
        if(curl_error($ch[$s]) == ''){// success
            $contents = curl_multi_getcontent($ch[$s]);
        }
        else{
            var_dump(curl_error($ch[$s]));
        }
    curl_multi_remove_handle($cmh, $ch[$s]);
    curl_close($ch[$s]);
    }
}
curl_multi_close($cmh);

外部のAPIを利用しAPIのレスポンスが低速である場合に特に有用である。但し、同時に開けるソケット数には限りがあるので、接続数がソケット上限数(定数:SOMAXCONN)を超える場合は、上述のロジックを改修する必要がある。

CentOSにMongoDBをインストールする

■インストール

yumリポジトリの追加

以下のコマンドでリポジトリを追加する。

vi /etc/yum.repos.d/mongo.repo

以下のようにファイルの中身を記述する。

[10gen]
name=10gen Repository
baseurl=http://downloads.mongodb.org/distros/centos/5.4/os/i386/
gpgcheck=0

保存したら以下のコマンドを実行する。

yum install mongo-stable*

起動

以下のコマンドで起動してみる。

/etc/init.d/mongod start

以下のコマンドで起動したか確認する。

lsof -i:27017

以下のコマンドで自動起動を設定する。

chkconfig mongod on
chkconfig mongod --list

参考

CentOS and Fedora Packages

amazon linuxにインストールする

wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.0.2.tgz
tar xvzf mongodb-linux-x86_64-2.0.2.tgz
mv mongodb-linux-x86_64-2.0.2 /var/lib/mongodb
mkdir /mnt/db
/var/lib/mongodb/bin/mongod --fork --logpath ~/mongod.log --dbpath /mnt/db/

■PHPから扱う準備

以下のコマンドでpecl_mongoをインストールする。

pecl clear-cache
pecl install mongo

以下のコマンドで設定ファイルを生成する。

cp /etc/php.d/curl.ini /etc/php.d/mongo.ini
vi /etc/php.d/mongo.ini

設定ファイルは以下のような記述だ。

; Enable mongo extension module
extension=mongo.so

設定が終わったらhttpdをreloadする。

/etc/init.d/httpd reload

参考

PHP & MongoDB Sitting in a Tree: Part 1

英語だが非常に参考になるドキュメントだ。

■ベンチマーク

以下のコードを使用してベンチマークしてみた。

$dbh = new Mongo();
$dbh = $dbh->testdb;
$col = $dbh->bench;
$start = microtime(true);
for($i = 0; $i < 1000; $i++){
    $col->insert(
        array(
            'key'   => "key{$i}",
            'value' => "abcdefghijklmnopqrstuvwxyz"
        ),
        true
    );
}
$end = microtime(true);
print($end - $start);0.66766786575317
$dbh->close();

但し、2回目以降は0.2秒以下になる。

データを取り出す

本当にデータが挿入されているのか不安になったので、以下のコードを使用してデータを覗いてみた。

$res = $col->find();
$s = 0;
foreach($res as $doc){
    print("<pre>{$s}");
    var_dump($doc);
    print('</pre>');
    $s++;
}
$dbh->close();

ベンチマークをしておいて言うのもオカシイが、データストアにおいて全く同じ条件というものは再現できないので単純に比較してはならない。用途に応じた選択が必要である。

amazon Linuxにインストールする

amazon Linuxにインストールする場合は以下のようにする。

curl -O  http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.0.2.tgz
tar xzf mongodb-linux-x86_64-2.0.2.tgz
mv mongodb-linux-x86_64-2.0.2 /var/lib/mongodb
cd /var/lib/mongodb/bin
mkdir /mnt/db
./mongod --fork --logpath /var/log/mongod.log --dbpath /mnt/db/

memcachedをインストールする

あまり興味がないが仕事で使うので試してみた。♪(´ε` )

■インストール

以下のコマンドを実行してmemcachedをインストールする。

yum install memcached
/etc/init.d/memcached start
chkconfig memcached on

設定ファイルは以下のコマンドで編集できる。編集が必要な場合は書き換えると良い。

vi /etc/sysconfig/memcached

PHPから使いたいので以下のようにpeclコマンドでインストールする。

pecl clear-cache
pecl install memcache
cp /etc/php.d/curl.ini /etc/php.d/memcache.ini
vi /etc/php.d/memcache.ini

以下のようにファイルを記述する。

; Enable memcache extension module
extension=memcache.so

ファイルを上書き保存したらhttpをreloadする。

/etc/init.d/httpd reload

■ベンチマーク

以下のコードを使用し簡単にベンチマークしてみた。

$memcache = new Memcache();
$memcache->connect('localhost', 11211);
$start = microtime(true);
for($i = 0; $i < 1000; $i++){
    $memcache->set("k{$i}", "abcdefghijklmnopqrstuvwxyz");
}
$end = microtime(true);
print($end - $start);// 0.07976508140564

さすがメモリにしかデータがないだけあって爆速だ。

GDとImageMagickの速度を比較してみた

■GD

以下のようなコードを用いてGDで合成画像を1000枚生成した時の時間を調べた。

$layers = array(
    0 => 'dress_back.png',
    1 => 'dress_back.png',
    2 => 'body.png',
    3 => 'dress.png',
    4 => 'bag.png',
    5 => 'bag.png',
    6 => 'face.png',
    7 => 'hear.png',
    8 => 'teara.png',
);
$start = microtime(true);
for($i = 0; $i < 10; $i++){
    $image = imagecreatefrompng("background.png");
    foreach($layers as $key => $value){
        $layer = imagecreatefrompng($value);
        imagecopy($image, $layer, 0, 0, 0, 0, 410, 454);
    }
    imagegif($image, "image{$i}.gif");
}
$end = microtime(true);
print($end - $start);

/*
 * windows
 * 10 => 0.27269101142883
 * 100 => 2.1620790958405
 * 1000 => 24.812913894653
 * 
 * linux
 * 10 => 0.21701502799988
 * 100 => 2.1362149715424
 * 1000 => 21.695859193802
 */

■ImageMagic

以下のようなコードを用いてImageMagickで合成画像を1000枚生成した時の時間を調べた。

$layers = array(
    0 => 'dress_back.png',
    1 => 'dress_back.png',
    2 => 'body.png',
    3 => 'dress.png',
    4 => 'bag.png',
    5 => 'bag.png',
    6 => 'face.png',
    7 => 'hear.png',
    8 => 'teara.png',
);
set_time_limit(0);
//$path = 'C:\xampp\htdocs\local.sample.org\public_html\\';
$path = '/home/local.sample.org/trunk/public_html/imagick/';
$start = microtime(true);
for($i = 0; $i < 1000; $i++){
    $image = new Imagick("{$path}background.png");
    foreach($layers as $key => $value){
        $layer = new Imagick($path . $value);
        $image->compositeImage($layer, $layer->getImageCompose(), 0, 0);
    }
    $image->writeImage("{$path}image{$i}.gif");
}
$end = microtime(true);
print($end - $start);

/*
 * windows
 * 10 => 2.2297260761261
 * 100 => 24.065160989761
 * 1000 => 247.36853098869
 * 
 * linux
 * 10 => 0.33637809753418
 * 100 => 3.3278291225433
 * 1000 => 33.274304866791
 */

■結果

Linuxの場合は1.5倍ImageMagickが遅かった。Windowsの場合は10倍ImageMagickが遅かった。

PHP5.3の名前空間を使ってみる

そういえば今まであんまり使わなかったけど、PHP5.3の名前空間を使ってみる。

namespace Lib\Mobile;

class Emoji{
    public function getEmoji(){
        return '絵文字一覧です';
    }
}

上述のように定義した場合は、以下のように使用することができる。

require_once 'Emoji.php';

$emoji = new Lib\Mobile\Emoji();
var_dump($emoji->getEmoji());// 絵文字一覧です

また、以下のようにuseを使用してインポートを先頭で明示することもできる。

require_once 'Emoji.php';
use Lib\Mobile as MobileLib;

$emoji = new MobileLib\Emoji();
var_dump($emoji->getEmoji());// 絵文字一覧です

asを使用しなかった場合は以下のように最後の単語がasの後にあるようなイメージだ。

require_once 'Emoji.php';
use Lib\Mobile;

$emoji = new Mobile\Emoji();
var_dump($emoji->getEmoji());// 絵文字一覧です

なんとなーく現時点では使いそうもないなーφ(-ω-。`)。

PHP5.3の遅延静的束縛を使ってみる

そういえば今まであんまり使わなかったけど、遅延静的束縛というものを使ってみる。

class Animal{
    public function cry(){
        print(self::_getVoice());
    }
    protected static function _getVoice(){
        return '(「・ω・)「がおー';
    }
}
class Dog extends Animal{
    protected static function _getVoice(){
        return 'bow!';
    }
}
$pochi = new Dog();
$pochi->cry();// (「・ω・)「がおー

マニュアルを参照すると以下のような記述がされている。

静的遅延束縛は直近の “非転送コール”(self:: や parent::、static:: による静的なコール、 あるいはクラス階層の中での forward_static_call() によるコール) のクラス名を保存します。 静的メソッドの場合、これは明示的に指定されたクラス (通常は :: 演算子の左側に書かれたもの) となります。静的メソッド以外の場合は、そのオブジェクトのクラスとなります。 get_called_class() 関数を使うとコール元のクラス名を文字列で取得できます。 static:: はこのクラスのスコープとなります。

selfでは直近のクラスが参照されるので、上述の例の場合はselfはAnimalクラスということになる。pochiにもっと犬らしくして欲しい時は以下のようにstaticを用いて記述する。

<?php
class Animal{
    public function cry(){
        print(static::_getVoice());
    }
    protected static function _getVoice(){
        return '(「・ω・)「がおー';
    }
}
class Dog extends Animal{
    protected static function _getVoice(){
        return 'bow!';
    }
}
$pochi = new Dog();
$pochi->cry();// bow!

親クラスから子クラスのメソッドが呼び出される感じなのでアクセス権はprotected以上でないと「Fatal error: Call to private method」となる。

Pythonでは以下のように問題なく、selfを使用することができる。

class Animal:
    def cry(self):
        print(self._getVoice())
    def _getVoice(self):
        return 'gao!'

class Dog(Animal):
    def _getVoice(self):
        return 'bow!'

pochi = Dog()
pochi.cry()# bow!

Javaの場合はそもそもselfがない。クラス名を直接指定する必要があり、明示しない時はカレントクラスのメソッドがコールされる。

static class Animal{
    public static String cry(){
        return getVoice();// 明示しない場合はAnimal.となる
    }
    protected static String getVoice(){
        return "(「・ω・)「がおー";
    }
}
static class Dog extends Animal{
    protected static String getVoice(){
        return "bow!";
    }
}
Dog pochi = new Dog();
Log.e("cry", pochi.cry());// (「・ω・)「がおー

Tokyo Tyrantを使ってみる

仕事で使うかもしれないので一応やってみる。

■インストール

wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.46.tar.gz
wget http://fallabs.com/tokyotyrant/tokyotyrant-1.1.41.tar.gz
tar xvzf tokyocabinet-1.4.46.tar.gz
tar xvzf tokyotyrant-1.1.41.tar.gz
cd tokyocabinet-1.4.46
./configure
make
make install
cd ../tokyotyrant-1.1.41
./configure

エラー1

tokyo cabinetが先にインストールされていないと以下のエラーがでる。

checking for tcutil.h... no
configure: error: tcutil.h is required
make
make install

ちょっと動かしてみる。

ttserver

■PHPから使う

pecl install tokyo_tyrant-beta
cp /etc/php.d/curl.ini /etc/php.d/tt.ini

元の記述を削除して、以下の記述に書き換える。

extension=tokyo_tyrant.so

■ベンチマーク

以下のコードを使用して簡単にベンチマークしてみた。

$start = microtime(true);
$tt    = new TokyoTyrant("localhost");
for($i = 0; $i < 10000; $i++){
    $tt->put("k{$i}", "abcdefghijglmnopqrstuvwxyz");
}
$end = microtime(true);
print($end - $start);//0.65114498138428

ベンチマークをしておいて言うのもオカシイが、データストアにおいて全く同じ条件というものは再現できないので単純に比較してはならない。用途に応じた選択が必要である。