Home

Shin x blog

第2回関西アンカンファレンスを2011/01/08に開催します

この記事の所要時間: 243

昨年好評を博した関西アンカンファレンスをまたまた開催します。

アンカンファレンスって何?の方は、昨年書いたエントリをご参照下さい。

大阪でアンカンファレンスを12月か1月にやります

前回の模様は以下から。

今回は兵庫県立大学様に神戸キャンパスを会場として提供頂けることになりました。ありがとうございます。

場所はハーバーランドにあります。見学に行ってきたのですが素晴らしい施設で、かなりテンション上がっています!

ビルの入り口はこんなにおしゃれ。

会場はこんな感じ。

窓からはこんな絶景が見られたりします。

概要

開催概要は以下になります。

■ 開催概要
・日時:2011/01/08(土) 10:30 – 18:00(開場:10:00)
・場所:兵庫県立大学神戸キャンパス(神戸ハーバーランドセンタービル23F)
・地図:http://www.u-hyogo.ac.jp/access/campus01.html
・参加費:0円(名刺ホルダーなど若干経費がかかるので、受付にカンパ箱を設置します。あくまで任意ですが、ご協力頂けると助かります。)
・定員:100人

タイムテーブル

10:00 受付開始
10:30-10:45 オープニングセッション
10:50-12:50 午前の部
12:50-13:50 お昼休み
13:50-14:50 午後の部1
14:50-15:50 短め枠
15:50-17:50 午後の部2
17:50- エンディングセッション

発表会場

発表を行う会場は、隣接する2教室に分かれます。2つのセッションが同時に進行するので、聞きたい方、発表したい方に移動して下さい。

発表枠

今回は「1セッション20分(15分発表+5分移動、準備)」となります。

前回の反省を生かして、移動・準備する時間を設けています。

短め枠

発表慣れしていない人や短めの発表がやりたい人向けの特別枠です。10分セッション(8分発表+2分移動、準備)となります。

発表枠の申し込み

もちろんこれは前回と同じく当日にホワイトボードに付箋を貼っていく方式になります。いつ発表するか、どんな発表が出るかは当日のお楽しみ!

発表テーマ

これも前回と同じくIT/Web系の内容なら何でもokです。

ただ、色々なバックグラウンドを持つ方が集まるイベントなので、何かを貶めたり攻撃したりするような内容は避けてくださいね。(みんな大人ですしね!)

申し込み

以下リンクのフォームからお申し込み下さい。

第2回関西アンカンファレンス申し込み

昨年は80名の申し込み枠があっという間に埋まったので、参加希望の方はお早めに。

発表される方もそうでない方も2011年は関西アンカンファレンスから盛り上がっていきましょう!

「半歩先のWebシステム構成」を発表してきました – 俺の話を聞け!

この記事の所要時間: 140

「俺の話を聞け!」という名のイベント(ほんとにイベント名です:D)で発表してきました。

イベントの詳細はこちらから

去年やった関西アンカンファンレスを小規模でやったようなイベントです。できるだけ多くの人に発表の機会をということで、初めての方から発表慣れしている方まで総勢19人が発表を行いました。

参加しての雑感をつらつらと。

  • 会場はクロノスさん。素晴らしい会場でした。ありがとうございます!
    これからもよろしくお願いしますm(_ _)m
  • 事前に聞いていたのに全然手伝えなくてごめんなさいm(_ _)m
  • やっぱりテーマソングはこれ
  • 大事なこと。「人は人、自分は自分」
  • とにかく楽しかった!
  • 発表した人は印象は残りやすいし、発表者同士の親近感もある。やっぱりできるだけやった方が良いと思う。
  • 初発表の人の方がちゃんと準備をしていた。すばらしい!
  • デモ最強。百聞は一見にしかず。
  • 笑いを求めるサガ:D
  • 話題が多岐に渡って面白かった。
  • 逆に話題を絞ってこういう形式のイベントも面白いかも。
  • お菓子はほどほどに。
  • 第2部も第3部も楽しかった!
  • 関西のイベントだと、勉強会やって、飲んで、歌ってをやっても家に帰れるのが嬉しい:D
  • 久しぶりの発表で妙に緊張した。。。でも、やって良かった。

「半歩先のWebシステム構成」

「半歩先のWebシステム構成」というタイトルで発表してきました。

自分の中で気になっている直近で使えそうなものをざっくり並べました。もう実践している人にとっては当たり前のことなのですが、来年はこの辺を意識してやりたいなと思ってます。

Reboot

ちょっと今年は色々あって、こういった活動から少し身を引いていたわけですが、今回のイベントでrebootした気分です。

やっぱイベントは良いですね。

来年は、1/8 や 4/2 など大きめのイベントがあるので頑張りますよ!

Mac+Google日本語入力でATOKショートカットキーで変換する

この記事の所要時間: 039

Mac+Google日本語入力でATOKのキーバインドで変換する方法です。

MacBookAirには、普段使っているATOKではなく、Google日本語入力を入れてるのですが、「CTRL+(u/I/o/p)」で「かな<->カナ<->半角カナ<->英字」といった変換ができず困っていました。

ごまかしごまかしF6-10を使っていたのですが、これまでのクセが抜けず、いらいらしていました。

今日こそ何とかするぞ!と意気込んで調べてみたところ、普通に設定がありました。。。

Google日本語入力の設定を開きます。(画面は英語版です)

keymap styleを「ATOK」に変更すればok。

なんでもっと早く気づかないか。

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 シリアライズデータ型(PHP Advent Calendar jp 2010 Day 2)

  • 2010-12-02 (木)
  • PHP
この記事の所要時間: 559

今年(2010年)は、日本でも技術系コミュニティのAdvent Calendarが流行していますね。

PHP関連だとCakePHP(明日書きます!)やSymfonyOpenPNEなどはあるのですが、PHP単体が無かったので作ってみました。

PHP Advent Calendar jp 2010

Advent Calendarについては、下記リンクが詳しいです。これを書いている段階では、まだ参加枠があるので、どんどん参加して下さい。みんなのちょっとしたPHPネタを書いていきましょう!

というわけで、まず初回(12/2に始めたので、Day1は空席で)のネタは、最近自分の中で流行中のPHPのシリアライズデータ(serialize()/unserialize())について。

シリアライズデータのデータ型

CakePHPのセキュリティホール発覚以降、一部で脚光を浴びたPHPのシリアライズなのですが、シリアライズデータで表現できるデータ型をあらためて調べてみました。

まあPHPのソース見れば一目瞭然ですね。

[ext/standard/var_unserializer.c]

 437   case 'C':
 438   case 'O': goto yy13;
 439   case 'N': goto yy5;
 440   case 'R': goto yy2;
 441   case 'S': goto yy10;
 442   case 'a': goto yy11;
 443   case 'b': goto yy6;
 444   case 'd': goto yy8;
 445   case 'i': goto yy7;
 446   case 'o': goto yy12;
 447   case 'r': goto yy4;
 448   case 's': goto yy9;

ざっくり読んだ感じでは以下な内容でしょうか。

C=CustomObject
O=Object
N=NULL
R=Reference
S=string
a=array
b=boolean
d=double
i=integer
o=Objectっぽいけどなんだろ?
r=Reference
s=string

シリアライズデータで表現してみる

‘b’ = boolean

boolean(論理型)です。

b:の後ろの数値は、1ならtrue、それ以外ならfalseになるようです。

b:1; => bool(true)
b:0; => bool(false)

‘i’ = integer

integer(整数型)です。

i:100; => int(100)

‘d’ = double/float

double/float(浮動小数点数)です。

d:10.123; =>float(10.123)

‘s’ / ‘S’ = string

string(文字列)です。’s’と’S’の違いはよく分かってないのですが、文字列をserialize()すると’s’になります。

s(S):の後ろが文字列のバイト数で、””で文字列を囲みます。

s:3:"abc"; => string(3) "abc"
S:3:"abc"; => string(3) "abc"
s:9:"頑張る"; => string(9) "頑張る"(UTF-8)

‘N’ => NULL

NULLです。

N; => NULL

‘a’ => array

array(配列)です。

a:の後ろは要素数です。あとは添え字、要素によって様々な形式を記載します。

a:2:{s:3:"1st";i:100;s:3:"2nd";i:200;}; => 
array(2) {
  ["1st"]=>
  int(100)
  ["2nd"]=>
  int(200)
}

‘C’ / ‘O’ / ‘o’=Custom Object / Object / Object?

クラスインスタンス(オブジェクト)です。通常インスタンスをserialize()すれば、’O’となります。

O:3:"Foo":1:{s:4:"var1";s:3:"abc";}

‘C’は、シリアライズする対象クラスがSerializableをimplementしている時に付与されます。この場合、シリアライズ、デシリアライズ処理は、PHPデフォルトの処理ではなく、対象クラスのserialize/unserializeメソッドで定義された処理が実行されます。

serializeメソッドではシリアライズしたデータをreturnします。unserializeメソッドでは、シリアライズしたデータが引数で渡されるのでそれをパースしてインスタンス変数にセットします。

C:3:"Foo":29:{a:1:{s:6:"value1";s:3:"abc";}}

‘o’は、内部的にはインスタンスを復元するようなのですが、具体的にどのように記載すれば良いかまだ分かってません><

‘r’ / ‘R’ = Reference

Reference(参照)です。’r’(小文字)と’R’(大文字)でデシリアライズした時の挙動が変わります。

‘R’の場合は、参照型としてデシリアライズされます。

a:2:{s:3:"1st";i:100;s:3:"2nd";R:2;}; => 
array(2) {
  ["1st"]=>
  &int(100)
  ["2nd"]=>
  &int(100)
}

‘r’の場合は、変数に参照先の値がセットされますが、参照型にはなりません。

a:2:{s:3:"1st";i:100;s:3:"2nd";r:2;}; => 
array(2) {
  ["1st"]=>
  int(100)
  ["2nd"]=>
  int(100)
}

参照型変数をシリアライズした際は、参照先の変数も一緒にシリアライズされれば’R’に、参照先変数がシリアライズデータに含まれていなければ、参照先の値がセットされます。(’r’は?)

リソース型やクロージャはNG

リソース型やクロージャは標準のserialize()ではシリアライズできません。

シリアライズデータは見れば分かる

シリアライズデータで身近なのは、セッションデータだと思うのですが、一見複雑そうなシリアライズデータでも開いてみると実は結構読めます。何より変数値はほぼそのまま入っているので、なんとなくでも内容を掴むことができます。

PHPユーザならシリアライズデータを読むことは普通だと思うのですが、初日ということでBasicなネタにしてみました。

では、明日のikeekiさん、よろしくお願いします!

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'"

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

会社名刺626枚のうち、Twitterアカウントが入っているのは何枚か?

この記事の所要時間: 133

会社の名刺にTwitterアカウント入れてますか?

1×1の名刺をリニューアルしようともろもろ検討中です。

せっかくだからTwitterアカウントを入れようかなと思って、他社がどうしているのかを手元の名刺で調べてみました。手持ちの名刺を全部見ると大変なんで、ぱっと取り出せた626枚の会社名刺で見てます。

ちなみに取り出した名刺の束には個人名刺も150枚ほど混ざってたので、800枚近くありました。夜中に何をやってんだか。。。

626枚の会社(法人)名刺

626枚の会社名刺の中でTwitterアカウントが入っていたのは、9件でした。1%強と思ったより少なかったですね。

会社をIT系とそれ以外に分けると、やはり9枚は全てIT系企業でした。

  • IT系企業:359枚(Twitterアカウント:9枚)
  • 一般企業:267枚(Twitterアカウント:0枚)

9件は全てここ一年以内で頂いた名刺

Twitterアカウントが入っていた会社名刺は全てここ一年以内に頂いた名刺ばかりでした。

名刺の中には数年前に頂いたものもあるので、もしかしたら今現在の名刺にはTwitterアカウントが入っているかもしれませんね。

懐かしい名刺もちらほら

なんだか色々な名刺を見ているとその当時のことがよみがえってきて懐かしいですね。

IT系では転職されている方も多いので、前職の名刺や前々職や前々前職の名刺が出てきたり:D

また、同じ会社でも現在とは名刺が変わったりして、時の流れを感じます。

1×1の新名刺にTwitterのアカウントを入れると、数年経ってTwitterが廃れると意味ないなーと思いつつ、どうせいずれ名刺は変えるものなので、時代を反映するものとして入れて見ようと思います。

新名刺は、乞うご期待。

Google Docs のスプレッドシートに表データをコピペする

この記事の所要時間: 211

Google Docs のスプレッドシートに表データをコピペする方法です。

Google Docs 便利ですね。Excel に比べると多少操作性や機能は劣りますが、どこからでも共有できるというのはそれを補って余りあります。

そんな便利なスプレッドシートなのですが、コピーしたCSVを表形式でスプレッドシートに貼る機能がありません。

もちろんCSVをファイルに書き出してインポートすれば良いのですが、今画面上に表示しているCSVをそのままコピペしたい時ってありませんか。

例えば、以下のようなCSVをコピペしてスプレッドシートに貼り付けると、1行が1つのセルに文字列として格納されてしまいます。

1,原田哲也,TZM250
2,加藤大治郎,NSR250
3,青山博一,RS250RW

タブ区切りならいける

何とかならないかなーと試してみると、なぜかタブ区切りだと各セルに値を入れることができました!

先のCSVをタブ区切り(TSV)に変更して、スプレッドシートに貼り付けると、

1    原田哲也    TZM250
2    加藤大治郎 NSR250
3    青山博一    RS250RW

ばっちりいけます。

ただし貼り付けはショートカットキーで

これ不思議なのですが、マウスの右クリックから「貼り付け」を選択するとセルに値が入りません。

ショートカットキーの command+v(Windowsなら、ctrl+v)でペーストすれば ok です。

psqlの検索結果をスプレッドシートに貼り付け

そもそもなんでこれをやりたかったかというと、psqlで検索した結果をスプレッドシートに貼り付けたかったから。

psqlで検索結果をTSVにするのは以下。

$ psql db_name
db_name=> \a   // クエリ結果の整形オフ
db_name=> \t    // 検索結果のみ出力
db_name=> \pset fieldsep '\t'  // 列の区切り文字をタブに(カンマにすれば CSV に)

db_name=> select id,name,code from users order by id; // 検索クエリ
1     原田哲也     TZM250
2     加藤大治郎     NSR250
3     青山博一     RS250RW

あとはこの結果をコピーして、スプレッドシートに貼り付けるだけ。あー便利。

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っぽくて好きです。

Home

検索
フィード
メタ情報

Return to page top