Home > PHP > CakePHP

CakePHP Archive

5分でわかる最近のPHP – 2011夏

この記事の所要時間: 414

ここ最近のPHP界隈では、興味深いニュースが続いています。最近PHPを追っかけていない人へ少しづつご紹介。

PHP

近頃、PHP界隈でホットなニュースを5つ、つまみぐいして見てみましょう。

1. PHP5.4.0-alphaリリース!

PHPの次期バージョン、5.4.0-alphaがリリースされました。

まだ alpha1 ですが、すでに Traits や Array dereferencing support など様々な機能追加が行われています。

特に Traits は面白い機能で、いずれはこれを利用したフレームワークの登場が考えられます。ぜひ使ってみたい機能ですね。

今後、正式リリースに向けてさらなる新機能が追加されていくようなので、目が離せません。

2. Short syntax for arrays を PHP5.4 で採用!

PHPでおなじみの連想配列を、array()ではなく、JavaScriptのように [] で定義できるシンタックスが採用されました。

$array = [1, 2, 3];
$array = ['foo' => 1, 'bar' => 2];

これは、そもそも2008年に @rsky さんが提案されていたもので、議論に上がる->リジェクトされる or 放置されるを繰り返して、3年越しでようやく実現となりました。@rsky さんの行動がPHPを動かしたわけです。おめでとうございます!

もう array() と書くのは過去の遺産になっていくでしょうね。(次は配列がオブジェクトになって、あの関数群がメソッドにまとまってくれたら。)

3. Built-in web server を PHP5.4 で採用!

PHP5.4 から CLI 版に簡易 Web サーバーが組み込まれるようになりました。

この機能はmoriyoshitさんが作られたものです。すばらしい!

PHPは Apache に組み込んで(mod_php)で利用されることが多いので、そもそもこういった機能は不要では無いか、という議論もあったようなのですが、httpd.conf 等の設定を変更することなく、コマンドラインからすぐに動作確認ができるサーバを起動できるのは非常に便利です。

実は昔、CakePHPにこういった開発サーバを組み込もうと思って、さわりだけ作ったりしたのですが、それが PHP でサポートされるようになりました。

普段の開発もそうですが、新たなライブラリやフレームワークを試す時にも便利ですね。

4. CakePHP2.0 Betaリリース!

CakePHPの次期バージョン、2.0のBeta版がリリースされました。

こちらはPHP5.2.6以降が対象バージョンとなっています。5.3以降ではなく、あえて5.2を範囲に入れているあたりが、1系でPHP4 & PHP5両対応を行っていたcakeらしいです。(個人的には5.3以降を対象にして、namespaceに対応して欲しかった感はありますが。)

alpha版を少し触ってみましたが、フレームワークのクラス構造が一新しており、ソースも前より洗練されている印象です。1系で懸念点であったパフォーマンスについてもbeta版の時点で改善されているようです。

今後の正式リリースに向けて期待が膨らみますね。

5. Symfony 2.0.0 リリース!

Symfonyの次期バージョン、Symfony2がついに正式リリースされました。

個人的にはPHP5.3フレームワークでは本命だと思っており、これを機に5.3の本格利用がようやく進むのではないでしょうか。日本のSymfonyコミュニティも盛り上がってるので、今後Symfonyがぐいぐい来そうですね。

PHPは止まらない

PHPは、独自の歩みながらどんどん前に進んでいっています。昔の知識のままで語らず、進化を続ける今のPHPに触れてみて下さい。

FizzBuzzではじめるテスト – 第1回関西PHP勉強会

この記事の所要時間: 338

7/22に大阪市内で第1回関西PHP勉強会を開催しました。

kphpug

4月にPHPカンファレンス関西を開催して以来、3ヶ月ぶりにPHPの勉強会を開催しました。

参加頂いたみなさんありがとうございました。また発表を快く引き受けていただいた皆さん、本当にありがとうございました。

イベント名に「第1回」と付けたのは、今後も継続して開催していきたいという気持ちの表れです。PHPを軸に色々なテーマで開催していきたいと思うので今後もよろしくお願いします。

スイーツタイム

勉強会をやるときは、休憩時間にみんなで食べるおやつを用意するのですが、今回は @msng さんに色とりどりのマカロンを用意してもらいました。見た目も鮮やかですし、適度な甘さで好評でしたね。(たしかに美味しかったです!)

昨今「スイーツタイム」が話題になっていますが、会場で飲食が可能なら実施することに賛成です。

単純に勉強会で発表を聞くだけでも疲れますし、特に平日夜の勉強会だとお腹が空く時間帯でもあります。そんな時に甘いモノをみんなで食べると自然と笑顔になります。

運営側としてもおやつを配るという行為を介して、参加している方と軽く言葉を交わしたり交流ができます。参加している方同士も「おいしいですねー」と隣の方と一言二言だけでも話ができるきっかけになります。

この効果は意外に侮れません。何度かこのおやつタイムをやっていますが、おやつタイム後のセッションは明らかに空気が変わります。それまで見知らぬ者同士で張り詰めていたような空気が和らぎ、みんなで一緒に聞こう空気に変わります。(もちろん、その固い空気をほぐすのが司会者の役割でもあるのですが、未熟なだけにおやつの力は絶大です)

このおやつタイムは、まっちゃだいふくさんが勉強会でいつも美味しいスイーツを出されているという話を聞いてから始めました。まっちゃだいふくメソッドとも呼ばれるこの手法はかなり有効なので、まだご存知無い方は、まっちゃだいふんさんの発表を見てみてください。

まっちゃだいふくメソッド / まっちゃだいふく

FizzBuzzではじめるテスト

今回はテーマを「テスト」にしたのですが、まずはテストの導入として、FizzBuzzを題材にテストを行う内容で発表しました。

テストの基本の考え方から、Selenium IDEとSimpleTest+CakePHPで、FizzBuzzをテストする内容になっています。

サンプルソースと資料は以下になりますので、これからテストをやってみようかなーという方は参考して下さい。

サンプルソース

テストを動かす時の補足です。

P.13 / Selenium IDE デモ

サンプルソースの app/tests/selenium/account.html がデモ用ファイルなので、 Selenium IDE で開いて実行して下さい。

FizzBuzz の実行

基本は CakePHP の設置方法と同じです。一例としては、サンプルソースをダウンロード+展開して、app/webroot を document_root に設定して下さい。

P.27 / Selenium IDE で FizzBuzz をテスト

サンプルソースの app/tests/selenium/fizzbuzz.html がテストケースなので、 Selenium IDE で開いて実行して下さい。

P.29 / SimpleTest(CakePHP) で FizzBuzz をテスト

http://localhost/test.php にアクセスして、model/Fizzbuzz のテストケースを実行して下さい。テストケースは、app/tests/cases/models/fizzbuzz.test.php 、テスト対象の Fizzbuzz モデルは、app/models/fizzbuzz.php です。

参加された方からのフィードバック

コードカバレッジ測定ツールPHP_CodeCoverageをCakePHPで使ってみた

この記事の所要時間: 64

PHP_CodeCoverageで、CakePHPのユニットテストのコードカバレッジを表示してみました。

php_codecoverage

CakePHP標準のテストランナー(test.php)でも単一のテストケースについてはコードカバレッジが表示できるのですが、All tests の時はコードカバレッジが表示されません(All testsでも表示されることもあるようです。hiromi さん、ありがとうございます)。

そこでPHP_CodeCoverageを使って、All testsのコードカバレッジを表示してみました。

1. PHP_CodeCoverage インストール

PHP_CodeCoverageは、PHPUnitでおなじみのSebastian Bergmannが開発した、コードカバレッジやCRAPを計測、表示するツールです。

PEARパッケージで提供されているので、pear コマンドでインストールします。

2011/06/15現在の最新版1.0.4では、PHP5.2.7以上とxDebugが必要となります。

sudo pear channel-discover pear.phpunit.de
sudo pear channel-discover components.ez.no

sudo pear install phpunit/PHP_CodeCoverage

ソースコードはgithubでも公開されており、README.markdownで詳しいインストール方法なども記載されているので、気になる人は見てみて下さい。

sebastianbergmann/php-code-coverage – GitHub

2. test.php のコードカバレッジを計測する

test.phpで実行する All tests のコードカバレッジを計測します。

test.php を直接改修して PHP_CodeCoverage を実行しても良いのですが、test.php を改修しない方法として、auto_prepend_file / auto_append_file を使う方法で実装します。

auto_prepend_file / auto_append_file を使うと test.php の実行前後に、自動実行するPHPスクリプトを指定することができます。そこで、auto_prepend_file ではコードカバレッジ計測を開始するPHPスクリプトファイルを、auto_append_file ではコードカバレッジ計測終了と結果を書きだすPHPスクリプトを指定します。

2-1. auto_prepend_file / auto_append_file を設定

httpd.confでauto_prepend_file / auto_append_file を設定します。

<VirtualHost *:80>
  ServerName example.com
  DocumentRooot /path/to/cakephp/app/webroot

  <Location /test.php>
    php_value auto_prepend_file /path/to/prepend.php
    php_value auto_append_file /path/to/append.php
  </Location>
</VirtualHost>

2-2. prepend.php

auto_prepend_file で指定したコードカバレッジ計測を開始するPHPスクリプトを実装します。

[/path/to/prepend.php]

ポイントは 7 行目から 14 行目で、PHP_CodeCoverage_Filterを使って、フレームワークやプラグイン、テストケース、 prepend.php、append.php を対象外にしています。

このあたりが考慮されているのがさすがですね。

2-3. append.php

auto_append_fileで指定したコードカバレッジ計測を終了して、結果ファイルを出力するPHPスクリプトを実装します。

[/path/to/append.php]

2-4. 結果出力ディレクトリ作成

append.phpでは app/webroot/coverage ディレクトリに結果ファイルを出力するので、あらかじめディレクトリを作成して apache ユーザに書き込み権限を付与しておきます。

$ mkdir app/webroot/coverage
$ chmod a+w app/webroot/coverage

3. test.php で All tests を実行

あとは普通にtest.phpで All tests を実行します。

テストが完了して /coverage/ にアクセスすると、下記のようなコードカバレッジ計測のレポートが表示されます。

php_codecoverage

内容は CakePHP 標準のコードカバレッジレポートよりも詳細で、全体、ディレクトリ単位、ファイル単位で、行数・メソッド数・クラス数でのコードカバレッジを確認することができます。

左のディレクトリ、ファイルはリンクになっており、クリックするとディクレトリ内のファイルを見ることができます。またファイルをクリックするとPHPソースが表示され、背景色によってその行が実行されたか否かが判別できるようになっています。

4. メモリーエラーが出たら

コードカバレッジ計測では多くのメモリを消費するのでテスト対象のソースファイルが多いと「Fatal error: Allowed memory size of 0 bytes exhausted」といったメモリ不足によるPHPエラーが出る場合があります。

エラーが発生した時は memory_limit にてPHPが確保できるメモリを増やします。

なお古いバージョンの test.php では memory_limit 設定がハードコーディングされている場合があるので、その際は test.php を直接書き換えて下さい。

[app/webroot/test.php]

-ini_set('memory_limit','128M');
+ini_set('memory_limit','512M');

手軽にコードカバレッジを表示

コードカバレッジを計測すること自体はxdebugを使うと簡単なのですが、それを集計して、見やすい形式にまとめてくれるという点で、PHP_CodeCoverage はかなり便利なツールです。

auto_prepend_file / auto_append_file を使う方法を応用すれば Selenium のテストでもコードカバレッジを計測することができそうです。これはぜひ試したいですね。

ここではCakePHPを対象としましたが、もちろん他のフレームワークやアプリケーションでも利用できるので、一度試してみてください。

CakePHP Modelとの付き合い方(CakePHP Advent Calendar 2010 3日目)

この記事の所要時間: 612

CakePHPのModelに悩む人が多いようなので、自分なりの付き合い方(考え方)をご紹介します。

CakePHP Advent Calendar 2010の3日目です。

前日の k1LoW さんのエントリ、参考になりますね。GETのフォームをdata[]でやるとURLがすんごいことになるので、ウチでは別途対応できるライブラリを作ったりしてます。

さて、3日目の今日は書きたいネタは幾つかあったのですが、「君の当たり前に僕らは感嘆させられるんだ」の精神に従って、自分なりのModelの使い方、考え方を書いてみます。

1. 適正なインターフェイスを用意して処理をカプセル化

まず基本的な考え方。

Model(に限らずですが)では、処理単位でインターフェイス(メソッド)を用意して、実装はカプセル化しておきます。

こうすることによって、Modelを利用する側(Controllerや他のModel等)はそのインターフェイス越しに処理を呼び出せば、求める処理が実行され、その結果を得ることできます。

呼び出し側では、求める処理さえが実行されれば良いわけで、その処理自体がどのような実装になっているのかは知る必要がありません。極端な話、求める要件さえ満たせば、処理はどのように行われていても良いわけです。

この処理のカプセル化というのはオブジェクト指向では一般的な考え方ですが、あらためてしっかりとイメージしておくとフレームワークと上手く付き合う方法が見えてくるのかなと思います。

もちろん、これはベースの考え方であって、実際は当然実装も気にしますし、それに応じた呼び出し方も考えます。ただ根底ではこの考え方を意識しています。

2. SQLを直接書いて良いか?

CakePHPが用意しているインターフェイスで簡単に全てのクエリが表現できればそれに超したことは無いのですが、実際のところそうもいかないこともあります。

発行したいSQLはイメージできているのに、それをどうCake風に書けば良いかを悩む、という場面に遭遇した人も多いのではないでしょうか。

もちろんフレームワーク流の書き方を習得する方法も1つなのですが、場合によっては、その処理をメソッド内に閉じ込めておけば、SQLを書いてしまっても良いと思います。

イメージとしては以下。このメソッドを呼び出す側からはregisterという処理を実行してくれれば良いわけで、中でsaveメソッドを呼ぶのか、SQL直書きなのかは関係ありません。

  public function register() {
     $this->query('複雑なSQL書く');
  }

もちろん、これも程度の問題で、基本はModelのメソッドをそのまま使います。ただ複雑なSQL、パフォーマンスが要求されるような箇所では、SQL直書きも許容するということです。

3. belongsTo以外のアソシエーションは使わない

単純なbelongsTo以外のアソシエーションは原則使いません。

複数テーブルのJOINが必要な場合は、DBにViewTable(CREATE VIEW)を作成して、それに対応するModelを作ります。

例えばでは、usersテーブルとuser_classesテーブルをJOINしたViewTableを作ります。

CREATE VIEW v_users AS
SELECT
  u.*,
  uc.name AS user_class_name
FROM
  users AS u
JOIN
  user_classes AS uc ON (u.user_class_id=uc.id)
;

そして、v_usersを利用するModelを作ります。

class VUser extends AppModel {
  public $useTable = 'v_users';
}

VUserモデルでfind()等を実行する場合は、あくまでv_usersという一つのViewTableに対する操作となるので、とても単純です。

さらにViewTableは自分でSQLを書いて作るので、意図したとおりのSQLが発行できます。もしクエリをチューニングするときはSQLレベルで調整できます。

複雑なアソシエーションを覚える、制御する必要が無いので、個人的にはこの方法が気にいっています。

4. アクション毎にModelを作る

Modelには多くの責務があるので、アプリケーションが大きくなってくると1つのModelに処理が増えてきて肥大化する傾向があります。

特にバリデーションなどは画面によって内容が異なる場合もあるので、1つのModelにあらゆる場面での処理を書いていくと複雑になり、メンテナンス性が落ちます。

そこで、処理を分割する、1つのModelの責任を小さくするためにControllerのアクション毎にModelを作成しています。

例えば、UserController#index()ならActionUserIndexというModelを、UserController#edit()ならActionUserEditというModelを作成します。

画面毎の処理はそのModelに書き、共通で利用するような処理はUserモデルに書くというように使い分けています。

もちろん中にはUserモデルをfindするだけで済むような画面もあるので、そういう場合は作らないときもありますが、基本的には作成するようにしています。

これにより画面毎の処理を局所化できるので、特にチームでの開発では効率が上がりました。

5. 例外を積極的に使う

わりと敬遠されがちな例外ですが、積極的に使ってます。例外を使えば、処理の考え方がシンプルになります。

例えば、Modelで何かエラーがあったら例外を投げるようにしています。投げる例外は場面に応じたものを選択しますが、とりあえずエラーなら例外を投げるというルールにします。

また、呼び出し側では、try句の中には正常系だけ書いて、異常系はcatchに書きます。try句の中には正常系処理しか無いので、本来実行すべき処理を追いやすくなります。

もちろん例外を使わず戻り値の規約を作れば同じようなことはできますが、try/catch句のようにPHPの構文で実装の意図を明確にすることができます。

try {
  正常系処理
} catch (NotFoundException $e) {
  異常系処理1
} catch (AppException $e) {
  異常系処理2
}

バランスも大事

フレームワークを使う上で、どこまでフレームワークの仕様に合わせるか、どこからは独自の方法で実装するかというのは悩むポイントですね。

このエントリで紹介した内容はCakePHPの基本的な使い方からは少し外れるものもあります。

ただ、フレームワークを使う目的は、フレームワークを使うことではなく、フレームワークを使って何かを作ることだと思っているので、バランスを取りながらうまく付き合っていきたいですね。

CakePHP Advent Calendar 2010 4日目は、remoreさんです。どんなエントリになるか楽しみですね!

PHP unserialize()が__destruct()を実行する?

この記事の所要時間: 328

CakePHPのセキュリティホール(まだの方はご対応を!)から、unserialize()が話題になっています。

このセキュリティホールは、外部から送信された値をチェックせずにunserialize()したことが引き金になっており、安全でない値をunserialize()することの危険性が指摘されています。

下記エントリでは、コードを交えてunserialize()から__destruct()が実行される過程が解説されています。

PHP5 __destruct() and unserialize() function – TokuLog 改メ tokuhirom’s blog

念のための補足なのですが、unserialize()から__destruct()が呼ばれるわけではありません。

下記コードは、PHP5.3.3で実行しています。

unserialize()から実行される関数

unserialize()から実行される関数(メソッド)は以下です。

__autoload、spl_autoload*などのオートローダー

デシリアライズするインスタンスのクラス定義を探す時に実行される可能性があります。

unserialize_callback_funcで設定した関数

上記オートローダー実行してもデシリアライズするインスタンスのクラス定義が存在しない場合に実行されます。ini_set()等で設定していなければ実行されません。

__wakeup

デシリアライズしたインスタンスに__wakeupメソッドが定義されていれば実行されます。

unserialize()から間接的に実行される関数

デシリアライズしたインスタンスの操作によって、結果実行される可能性があるのは以下です。

__destruct()

デシリアライズしたインスタンスの参照が0になったタイミングで実行されます。通常必ず実行されます。

__toString() / __set() / __get() / __call() / __invoke()などのマジックメソッド

デシリアライズしたインスタンスへの操作によって実行される可能性があります。

この中で実行されそうなのは__toString()です。unserialize()した値が文字列だと想定して以下のようなコードを書いていると__toString()が実行されます。

func start
Foo::__toString
func end

unserialize()で__destruct()が実行される?

上記でも触れたように__destruct()は、unserialize()で呼ばれるわけではなく、デシリアライズしたインスタンスの参照が0になるタイミングで実行されます。

これは通常のクラスインスタンスと同じ挙動です。

下記コードを実行してみるとその挙動が確認できます。

実行結果

% php unserialize.php
func start
func end
Foo::__destruct <--- "func end"の後

ただ以下のようにunserialize()の戻り値を変数に格納しない場合は、デシリアライズしたインスタンスへの参照がありませんので、即時に__destruct()が実行されます。

func start
Foo::__destruct   // unserialize()して、即__destruct()が呼ばれる
func end

[おまけ] protected/privateな変数もデシリアライズ可能

ちなみにunserialize()では、protected/privateなインスタンス変数もデシリアライズ可能です。インスタンス変数をprotected/privateにしたところで、unserialize()で汚染される可能性があることには変わりありません。

object(Foo)#2 (3) {
  ["var1"]=>
  string(6) "public"
  ["var2":protected]=>
  string(9) "protected"
  ["var3":"Foo":private]=>
  string(7) "private"
}

でも結果としては実行される

unserialize()が__destruct()を直接実行するわけではないですが、デシリアライズしたインスタンスはどこかで破棄されるので、結果として__destruct()が実行されることには変わりありません。

ただやみくもに「unserialize()が__destruct()を実行する」と考えると問題を見誤る可能性があるのでご注意を。

参考リンク

CakePHPのSecurityComponentに深刻なセキュリティホールが見つかりました

この記事の所要時間: 29

すでにご存知の方も多いと思うのですが、CakePHPに深刻なセキュリティホールが見つかりました。

SecurityComponentの実装に問題があり、結果、外部から任意のコードを実行させることができるという深刻な内容です。

セキュリティホールの概要や攻撃手順については以下のエントリが詳しいですので、ご一読を。
CakePHP の PHP コード実行の脆弱性を使って CakePHP を焦がす

なお、今回の問題はSecurityComponentを利用していない場合は発生しません。

もしSecurityComponentを利用している場合は、以下のいずれかの方法で早急に対策してください。

1. CakePHP1.2.9 or 1.3.6にアップグレードする。

この脆弱性を受けて修正バージョンが出ています。

CakePHP 1.3.6 and 1.2.9 released | The Bakery, Everything CakePHP

2. SecurityComponentを自分で修正する

バージョン変更が容易で無い場合は、SecurityComponent を修正します。

以下に修正差分があるので、このコードをSecurityComponentに適用してください。

https://github.com/cakephp/cakephp/commit/e431e86

3. SecurityComponentの利用をやめる

SecurityComponentを CSRF 対策で利用している人も多いと思いますが、現在のSecurityComponent は必要以上に複雑な実装となっていて内容が掴みづらいという印象です。

いっそのこと自分に必要なシンプルなものを自作してしまうのもひとつの方法です。(私も社内で開発したものを使っています。)

まずは確認を

CakePHPを使っている方は、まずはSecurityComponentを利用しているか確認を。

簡易的ですが、SecurityComponent を使っているかどうかは以下のコマンドでも探せます。

% find app/ -name "*.php" | xargs grep "'Security'"
% find plugin/ -name "*.php" | xargs grep "'Security'"

まだ実際のサイトでの攻撃例は聞かないですが、今後発生する可能性があります。お気をつけを。

PHPで認証して、mod_xsendfileでファイルを出力する

この記事の所要時間: 545

ApacheでX-Sendfileが利用できるmod_xsendfileをPHPと連携して使ってみました。

PHPで認証してから、許可したユーザのみにファイルを出力する、という処理を実装する場合、ファイルはdocument_root外に配置しておいて、readfile()やfpassthru()でファイルを出力するという手法を良く使います。

この方法でも問題無い場合が多いのですが、容量の大きいファイルを出力する際は思ったようなスピードが出ない時があります。

そのような時はmod_xsendfileを使って、ファイル出力の部分をApacheに任せてしまう方法が有効です。

ここでは2010/11/12時点の最新版であるmod_xsendfile 0.12を対象としています。またインストール環境はRHEL、CentOSを想定しています。

mod_xsendfileのインストール

mod_xsendfileはApache2/2.2で動作するモジュールです。

インストールにあたって、apxsコマンドが必要となるので、もしインストールしていない場合はyum等でインストールします。(apxsは、RPMならhttpd-develパッケージに含まれています)

% sudo yum install httpd-devel

次にmod_xsendfileをダウンロードします。mod_xsendfileは、mod_xsendfile.cという1ファイルだけなので、それをダウンロードしてインストールします。

ブラウザからダウンロードする際は問題無いのですが、wgetでダウンロードしようとすると証明書エラーが発生します。–no-check-certificateオプションを付けるとこのエラーを避けることができます。

% wget --no-check-certificate https://tn123.org/mod_xsendfile/mod_xsendfile.c

apxsでmod_xsendfileをインストールします。

% sudo /usr/sbin/apxs -cia mod_xsendfile.c

インストールと共にhttpd.confにLoadModuleが追加されます。

[/etc/httpd/conf/httpd.conf]

LoadModule xsendfile_module   /usr/lib/httpd/modules/mod_xsendfile.so

mod_xsendfileを設定する

mod_xsendfileを利用するために設定を行います。

httpd.confでXSendFilePathを指定する

まず、XSendFilePathで出力を許可するパスを指定します。mod_xsenfileではdocument_root外のファイルを出力することができるので、誤って意図しないファイルの出力を避けるために出力対象のパスを指定する必要があります。

例えば、出力するファイルは「/path/to/images」以下にあるなら以下のように指定します。

[/etc/httpd/conf/httpd.conf]

XSendFilePath /path/to/images

XSendFilePathは、VirtualHostやDirecortyディレクティブでも指定が可能です。Directoryディレクティブでは実行するPHPファイルのパスを指定できます。例えば、CakePHPで指定するなら以下のようになります。(出力ファイルがapp/data以下にあるとします。)

[/etc/httpd/conf/httpd.conf]


  XSendFilePath /path/to/app/data

XSendFileをonにする

次にXSendFileをonに設定します。これによりX-Sendfileが有効となります。

/etc/httpd/conf*な設定ファイルでも記載できるのですが、アプリ側ファイルの方が都合が良いので、.htaccessに設定を書いておきます。

[/path/to/app/webroot/.htaccess]


    XSendFile on

これで設定は完了です。あとはPHPから出力するファイルを指定します。

XSendFileAllowAboveは削除

なおmod_xsendfile0.9ではXSendFileAllowAboveという設定項目があったのですが、これは0.10で削除されたようです。記載しているとエラーになるのでご注意を。

PHPから出力するファイルを指定

mod_xsendfileと使って、PHPからファイルを出力するにはX-Sendfileヘッダで出力ファイルパスを指定します。

下記のようにreadfile()を記載していた箇所(下から2行目)を、X-Sendfileを出力するheader()に書き換えます。

これでmod_xsendfileからファイルが出力されます。

ちょっと気になったこと

X-Sendfileヘッダは外部に出力される?

X-Sendfileヘッダには出力ファイルのパスを指定するので、外部に出力されるのはあまり好ましいことではありません。mod_xsendfileの処理が有効になっていれば、このヘッダは除去され外部には出力されないようになっています。

0バイトのファイルが出力される

X-Sendfileヘッダで指定したファイルパスが、XSendFilePathで指定したパスにマッチしないと0バイトになるようです。必要であれば、XSendFilePathにファイルパスを追加しましょう。

404が発生する

X-Sendfileヘッダで指定したファイルが存在しない場合は404になります。

PHP以外でも使える?

X-Sendfileヘッダをレスポンスヘッダに出力できれば良いので、PHP以外でも利用できるようです。

Apacheで使えるX-Sendfile

数年前にこんなエントリも書いたりしていたのですが、たしか当時はApacheでの実装は無かったと思います。

なんとなくそのままのイメージでいたので、Lighttpd(nginxにも似た機能があったような。X-Accel-Redirectかな。)いいなあと思ってたら、実は結構前からApacheでもできるようになったんですね。

この認証ロジックはPHP、出力はmod_xsendfileと、それぞれ得意な分野に分けるのは、Unixっぽくて好きです。

PHP5.3+古いCakePHPのDeprecated表示をPHPコードを書き換えずに抑制する

この記事の所要時間: 133

PHP5.3+古いCakePHPで表示される大量のDeprecatedを抑制する方法です。

これはPHP5.3からE_ALLにE_DEPRECATEDが含まれたためで、非推奨な関数や文法を使っているとDeprecatedエラーが表示されます。

Deprecated表示を抑制する一番単純なのは、error_reporting設定でE_ALLからE_DEPRECATEDを外す方法です。

error_reporting = E_ALL & ~E_DEPRECATED

CakePHPでもデバッグレベルが0であれば、この方法で回避可能です。

しかし開発環境でデバッグレベルを1以上にしていると、フレームワークがerror_reportingをE_ALLに上書きしてしまうため、Deprecatedが表示されてしまいます。

E_ALLを設定している箇所を書き換える方法もありなのですが、開発環境にある複数のプロジェクトについて書き換えていくのも中々骨の折れる作業です。

ということで、CakePHP側のソースは書き換えずにDeprecated表示を抑制する方法を考えてみました。

E_ALLからE_DEPRECATEDを外す

方法は単純。PHP自体のソースを変更してE_ALLからE_DEPRECATEDを外すだけです。

変更箇所は1箇所だけ。

[Zend/zend_errors.h]

— zend_errors.h.org 2010-09-23 18:10:00.000000000 +0900
+++ zend_errors.h 2010-09-23 17:05:30.000000000 +0900
@@ -38,7 +38,7 @@
#define E_DEPRECATED (1<<13L) #define E_USER_DEPRECATED (1<<14L) -#define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR | E_DEPRECATED | E_USER_DEPRECATED) +#define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR | E_USER_DEPRECATED) #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) #endif /* ZEND_ERRORS_H */ [/code]

あとは通常どおりPHPをビルドしてインストールすればokです。

変更前後でE_ALLの値は以下のように変わります。

変更前(オリジナル)
% php -r 'var_dump(E_ALL);' 
int(30719)

変更後
% php -r 'var_dump(E_ALL);' 
int(22527)

これでerror_reportingにE_ALLが設定されても、Deprecatedは表示されません。

とりあえずですが

本来はDeprecatedな原因を取り除くことが一番なのですが、本番環境はPHP5.2や5.1で、開発環境はPHP5.3にしたいということがあったので、この方法で対処しました。

アプリケーション側のソースは一切変更する必要が無いので楽ですね。まあ開発環境限定ということで。

iPhone/iPadのスクリーンショットを共有する「iScreenShot」をリリースしました

この記事の所要時間: 421

iPhone(iPod touch)、iPadのスクリーンショットを投稿して、みんなで見て楽しむサービス「iScreenShot」をリリースしました。

iScreenShot
=> iPhone/iPadのスクリーショットを共有 | iScreenShot

機能の詳細は、実際にサイトにアクセスして頂くのが分かりやすいので(ヘルプもありますし)、ここではサイトを作る経緯までや公開してからについて、ざくっと書いてみます。

構築した経緯

iPhone 3GSを昨年(2009年)の夏に購入したのですが、アプリを入れてカスタムし出した頃から、他人のホーム画面にとても興味が出てきました。どうにかして色々な人のホーム画面が見れないかな、ということでこのサービスを考えました。

ただ、アイデアとしてはあったのですが、なかなか手が付けられずに結局そのまま放置されることになりました。

そして今年の春、iPadが発売され、さらにiPhone4(iOS4)が発表されました。デバイスがというよりOSのバージョンアップにより、当時よりホーム画面のカスタマイズの自由度が広がりました。つまりこれまで以上に多様なホーム画面が見られるわけです。

これは作るしかないでしょ、ということで公開にするにいたりました。

公開して

まだβ版ということで、8/1夜と翌日昼にこっそりTwitterにだけお知らせをpostしました。

TwitterでのRTやblog等でのご紹介で、少しづつですがスクリーンショットが投稿されはじめました。実際に投稿されたスクリーンショットを見ると、それぞれに個性があって面白いですね。知人がiPhoneを持っていてもホーム画面をじっくり見る機会はあまり無いので、こうやって色々なホーム画面が見られるのは想定していたより楽しいですね:D

使った方、見た方のコメントでも「面白そう」「人のホーム見たいよね」という話があって、作って良かったなーと思っています。

早速、iPhone/iPadのblogでお馴染みのtobu iPhoneさんととはてブニュースさんにも取り上げて頂けました!はじめは知っている人でボチボチ投稿してもらえれば良いかなと思っていたのですが、一気に色々な方に投稿して頂けるようになりました。ありがとうございます。やっぱり、すごい。

お気に入りのホーム画面

どんなスクリーンショットがあるかは見るのが一番なので、投稿されたスクリーンショットの中で自分のお気に入りのものをご紹介します。

=> お気に入り | iScreenShot

まずは公開早々に投稿頂いたitayanさんのホーム画面。

青系の背景とアイコンできれいにまとまっていますね。色合いを合わせるように意識してアイコンを並べているとのこと。なるほど。

ご自慢のホーム画面をキャプチャーしてみました。 | iScreenShot

次にユニークなホーム画面を投稿されているfool4rootさんのホーム画面。

アイコンを全面に置かずにあえて背景を見せるのがポイントですね。しかしFlashって:D

Flash 対応しました :-P | iScreenShot

そして今のいちおしがこれ!

Kzh_09Jpさんのホーム画面です。

はじめて見た時に驚いて、さっそくコメント入れました:D iOS4のホームボタン2度押しによるアイコングレーアウトを上手く利用して背景を浮かせています。これはすごい。ぜひ実機で次元が現れるところを見てみたいです。

ホームボタンを連続二度押したときに現れるこのショットが何気に気に入っ... | iScreenShot

あとおまけで、自分が投稿したものを。

文字アイコンを並べて作ってみました。この画面を2ページ以降に用意しておいて、相手に「ほら、スライドさせて」といって、見せると効果ありそうです:D

@crema おたんじょうび、おめでとうございます! | iScreenShot

ホーム画面ではなく、ロック中の画面です。iPhone使っている人ならいつも見るバッテリ表示の電池から液漏れです:D これは実際に人に見せると反応が良いです。

バッテリーから液漏れ | iScreenShot

ほかにもいろいろなスクリーンショットがあるのでサイトで見てみて下さい。

ホーム画面は楽しい!

投稿されたスクリーンショットを見て、あらためて思うのはやっぱりiPhone/iPadは画面が美しいですね。並べてみると惚れ惚れします。また、その美しい画面をそのままスクリーンショットで保存できる機能を標準で用意しているのは、さすがAppleだなーと思います。

これまで、それほどホーム画面の体裁を意識していなかったのですが、色々な人のホーム画面を見ると俄然やる気がでて来ますね。

見て楽しい、投稿して楽しい、というようにiPhone/iPadユーザ(+気になる人)が楽しめるサービスになればなあ、と思っています。ホーム画面コンテストとかやると楽しそうなので、企画も色々とやっていきますね。

どうですか?あなたのご自慢のスクリーンショットも投稿したくなってきましたか?

=> iPhone/iPadのスクリーショットを共有 | iScreenShot

書籍名に年齢が入っている本を探す

この記事の所要時間: 053

「35歳からの○○」「40歳までに身につける××」といった書籍名に年齢が含まれる本が数多くあります。

こういった書籍にはどういうものがあるだろう、ということで調べてみました。

日頃、電車の広告や日経の広告などに掲載されているビジネス書などで年齢が書籍名に含まれる本を良く見ます。

年齢は万人に必ずあるものですし、自分に合致する年齢であれば興味を引くので良く利用されているのかもしれません。

実際にどのような本が出版されているのかを楽天ブックス書籍検索APIを使って調べてみました。

調査対象

楽天ブックス書籍検索APIで取得できる書籍から書籍名に年齢が含まれている本を抽出しています。

「0歳児・1歳児・2歳児のための乳児保育」といった複数の年齢が書籍名に含まれる場合はそれぞれの年齢として加算しています。

「 1歳から100歳の夢」といった年齢を範囲で含めている書籍に関しては加算していません。

年齢別書籍数グラフ

集計結果のグラフは以下。

=> 年齢別書籍数グラフ

最も多く含まれている年齢は3歳

最も書籍名に多く含まれている年齢は3歳でした。続いて5歳、2歳、4歳、0歳、1歳と乳幼児向けが並ぶ結果となりました。

ビジネス書系が並ぶのかと思いきやこれは意外な結果ですね。

「3歳のお気に入りえほん集」「ディズニーの読み聞かせえほん(どきどき3歳)」「 3歳までこそ大切な子育て10則」など子育て本、知育系の本が並んでいました。このあたりは1年齢の本も多いですが、「3・4・5才のおりがみ」のようにいくつかの年齢をまたいでいるのも特徴ですね。

たしかに実体験としても幼児向け本は何冊も買っているので、言われてみれば納得です。

=> 3歳の本を見る

やはり多いのは10区切り

次に多いのが10区切りで、100、50、60歳と続きます。

他にも40、10、20、15、35歳が上位に来るのでキリの良い年齢は、その付記の年齢の人も含めて対象となりやすいようです。

ここでも意外なのが、100、50、60歳というやや諸先輩向けの本が多いということです。日頃、目にする30/40歳代の本よりも多いというのは本に親しみを持つ年齢が故なのでしょうか。

面白いことに、100歳が含まれる本には「100歳まで」という表現が多いのに対し、50、60歳が含まれる本では「50歳から」「60歳から」という本が多いです。50、60歳はまだまだこれからですね。

=> 100歳の本を見る
=> 50歳の本を見る
=> 60歳の本を見る

意外にビジネス書は少ない?

広告の印象ではビジネス書や自己啓発系の本が溢れているのかと思っていたのですが、上位の年齢層を見てみると必ずしもそうではありませんでした。

本のジャンルとしてはビジネス系を除くと、教育書や小説、あと闘病記的な本が目に付きました。

年齢が含まれる本から見るとある女性の20代

20歳(はたち)でお店を立ち上げる!
21歳アタシ的寂しさ
綾。ホステス、22歳。新装版
23歳のディールメーカー
24才・時給750円の私がベンチャー経営で劇的成長できた理由(わけ)
迷い続ける25歳の退職届
26歳のレクイエム
27歳からの就職術
28歳からのぶっつけ留学成功法
29歳までに“その他大勢”から脱けだす習慣
30歳からの安産

私はアゲ子。20歳で店を起ち上げたけど、寂しくなって、ホステスになったの。23歳でディールメーカーになったけど、24歳の時給は750円。25歳で迷ったあげく退職した。。。
26歳の時は無職でどん底ね。でも27歳に奮起して就職活動をしたけど、気が変わって28歳で留学。29歳に「私はその他大勢とは違うのよ!」と一歩抜け出す習慣を身につけた結果、30歳で無事に安産。今は幸せよ。

といった20代人生が思い浮かびますね:D

年齢が含まれる本を探すサービス「アゲ本」

こういった年齢が含まれる本を探すサービスを作ってみました。

「アゲ本」
http://agebook.in/

年齢を入力すると書籍名にマッチした書籍をランダムで表示します。こちらでは「1から100歳」といった年齢範囲の書籍にもマッチするようになっています。

自分の年齢を入力するもの良し、どなたかの誕生日プレゼントとして本を探すのも良し、一度遊んでみて下さい。

ホーム > PHP > CakePHP

検索
フィード
メタ情報

Return to page top