2007年2月15日 (木)

拡張子がHTMLのファイルをPHPとして実行させる

PHP を Apache 上で動作させるときには。モジュールとして組み込む方法が一般的だと思います。

通常は、「AddType」を用いて PHP ファイルを認識させます。「httpd.conf」ファイルに以下のような文を追加します。

AddType application/x-httpd-php .php

しかし、これでは明らかにPHPを使用していることがわかってしまいます。それにHTMLファイルの中に一部PHPを埋め込んで動作させたい場合があると思います。
そういった場合には、httpd.confファイルにHTMLの拡張子である「.html」を追加します。

AddType application/x-httpd-php .php .html

このままだとすべての「.html」という拡張子がついたファイルがいったんPHPで読み込まれることになるので無駄な処理が実行されてしまいます。

こういった場合は、特定のディレクトリのファイルだけ対象になるように「.htaccess」ファイルに上記の設定を行います。

このときhttpd.confファイルの設定で該当のディレクトの<Directory>セクションにあるAllowOverrideディレクティブに「FileInfo」が指定されていない場合動作しないので気をつけてください。自分でサーバーを管理していない場合は、管理者にお問い合わせください。

<Directory>セクションとAllowOverrideディレクティブの詳しいことは、Apacheのドキュメントに書かれているのでそちらを参考にしてください。
<Directory>セクションのドキュメント
AllowOverrideディレクティブのドキュメント

しかし、これでもまだ関係ないファイルが多い場合などは無駄な処理が実行されてしまいます。こういった場合は、.htaccessファイルに<Files>セクションを追加することで指定のファイルだけをPHPとして処理することが可能です。

<Files form.html>
    ForceType  application/x-httpd-php
</Files>

こうすることで特定のファイルだけをPHPのファイルとして実行させることが可能です。<Files>セクションのファイル名は正規表現を使うことができるようです。

<Files>セクションとForceTypeディレクティブの詳しいことは、Apacheのドキュメントに書かれているのでそちらを参考にしてください。
<Files>セクションのドキュメント
ForceTypeディレクティブのドキュメント

これでスマートにPHPを実行させることができます。

| | コメント (0) | トラックバック (0)

2007年1月29日 (月)

[PHP]拡張モジュールを自作する

あけましおめでとうございます。といってもすでに1月も終わろうとしていますが ^^;
本年もヨロシクお願いします。

今年一発目のネタは、PHPで拡張モジュールを自分で作ってしまおうというネタです。

PHPはすでにいろいろな機能が、標準でついているのでほとんど自作する必要はありません。それ以外にもPEARPECL といった拡張モジュールもいろいろあるので、それらを使うといろいろなことができます。
しかし、ライセンスの問題であったり、パフォーマンスを出すために独自機能をスクリプト以外で作ろうとするためには、やはり自分で拡張モジュールを作る必要があります。

そこで今回は、実際に拡張モジュールを作ってみました。

方法は、すでに標準のPHPのソースの中に拡張モジュールを簡単に作る機能があるのでそれを使用していきます。

まずはじめに、関数の雛形を作ります。これは、実際にスクリプトから呼び出す関数の宣言を行うファイルで関数名とその関数の引数や戻り値を書いておきます。これを使用するとこの宣言しておいた関数を基にソースの中身を作成してくれるのであとの作業が楽になります。

test.protoファイルの内容
void myfunction_a(string szInput)・・・(1)
string myfunction_b(string szInput , int nIDs )・・・(2)
string myfunction_c(mixed mInput , array aIDs )・・・(3)

(1)は、引数が文字列で戻り値がなしの関数で(2)は戻り値が文字列で引数が文字列と整数型になっています。(3)の関数は戻り値が文字列で第1引数が何でもありで第2引数が配列型になっています。。
string」,「mixed」,「array」は、PHPの型です。
これ以外の型については、PHPのマニュアルの型の部分に書いてあるものが使用できるはずです。(「string」,「int」,「array」,「mixed」以外は試してませんがこれらについては雛形がきちんとできていました。)
ちなみに関数名に英大文字を使用すると怒られるようです。

関数の雛形ファイルを作成したら今度はこれを使用して実際のソースの雛形を作成します。

Windowsの場合はCygwinが必要になりますのでCygwinプロジェクトからダウンロードしてインストールをしておいてください。

Cygwinまたは、UNIXのシェルから以下のコマンドを発行してソースを作成します。

$ sh ext_skel --extname=test --proto=test.proto

「--extname」で拡張モジュールのパッケージ名を指定します。この指定した名前のディレクトリが作成されてその中にソースの雛形が作成されます。
「--proto」に先ほど作成した関数の雛形が書いてあるファイル名を指定します。それでこの関数の雛形がソースの中に作成されます。

作成されたディレクトリの中をみると以下のファイルが作成されています。

$ ls -l
合計 32
-rw-r--r--  1 shima  shima     4  1月 29 22:19 CREDITS
-rw-r--r--  1 shima  shima     0  1月 29 22:19 EXPERIMENTAL
-rw-r--r--  1 shima  shima    1975  1月 29 22:19 config.m4
-rw-r--r--  1 shima  shima   282  1月 29 22:19 config.w32
-rw-r--r--  1 shima  shima    2771  1月 29 22:19 php_test.h
-rw-r--r--  1 shima  shima    6467  1月 29 22:19 test.c
-rw-r--r--  1 shima  shima   496  1月 29 22:19 test.php
drwxr-xr-x  2 shima  shima    4096  1月 29 22:19 tests

「test.c」と「php_test.h」が関数の中身を実装していくファイルになります。このファイルに関しては、後は普通のCの関数として実装していけばよいです。戻り値や引数などの処理については、このほかの拡張モジュールのソースを参考にしていけば大変ですが実装は可能です。

関数の実装が終わった後は、組み込みを行います。そのまま組み込に条件「--with-XXX」とか「--enable-XXX」をつける場合は、「config.m4」と「config.w32」を編集して必要な部分からコメントの記号をのぞいて有効にします。
注意点ですが、「config.w32」で「--with-XXX」を有効にしたときにほかの部分のコメントを残しておいたまま処理を行った場合にうまくいきませんでした。うまくいかなかった場合は、先頭2行以外のコメント部分を完全に削除したほうがいいかもしれません。

組み込みは、buildconfを実行して「configure」スクリプトに反映させます。これを行わないとビルドしたときに組み込まれません。Windowsでは、「buildconf.bat」を実行します。

$ ./buildconf

ここでエラーが出なければ「configure」スクリプトを実行します。Windowsでは、「cscript /nologo configure.js」を実行します。ほかのオプションに関しては、必要なものを指定してください。

$ ./configure '--enable-mbstring' '--enable-mbregex' '--with-pcre-regex' '--enable-session' ・・・

続いてビルドします。

$ make

これでビルドのエラーが出なければ完成です。

もし、関数が正しく実装されたかどうかを確認する場合は、「tests」ディレクトリ内の「001.phpt」ファイル内に関数のテストコードを実装しておけば「make test」とビルド後に実行すれば自動的にテストを行ってきちんと動作しているか確認することができます。

以上で拡張モジュールを自分で作成する方法を簡単に説明しました。実際には、PHP独自の実装をいろいろ行わなければなりませんが似たような機能が実装されている拡張モジュールがほかにあると思いますのでそちらの関数を参考にしながら実装するのが簡単だと思います。くれぐれもそのままパクらないでくださいね。

| | コメント (0) | トラックバック (0)

2006年11月 8日 (水)

[PHP]PDOではまったこと

PHPのPDOで開発を行っていますが、基本的にWindows環境で試験などを行っています。それでたまにLinux上で試験を実行してみととたんに動かなくなることがあります。今日は、ちょっとした思い込みで動かないことになってしまっていたのでそのことを書いておきます。

データベースからデータを取り込むときにPDOを使用している場合、

$db = new PDO( 'pgsql:host=localhost port=5432 dbname=testdb user=bruce password=mypass' );
$stmt = $db->prepare( 'SELECT * FROM testtable WHERE id = :id' );
$stmt->execute( array( ':id'=>$id ) );
$result = $stmt->fetch( PDO::FETCH_ASSOC );

というような一度、「prepare」をしてクエリーの発行準備をおこなってそれから「execute」にパラメータを渡して実際の実行を行うといった書き方をします。

ここまでは、別に何ということもないのですが、複数のパラメータを「execute」に渡すときに落とし穴がありました。

たとえば

$stmt = $db->prepare( 'SELECT * FORM shouhin WHERE price > :min AND price < :max';
$stmt->execute( array( ':min'=>10000, ':max'=>50000 );
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );

というような別の値をとるような変数がある場合は問題ないのですが、同じ値を使う場合、何も考えないで

$stmt = $db->prepare( 'SELECT * FORM seiseki WHERE kokugo = :tensu AND sansu = :tensu';
$stmt->execute( array( ':tensu'=>100 );
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );

という感じに「tensu」を使いまわしてクエリーを発行しようとしました。これは、Windows版で実行すると問題なく国語と算数の点数が100点のデータを取得できるのですが、Linux版に持っていくとクエリーエラーが発生して落ちてしまいます。

よくよくドキュメントを見てみるときちんと「prepare」の中にも書かれていましたし、オンラインのドキュメントの囲みの中で書かれていますがこちらにも同じようにはまった人がいたようです。

つまりは、

$stmt = $db->prepare( 'SELECT * FORM seiseki WHERE kokugo = :kokugo AND sansu = :sansu';
$stmt->execute( array( ':kokugo'=>100, ':sansu'=>100 );
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );

といった感じに同じ値を使うのでもそれぞれ別の名前として使用しろということらしいです。

まあ、いろいろとありましたが結論としてはきちんとドキュメントに目を通せということなんでしょうけど、どう考えても「prepare」に名前をつけれるのであれば使い回しができてもよさそうな気がします。

| | コメント (0) | トラックバック (0)

2006年10月26日 (木)

[PHP]PDOでPostgreSQLを操作したときのエラー

PHPとPostgerSQLを使用してアプリケーションを開発していますが、そのときにLinux版でのみエラーが発生するということがありました。

PostgreSQLの設定でログを出力するように設定していて気がついたのですが、Windows版では、問題なくクエリーの発行が行われて正常に終了していました。そこでOSをFedora Core 5に変えてその上で同様に試験をしていたところあるパターンでのみ、登録処理がうまくいきませんでした。

クエリーのログとしては、

LOG:  statement: DEALLOCATE pdo_pgsql_stmt_09b83bd4
ERROR:  prepared statement "pdo_pgsql_stmt_09b83bd4" does not exist

といった内容で、どうやら発行したクエリーの解除を行っているのですが、そもそも発行していないクエリーの解除を行っているためにエラーが発生して処理が終わっていることがわかりました。
そもそも、そんな操作はいらないんですが^^;

そこでPHPのバグリポートの中をチェックするとどうやら同じような不具合を発見することができました。

そのバグリポートを見てみるとPostgreSQLのPDOのドライバにバグがあるらしくて、パッチを当てれば動作することがわかりました。

そこから、いろいろとパッチを当ててビルドするのにいろいろ大変でしたが(それは、また次の機会に)、パッチを当てて動作を確認したところ問題なく動作して余計なクエリーの解除をしないようになりました。

まだまだ、調べていくとまだまだPostgreSQLのPDOドライバはできがよろしくないようなので別の問題が発生するかもしれません。

[追記 2006/10/26 21:18]
ここで使用しているPHPのバージョンは、5.1.6で、PostgreSQLは8.1.4です。

| | コメント (0) | トラックバック (0)