まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:cakephp

PHP の MVC フレームワークの1つである CakePHP は、デフォルト設定の場合はその内部キャッシュにファイルシステムが使われています。

もちろんこれでも動くのですが、このキャッシュを memcached(メモリサーバー)にすることで、比較的簡単に高速化を実現することができます。以下は CakePHP 2.x を使う前提ですが、キャッシュに memcached を利用する方法を紹介します。


まずは memcached と、PHP から memcached を利用するための pecl-memcache をインストールしておきます:
# yum install memcached php-pecl-memcache -y

このコマンドが失敗する場合は yum リポジトリが足りていない可能性が高いので、以下のコマンドを実行してから再度 yum install してみてください(RHEL 6.x x86_64 の場合):
# rpm -Uhv http://ftp.riken.jp/Linux/repoforge/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm

memcached と pecl-memcache がインストールできたら memcached を起動し、httpd を再起動します:
# /etc/init.d/memcached start
# chkconfig memcached on
# /etc/init.d/httpd restart

これで memcached の用意ができました。では CakePHP 側の設定を変更して、この memcached を利用するようにしてみましょう。app/Config/core.php ファイルを編集し、以下の設定を加えます:
# vi app/Config/core.php

  :
  :
//. デフォルトのキャッシュ設定(Cache::config で始まっている設定)が有効になっていたらコメントで無効にする //. Cache::config( "default", array( "engine" => "File" ) );
:
: //. デフォルトでは memcached にキャッシュするよう設定を追加 Cache::config( "default", array( "engine" => "Memcache", // 保存先は memcache "duration" => 3600, // キャッシュの有効時間は3600秒 "probability" => 100, // キャッシュ再作成率は100%(全て) "prefix" => Inflector::slug( APP_DIR ) . "_", // キャッシュ名のプレフィクスは定数 APP_DIR + "_" "servers" => array( "127.0.0.1:11211" ), // memcached サーバーとポート番号 "compress" => false // キャッシュは圧縮しない ));
: :

では現在までに作成されたキャッシュを全てクリアします:
# cd app/tmp/cache
# rf -rf ./*

この後に CakePHP を使ってみて、app/tmp/cache 以下にフォルダが作成されていないことが確認できれば成功です。

前回、LAMP 環境を構築した IBM LinuxONE サーバーを使って、PHP のメジャーな MVC フレームワークの1つであるCakePHP の環境を整えてみます:
IBM LinuxONE コミュニティクラウド上で LAMP 環境を作る


まず CakePHP を動かす場合の PHP 設定を行います。/etc/php.ini を適宜変更するのですが、最低限やっておかないといけないのが、タイムゾーンの設定です。/etc/php.ini を編集して、以下の設定を加えます([Date] カテゴリ内でコメントアウトされている Date.timezone の設定からコメントを外し、"Asia/Tokyo" に設定して保存します:
$ sudo vi /etc/php.ini

  :
  :
[Date]
Date.timezone = "Asia/Tokyo"
  :
  :

また CakePHP では PHPUnit というモジュールを使うことになるので、これもインストールしておきます。前回の LAMP 環境構築時に pear もインストールしているので、pear を使って PHPUnit を導入します:
$ sudo pear install pear/PHPUnit

次に MySQL の設定を行います。まずは文字コードの設定を変更して、デフォルトで UTF-8 を使えるようにします:
$ sudo vi /etc/my.ini

[mysqld]
character-set-server=utf8

[mysql]
default-character-set=utf8



今回は CakePHP 専用のデータベース(cakedb)を新たに作成し、その中に商品情報を格納するマスターテーブル(items)と、商品カテゴリを格納するマスターテーブル(categories)を定義することにします:
$ mysql -u root -p

mysql> create database cakedb default character set utf8;
mysql> use cakedb
mysql> create table items( id int primary key auto_increment, name varchar(50), category_id int, created datetime default null, modified datetime default null );
mysql> create table categories( id int primary key auto_increment, name varchar(50), created datetime default null, modified datetime default null );
mysql> quit

1つのデータベースと、2つのテーブルを作りました。必要に応じてこれらにアクセスできるユーザーなどを追加しましょう。

これら2つのマスターテーブルを操作できるような環境を CakePHP で作ることにしましょう。ここは必須ではありませんが、データベースを操作する上では phpMyAdmin があると便利です。IBM LinuxONE コミュニティクラウドのサーバーに phpMyAdmin 環境を導入する場合の手順はこちらの記事を参考にしてください:
IBM LinuxONE コミュニティクラウド上に phpMyAdmin を導入する


ではいよいよメインディッシュの CakePHP 環境を構築します。PHP 5.3 でも動くよう、CakePHP のバージョンは 2.x を使うことにします。またこれも Apache HTTPD のドキュメントルートがデフォルトのままの /var/www/html であるとして作業を紹介します:
$ https://github.com/cakephp/cakephp/archive/2.9.4.zip
$ sudo /bin/bash
# cd /var/www/html
# unzip ~linux1/2.9.4.zip
# mv cakephp-2.9.4 cakephp
# chmod 777 -R cakephp/app/tmp
# chmod 755 cakephp/lib/Cake/Console/cake
# cd cakephp/app/Config
# vi core.php

  :
  :
/**
 * A random string used in security hashing methods.
 */
        Configure::write('Security.salt', 'ABCDabcd1234');

/**
 * A random numeric string (digits only) used to encrypt/decrypt strings.
 */
        Configure::write('Security.cipherSeed', '1234567890');
  :
  :

最後の cakephp/app/Config/core.php の編集作業では 'Security.salt' の値と、'Security.cipherSeed' の値はデフォルトの(既知の)値のままだと危ないのでランダムな値に書き換えました。

続けて(カレントディレクトリが cake/app/Config/ の状態で)、更にデータベースの設定ファイルを用意して、自分の環境に合わせた設定を行います:
# cp database.php.default database.php
# vi database.php

  :
  :
class DATABASE_CONFIG {

        public $default = array(
                'datasource' => 'Database/Mysql',
                'persistent' => false,
                'host' => 'localhost',
                'login' => 'root',
                'password' => 'P@ssw0rd',
                'database' => 'cakedb',
                'prefix' => '',
                //'encoding' => 'utf8',
        );
  :
  :

↑具体的にはユーザー名(login)、パスワード(password)、データベース(database)の値を書き換えます。


CakePHP 自体はここまでの設定で動くはずです。必要に応じて DebugKit などの便利なプラグインを cakephp/app/Plugin/ 以下に追加で導入してください。DebugKit の導入に関してはこちらを参照ください:
https://github.com/cakephp/debug_kit/tree/2.2


ブラウザで http://(IPアドレス)/cakephp/ にアクセスすると、CakePHP のホーム画面が表示されます。緑と黄色のバーが並んでいる状態であれば、少なくとも設定は間違っていないことになります。下図では DebugKit まで導入して、全て緑になっている状態です:
2017010603

 

IBM Bluemix 上で CakePHP を動かす」。実はこれ、自分が Bluemix に携わるようになった直後くらいから挑戦しては跳ね返されて、少し環境が変わってはまた挑戦して挫折して・・・を繰り返してきたテーマでした。実は意外と難しいんです。

が、先日のランタイムアップデートで PHP ランタイムの環境も変わり、その後の環境であればなんとか動せることが分かりました。その手順を紹介します。


まずは Bluemix に PHP ランタイムと MySQL データベースを用意します。その辺りの手順はこちらのエントリを参照してください。このエントリでは WordPress の導入方法を紹介していますが、そこまで行う必要はなく、PHP ランタイムと MySQL データベースサービスを作成して、接続情報の環境変数を確認して、cf ツールをインストールするところまでを参考にしてください:
IBM Bluemix 上に WordPress 環境を構築する(2015/06/28)


では改めて Bluemix 上に構築した PHP + MySQL 環境上に CakePHP と、データベース管理目的で phpMyAdmin をインストールしてみましょう。


まずは専用の空フォルダを1つ用意します。この例では C:\tmp\cake というフォルダを新たに作りました。このフォルダが PHP サーバーのドキュメントルートになるイメージです:
2015062900


次に CakePHP のコードを入手します。公式ページに移動し、2.x 系の最新バージョンをダウンロードします(3.x でも動くかもしれませんが未検証です)。この図では 2.6.7 が最新バージョンになっており、ダウンロードするファイルは cakephp-2.6.7.zip というものでした:
2015062901


この zip ファイルを展開して、特定のフォルダに保存します。この例では C:\tmp\cake フォルダに cakephp というフォルダ名で保存しています:
2015062902


次に CakePHP の設定ファイルをこの環境に合わせて2ファイル変更します。まずは app\Config\core.php ファイルをテキストエディタで開き、以下の2箇所を変更して保存します:
/**
 * A random string used in security hashing methods. Security.salt を適当な文字列に変更
 */
	Configure::write('Security.salt', 'ABCDabcd1234');

/**
 * A random numeric string (digits only) used to encrypt/decrypt strings. Security.cipherSeed を適当な数値文字列に変更
 */
	Configure::write('Security.cipherSeed', '1234567890');

続いて app\Config\database.php.default を app\Config\database.php にリネームし、更に以下の箇所を変更して保存します:
class DATABASE_CONFIG {

  public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => '(接続情報の host の値)',
    'port' => '(接続情報の port の値)',
    'login' => '(接続情報の username の値)',
    'password' => '(接続情報の password の値)',
    'database' => '(接続情報の name の値)',
    'prefix' => '',
    //'encoding' => 'utf8',
  );
: :

(補足)
この後 cf コマンドでデプロイする場合の CakePHP 側の作業はここまでですが、IDS(IBM DevOps Services) を使ってデプロイする場合は、更にもう1ファイルの変更が必要です。

CakePHP の zip ファイルを展開したフォルダ直下に .gitignore というファイルがあります。この中で /app/Config/database.php ファイルが指定されています。このままだと(リネーム後の) database.php の存在が認識されないため、.gitignore を編集して、この一行の先頭に # を入れコメント行扱いにしてください:
# User specific & automatically generated files #
#################################################
#/app/Config/database.php
/app/tmp
/lib/Cake/Console/Templates/skel/tmp/
  :
  :
(補足終わり)


これで CakePHP の準備ができました。このままデプロイすれば CakePHP 環境としては使えるのですが、MySQL データベースの管理が不便なので、phpMyAdmin 環境も合わせて用意することにします。

まずは phpMyAdmin のコードを入手します。公式ページにアクセスし、最新版モジュール(この図では 4.4.10 でファイル名は phpMyAdmin-4.4.10-all-languages.zip)をダウンロードします:
2015062903


この zip ファイルを展開して、上記で CakePHP を保存したのと同じフォルダに保存します。この例では展開先フォルダを phpMyAdmin としています:
2015062904


次に phpMyAdmin の設定ファイルをこの環境に合わせて変更します。展開先フォルダ直下の config.sample.inc.php を config.inc.php にリネームしてからテキストエディタで開き、以下を変更して保存します('port'の方は一行丸ごと追加してください)。:
  :
  :
$cfg['Servers'][$i]['host'] = '(接続情報の host の値)';
$cfg['Servers'][$i]['port'] = '(接続情報の port の値)';  # この行は追加
  :
  :


これで phpMyAdmin の設定も完了しました。最後に Bluemix 上の PHP ランタイムで mbstring や MySQL, PDO を有効にするための設定を追加します。 CakePHP や phpMyAdmin を保存したフォルダ(ドキュメントルートにするフォルダ)に .bp-config というフォルダを作ります:
2015062905


そしてこの .bp-config フォルダの中に options.json というテキストファイルを以下の内容で新規に作成して保存します:
{
  "PHP_EXTENSIONS": [ "bz2", "zlib", "curl", "mcrypt", "mbstring", "mysql", "pdo", "pdo_mysql" ]
}
2015062906


更に、ドキュメントルート直下に composer.json というファイルを以下の({} だけの)内容で作成します:
{}
2015062907


これで全ての準備が整いました。ではこのフォルダ(cakephp や phpMyAdmin, .bp-config のあるフォルダ)をカレントフォルダにして、Bluemix 上の PHP アプリケーションに cf ツールでプッシュします:
> cd c:\tmp\cake (目的のフォルダ)

> cf login -a https://api.ng.bluemix.net/ -u (Bluemix のログインID)

※データセンターが英国を使っている場合は https://api.eu-gb.bluemix.net を指定する

(パスワード入力を求められるので指定)

> cf push (Bluemix で作成時に指定したアプリ名)

cf push コマンドが成功すると Bluemix 上に CakePHP および phpMyAdmin の環境ができているはずです:

(CakePHP 環境)
2015062908

(phpMyAdmin 環境)
2015062909


念願の CakePHP on Bluemix 環境の作り方が分かりました!

謎だった Power 版 RHEL(RedHat Enterprise Linux) での MongoDB の動かし方が分かりました!

これまでは「CPU のエンディアンの違いにより MongoDB が動かなかった」と思っていたのですが、IBM のダウンロードサイトで Power 版 RHEL 向けビルド済み rpm パッケージの存在を確認しました。これを使います。


まず準備段階として Power 版 RHEL 環境を用意します。・・・といっても普通の人はそんな環境持ってないですよね(苦笑)。 2週間のお試し程度であれば、開発者向けサービスである IBM Power Development Cloud を利用して環境を構築することも可能です。 その場合の手順はこちらのブログエントリを参照ください:


Power 版 RHEL の準備ができたら早速 MongoDB を導入しましょう。といっても特別な作業ではなく、必要な rpm パッケージを IBM からダウンロードしてインストールするだけです。Intel 版 RHEL と異なるのはファイル名のアーキテクチャ部分が i686 とか x86_64 とかではなく、ppc64 になっていることくらいです。あと現在用意されている MongoDB はバージョン 2.4.9(RC0) のようです:
# cd /tmp
# yum install wget boost-devel
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/v8-3.14.5.10-2.el6.ppc64.rpm
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/libmongodb-2.4.9-1.el6.ppc64.rpm
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/mongodb-server-2.4.9-1.el6.ppc64.rpm
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/mongodb-2.4.9-1.el6.ppc64.rpm
# rpm -ivh v8-3.14.5.10-2.el6.ppc64.rpm
# rpm -ivh libmongodb-2.4.9-1.el6.ppc64.rpm
# rpm -ivh mongodb-server-2.4.9-1.el6.ppc64.rpm
# rpm -ivh mongodb-2.4.9-1.el6.ppc64.rpm

これで MongoDB のインストールは完了です。念のため、導入先を確認しておきましょう:
# which mongod
/usr/bin/mongod
# which mongo
/usr/bin/mongo

MongoDB の起動はコマンドラインから、以下の内容を実行します:
# mongod --dbpath /var/lib/mongodb

実行するとサーバーコンソールのようにメッセージがずらずらと・・・出てくればサービスの起動成功です。ちなみにサービスの終了は CTRL + C です。
2014121001


Mongo クライアントは何の違いも感じずに使えます:
2014121002


この Power 版 RHEL 向け MongoDB はいつから用意されてたんだろう? ともあれ、これで Power 版の RHEL でも MongoDB が動くことが確認できました。本当に Intel 版との違いがなくなりつつあることを実感します。


そして、これはつまり MongoDB に対応したフレームワーク(cakePHPとか)を Power 版 RHEL で動かすことができるようになったのかな?? とも思っているのですが、実際 cakePHP で使ってみると Intel 版では見たことのないエラーメッセージに遭遇したりして、まだもう少し待った方がいいのかな、とも思ってたりします。要はちゃんと動かして調べましょう、ということで。


最後に、自分が業務で開発に携わっている公開済みサービスがこの Power 版 RHEL 環境でもある程度動いたので記念アップ!
2014121003

 

cakePHP には Validation という便利な機能が標準で搭載されています。


これは例えば、
 users テーブルの name フィールドの値は2文字以上30文字以内
というルールをアプリケーションのレベルで付与する、というものです。「アプリケーションのレベルで」付与するので、例えば入力の際のエラーメッセージも併せて定義することができます。

具体的にはこんな感じでモデルにルールを記述することになります。上記例では users テーブルを対象にしているので、モデルは Model/User.php ファイルとなり、その中に以下の様な Validation ルールを加えます:
<?php
App:uses('AppModel', 'Model' );
class User extends AppModel{
  :
  :
  
  public $validate = array(
    'name' => array(
      'between' => array(
        'rule' => array('between',2,30),
        'message' => '名前は2文字以上30文字以内で入力してください。'
      )
    )
  );
}
?%gt;

これで User モデルに Validation ルールが適用され、この条件に合わないデータ配列で save() メソッドを実行しても保存できなくなります。その際に定義されているエラーメッセージを取得することもできるので、それを画面に表示して再入力を促すこともできます。


これはこれで便利なのですが、アプリケーションを運用しているとこのルールを変えたくなることがあります。例えば name フィールドの値を5文字以上50文字以内に変更したい、というケースを考えます。

モデルのルールとしては上記の $validation 変数の該当部分を array('between',2,30) から array('between',5,50) に変え、エラーメッセージも新しいものに変更するだけで済みます。しかしこれだけでは問題が起こることもあります。


例えば元の Validation ルール運用時にユーザーがデータを作り、その後新しい Validation ルールに変えたとします。そしてユーザーや管理者が、現在の users データのあるレコードの、name フィールドではない別のフィールドの値を変えたいと思っている、という状況を考えてみてください:

(例) 管理者が id = 10 のユーザーの admin_flag 列の値を 0 から 1 に変えたい、と思っている。。。

idnameadmin_flag
10ABC0


ロジックそのものは単純で、こんな感じになります:
    :
//. id = 10 の User を検索 $user = $this->User->find('first', array('conditions'=>array('id'=>'10'));
//. admin_flag の値を 1 に変更 $user['User']['admin_flag'] = 1;
//. 更新して保存 $this->User->save($user['User']);
:

しかしこのロジックには問題があり、実行しても admin_flag の値は更新されません。 その理由は今は新しい Validation ルールで運用されているため、name 値は5文字以上になっている必要がある、というルールが適用されるためです。現在の "ABC" という name 値は以前のルールでは問題なく作れていても今のルールでは認められません。そのため save に失敗してしまいます。

その一方で、これは管理・運用上の処置であるため、ユーザーの意志とは関係なく管理者が行う必要のある作業であるケースもありえます。name 値が現行の Validation ルールにはそぐわないものであったとしても、この変更を保存できるようにしたいのですが、何か方法はないでしょうか?


で、その答がこのブログエントリのテーマでもある「Validation ルールを一時的に無効にする」です。実はすごく簡単で、最後の save メソッド実行時に第二パラメータを指定します:
    :
//. id = 10 の User を検索 $user = $this->User->find('first', array('conditions'=>array('id'=>'10'));
//. admin_flag の値を 1 に変更 $user['User']['admin_flag'] = 1;
//. 更新して保存 $this->User->save($user['User'], false);
:

これで Validation ルールを一時的に無効にした上で save メソッドを実行することができます。


 

このページのトップヘ