PHPからMongoDBのAutoIncrementを使用する

MongoDBでfindAndModifyを使用したAuto Incrementの実装方法が公式サイトに載っています。

Create an Auto-Incrementing Sequence Field

これをPHPで実装する場合、以下のようになります。

Auto Increment用collectionの作成

あらかじめAuto Increment用のcollection(counters)を用意します。

$ mongo
> db.counters.insert({_id: 'userid', seq: 1});

PHPでの実装

commandを使用し取得したSequenceでINSERTを行います。

<?php

$mongo = new Mongo('localhost:27017');
$db = $mongo->selectDB('hoge');
$rs = $db->command(array(
    'findandmodify' => 'counters',
    'query' => array('_id' => 'userid'),
    'update' => array('$inc' => array('seq' => 1))
));
$seq_val = $rs['value']['seq'];

$users = $db->selectCollection('users');
$users->insert(array(
    '_id' => $seq_val,
    'name' => 'Sarah C.'
));

試した環境

AppFogで始めるFuelPHP

がっつり使ったわけではないので、とりあえず環境構築まで。
タイトルが変だけど、まーいいか。

AppFogのSIGN UP

AppFogのアカウントが無いと始まらないので、

http://www.appfog.com/

にアクセスし、右上『SIGN UP』からAppFogのアカウントを作成します。

アプリケーションの作成

次にアプリケーション(PHP+MySQL)の作成です。
以下のサイトを参考にさせて頂きました。

appfog に PHP + MySQL 環境を作る

上記サイトを参考に、PHP+MySQLのアプリケーションを作成します。

AppFogコマンドラインツールのインストール

以下のページを参考にAppFog用のコマンドラインツールをインストールします。

http://docs.appfog.com/getting-started/af-cli

$ gem install af

FuelPHPの用意

ローカルにFuelPHPを用意します。

$ wget https://github.com/downloads/fuel/fuel/fuelphp-1.4.zip
$ unzip fuelphp-1.4.zip
$ cd fuelphp-1.4
$ vi .htaccess
$ vi fuel/app/config/config.php
$ php oil refine install
$ vi fuel/app/config/db.php
$ vi fuel/app/config/development/db.php

.htaccess

RewriteEngine On
RewriteBase /public
RewriteRule (.*) /public/$1 [L]

config.php

とりあえず最低限の設定

<?php
return array(
    'base_url' => '/',
    'default_timezone' => 'Asia/Tokyo'
);

※2012/11/30追記
『base_url』を設定しないとURLにpublicが含まれるようです。
参考)
PHPFog の FuelPHP アプリを AppFog に移行してみる (2) - A Day in Serenity @ kenjis

config/db.php

一応、MongoDB/Redisの設定も。

<?php
$j = json_decode(getenv('VCAP_SERVICES'));
$mongo = $j->{'mongodb-1.8'}[0]->{'credentials'};
$redis = $j->{'redis-2.2'}[0]->{'credentials'};

return array(
    'mongo' => array(
        'default' => array(
            'hostname' => $mongo->{'host'},
            'port'     => $mongo->{'port'},
            'username' => $mongo->{'username'},
            'password' => $mongo->{'password'},
            'database' => $mongo->{'db'}
        )
    ),
    'redis' => array(
        'default' => array(
            'hostname' => $redis->{'host'},
            'port'     => $redis->{'port'},
            'password' => $redis->{'password'}
        )
    )
);

development/db.php

<?php
$j = json_decode(getenv('VCAP_SERVICES'));
$mysql = $j->{'mysql-5.1'}[0]->{'credentials'};

return array(
    'default' => array(
        'connect' => array(
            'dsn' => 'mysql:host='.$mysql->{'host'}.';dbname='.$mysql->{'name'},
            'username' => $mysql->{'username'},
            'password' => $mysql->{'password'},
        )
    )
);

ここまでで下準備は完了です。

アップロード

afコマンドを使用しファイルをアップロードします。
fuelphpを伸張したディレクトリへ移動し以下を実行。

$ af login
$ af update {name}

例)
$ af update myapp

※{name}に入るのは『アプリケーションの作成』時に指定したサブドメイン

確認

実際にURLにアクセスし、FuelPHPのWelcomeが表示されている事が確認出来ればOK!

その他

FuelPHPのRedisクラスを使用しようとしたら、Redisクラスが競合しているらしく、そのままでは使用不可。とりあえず以下のように呼び出し。

<?php
$redis = \Fuel\Core\Redis::forge('default');

FuelPHPのAgentクラスが機能しない件

FuelPHPのAgentクラスは、デフォルト設定の場合、

http://browsers.garykeith.com/stream.asp?Lite_PHP_BrowsCapINI

からUA一覧を取得し使用していますが、このサイトが閉鎖したようで、
1.3以前のバージョンでAgentクラスをデフォルト設定で使用している場合、
うまく機能していない可能性があります。
(※当然の事ながらcacheに残っていれば動作します)
(※Ver1.4ではデフォルトで『http://tempdownloads.browserscap.com/stream.asp?Lite_PHP_BrowsCapINI』を参照するようになりました)

参考)
https://groups.google.com/forum/#!topic/browscap/Yy3Djd1Mqvk

以下、一時的な対応方法です。

$ cd fuel/app/config
$ wget -O php_browscap.ini http://tempdownloads.browserscap.com/stream.php?BrowsCapINI
$ vi agent.php

config/agent.php

<?php
return array(
    'browscap' => array(
        'enable' => true,
        'method' => 'local',
        'file'   => APPPATH.'config/php_browscap.ini'
    )
);

FuelPHPのインストールから開発までの流れをおさらい

なんだかんだで毎回調べているような気がするので、
FuelPHPのインストールから諸々の下準備の流れをメモっておきます。

以下を想定しています。

  • DocumentRoot : /var/www/html
  • ProjectRoot : /var/www/sample
  • FuelPHP Version : 1.3

1. FuelPHPのインストール

まずはFuelPHPのインストールから。

ダウンロードして使用する場合

伸張したディレクトリがそのままプロジェクトのディレクトリに。

$ cd /var/www
$ wget https://github.com/downloads/fuel/fuel/fuelphp-1.3.zip
$ unzip fuelphp-1.3.zip -d sample
$ cd sample
    (ver1.6以上の場合、sampleディレクトリへ移動後『php composer.phar update』を実行する必要があります)
$ php oil refine install

※ FuelPHP1.4の場合、『3. config設定』を先に設定しないと、エラーになります。
※ zip版のpublic配下の.htaccessパーミッションが『670』なのは、自分の環境の問題?

コマンドラインでインストールを行う場合

oilコマンドでプロジェクトを作成。

$ curl get.fuelphp.com/oil | sh
$ which oil
$ cd /var/www
$ oil create sample

2. ドキュメントルート設定

publicディレクトリをDocumentRootとして使用する為、移動。

$ mv /var/www/sample/public /var/www/html
$ vi /var/www/html/index.php

publicディレクトリをプロジェクトディレクトリから移動した為、以下のパスを修正。

<?php
...
define('APPPATH', realpath(__DIR__.'/../sample/fuel/app/').DIRECTORY_SEPARATOR);
define('PKGPATH', realpath(__DIR__.'/../sample/fuel/packages/').DIRECTORY_SEPARATOR);
define('COREPATH', realpath(__DIR__.'/../sample/fuel/core/').DIRECTORY_SEPARATOR);

3. config設定

$ vi /var/www/sample/fuel/app/config/config.php

修正箇所のみ抜粋

<?php
return array(
...
    'index_file' => false,
    'language' => 'ja',
    'locale' => 'ja_JP.UTF-8',
    'default_timezone' => 'Asia/Tokyo',
...
    'always_load' => array(
        'packages' => array(
            'orm',
        ),
...
);

セッションがデフォルトでcookieになっている為、fileに変更。

$ vi /var/www/sample/fuel/app/config/session.php

※ファイルは新規作成

<?php
return array(
    'driver' => 'file'
);
※ 2013/01/29追記

localeには”ja_JP.UTF-8"を指定しないと酷い目に合う場合があるようです。

※ 2013/03/05追記

Ver1.5では『security.output_filter』がデフォルトで空になっているようです。

Ver1.5 - Ver1.5.2を使用している場合、app/config/config.phpに以下を追加した方がいいかもしれません。

<?php
...
    'security' => array(
        'uri_filter' => array('htmlentities'),
        'output_filter' => array('Security::htmlentities'),
        'whitelisted_classes' => array(
            'Fuel\\Core\\Response',
            'Fuel\\Core\\View',
            'Fuel\\Core\\ViewModel',
            'Closure'
        )
...

参考) FuelPHP 1.5.3 hotfix がリリースされました - A Day in Serenity @ kenjis

4. DB設定

DB接続情報を修正。
(development/db.php , production/db.php をそれぞれ修正)

$ vi /var/www/sample/fuel/app/config/development/db.php

適宜変更

<?php

return array(
    'default' => array(
        'connection' => array(
            'dsn' => 'mysql:host=localhost;dbname=fuel_dev',
            'username'   => 'fuel_app',
            'password'   => 'super_secret_password',
        ),
    ),
);

5. モデル作成

必要なモデルの作成マイグレーションの実行。

$ cd /var/www/sample
$ php oil generate model hoge name:varchar[255] sex:int del_flg:bool
$ php oil refine migrate

※ php oil generate model {テーブル名} {カラム1名}:{カラム1型} {カラム2名}:{カラム2型}...

※テーブルの管理画面が必要であれば『php oil generate model』を『php oil generate admin』に変更しSimpleAuthを設定

6. コントローラ作成

$ cd /var/www/sample
$ php oil generate controller example index add

※ php oil generate controller {コントローラ名} {アクション1} {アクション2}...

※oil generate controllerで生成されるのはController_Template

7. TOPページの設定

$ cd /var/www/sample/fuel/app/config
$ vi routes.php

TOPページとなるコントローラを設定。

<?php
return array(
    '_root_' => 'top/index',
    ...
);

8. いざ開発!

こんな感じだと思うんですが、間違い/漏れ等あればご指摘下さい。

FuelPHP入門

FuelPHP入門

ファイルの有無でメンテページへ切り替える為のmod_rewrite設定

あらかじめこの設定をしておけば、サイトのメンテナンス時、
毎回メンテページへのリダイレクトを設定する手間が省けます。


そこの『え?1回リダイレクトの設定すれば、後は毎回コメントを解除するだけなんだけど』とか言ってる人!
ごもっとも。

まー、色々方法がある中から、自分の好きなものを選べる方がいいと思うので。

設定

以下が設定例になります。

// .htaccess
ErrorDocument 503 /mainte.html
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond /var/www/html/mainte_trigger.txt -f
    RewriteCond %{REQUEST_URI} !^/mainte.html [NC]
    RewriteRule .* - [R=503,L]
</IfModule>

ドキュメントルートは『/var/www/html』になっていて、メンテページを『mainte.html』として配置しています。

上記の場合

  • 『/var/www/html/mainte_trigger.txt』が存在する場合

にHTTPステータス503でメンテページを表示します。

切り替え方法

後はSCPなりコマンドラインなりで『/var/www/html/mainte_trigger.txt』を作成すればメンテページ表示、削除すればメンテ解除になります。

補足

mainte_trigger.txtのサイズまで見る場合、『-f』オプションではなく『-s』オプションを使用します。

  • -f : 『ファイルが存在する場合にtrue』
  • -s : 『ファイルが存在し、サイズが0でなければtrue』

シェルスクリプトで重複起動(二重起動)防止

シェルスクリプトの二重起動防止は、

  • ロックファイルを使用する
  • pgrep、pkill、pidofコマンドを使用する

等、色々方法があると思いますが、
以下は、単純なファイル/ディレクトリ確認で重複起動チェックする方法です。

#!/bin/sh

PIDFILE=$(basename $0).pid

if [ -s ${PIDFILE} ] ; then
    if [ -d /proc/$(cat ${PIDFILE}) ] ; then
        # 多重起動
        exit
    fi
fi
echo $$ > ${PIDFILE}

# 処理

と、まー今さらなネタでした。