PHPスクリプト無料配布所 :: PHP.TO http://php.to PHPスクリプトの無料配布、Tips集。PHPやPostgreSQLなど、各種マニュアルもあり(毎日更新) ja サクラエディタの強調表示用キーワードファイル(.KWD)を作成する方法 http://php.to/tips/13/ オープンソースの国産エディタとして、サクラエディタ(sakura editor)というテキストエディタがあります。 フリーなのに他言語対応・タブ表示・常駐機能・複数の文法強調表示対応などなど、多機能な優れモノなので、PHPの開発にもこれを用いる方も多いのではないでしょうか。 PHPはビルトイン関数が多いため、PHP関数の強調表示を行うとエディタ側がメモリを食うこともあり、当初は強調表示のためのキーワードファイル(以下、KWDファイル)が配布パッケージ内に含まれていなかったのですが、最近になって含まれるようになりました。 しかし、このKWDファイルはこちらで公開されているものを使用しているのか、やや古い(2005/01時点のもの)ようです。 このKWDファイル内には、3440のPHPキーワード(予約語や関数)が含まれていますが、PHPのバージョンアップに伴い、2008/09現在では、3900以上のPHPキーワードが存在する模様です。(class内の関数などを入れればもっと多い) file_put_contents や JSON 関数など、比較的新しい関数を利用する場合は、強調表示されなくて困るので、KWDファイルを最新のものに更新するスクリプトを作成してみました。 使い方:以下のコードをコピーして、適当な名前(例:make_kwd.php)で保存します。 コマンドラインで実行する場合は php make_kwd.php > php.kwdと実行します。 ブラウザ上で実行する場合は、適当なサーバに上げて、そのファイルのURLを叩き、表示されるテキストをコピーして php.kwd というファイル名で保存してください。 あとは、サクラエディタがインストールされているフォルダにある keyword フォルダに同ファイルを上書きコピーして、サクラエディタの[設定]→[共通設定]→[強調キーワード]でPHPのセットに対して、先ほどのファイルをインポートしなおせば完了です。 (参考)サクラエディタでPHPキーワードを強調表示する設定 #同様に、KHPファイルも作ろうと思ったのですが、どこかで作成スクリプトを公開されていたような。。。 #残念ながら探し出せませんでしたが、需要があれば作ります。 ##なお、サクラエディタはPHPのchmファイルと連携できますが、PHPの公式サイトで配布されている ##chmファイルは一部文字化けしているので、こちらを参考に、KeyToolsでchmファイルをリビルドすると幸せになれます。 2008-09-03T23:59:59+09:00 PHPで日本語ドメインを使う方法 http://php.to/tips/12/ IE7の普及とJPNICによる日本語ドメインの価格値下げの効果でしょうか、最近になってやっとpunycodeでエンコードした日本語ドメインが増えてきました。 PHPでも日本語ドメインを使うことがあると思いますが、あまり資料がないようなので、最もお手軽だと思われる方法を紹介します。 まず、コマンドラインから PEAR の Net::IDNAをインストールします。 pear install Net_IDNA これで下記の関数を用いて、日本語ドメインのエンコード/デコードを行えるようになります。 ちなみに、$url の文字コードはUTF-8である必要があります。 また、デコードの際は念のため "xn--" がドメインの行頭に含まれているかどうかを確認してからの方が幸せになれるかもしれません。 2007-08-28T23:59:59+09:00 携帯電話端末用GPS機能を利用した緯度経度情報の利用方法(その2) http://php.to/tips/11/ 需要がないと思って、すっかり間が空いてしまってました。 久々に更新します。 サブルーチン単位の公開になってすみませんが、dms度分秒単位とdegree度単位の相互変換関数を紹介します。 どちらかに合わせて計算したいのに、携帯電話によってはdmsまたはdegree系でしか座標を取得できなかったり、キャリアによって微妙にフォーマットが違うことがあります。そんなときの変換にどうぞ。 (ただし、こちらも桁落ち・丸め誤差が発生しますので精度は落ちます) ここに載っていない機種については、degree度単位で座標が取得できたと思います。 正規表現で書いたら、もっとすっきりしそうですね。 2007-08-23T23:59:59+09:00 mod_perlは本当に速いのか? http://php.to/tips/10/ 昔から、PHPとPerlはよく比較されてきました。 通常のPerlはCGIで動くので、httpdのモジュールとして動くPHPと比べたら起動のオーバヘッドのために「遅い」と言うのが通説でした。 そんな頃、川合さんのPerlよりPHPの方が軽くて速いは本当?というページでは「PHPと同じほぼ仕組みで動くmod_perlならPerlのほうが速い」という結論が出されていました。 このページは2002年から影響力が大きく「やっぱPHPよりPerlだよね」という風潮が吹いたこともありました。(小飼さんの404 Blog Not Foundのページもこちらの結果を参考にしているようです) ただ、当時から私が疑問に思っていたのは、上記サイトのベンチでは「mod_perlはアクセラレータであり、実行コードをキャッシュする」ことを考慮していないことです。 mod_phpはCGI版のPerlと同様にアクセラレータを通さずに毎回コンパイルが行われるのにも関わらず、です。 それに加え、Perlは必要なモジュールのみを実行時に use でロードすれば良いのですが、PHPではその性質上、モジュールのコンパイル時にリンクさせてやる必要があります。 この結果、mod_phpをロードしたhttpdは1プロセスあたりのサイズが増加し、最小単位で動作が可能なmod_perlに比べると、「軽い」とは言えないのも確かです。 よって、上記のようなテストを行うのであれば、PHP側では 「./configure時に必要最低限の機能しかenabledにしない。(どうしても拡張モジュールを使う場合は、dlでロードする)」 「APCやXCacheなどのアクセラレータ(実行コードキャッシュモジュール)を追加する」 という設定を事前に行うか、そもそもCGI同士で比較するべきだったのではないでしょうか。 私の経験では、上記設定を行った後にmod_perlとmod_phpでもう一度同じベンチマークを行えば、おそらくPHPの方が早いように思います。 ただし、私はPerlがPHPに比べて劣っていると言うつもりは全くありません。 そもそも言語自体が作られた経緯が違いますので、「何でも出来て、たまたまWEBにも対応できるから使われてきたPerl」と、「ほぼWEBだけに特化した作りのPHP」では、後者の方がWEB用途においては優れていて当たり前だからです。 レガシーな技術とportされるモジュールだけで10年以上も第一線でやっていけるPerl5は素晴らしいとさえ思います。 mixiやlivedoor、はてな、slashdotなどではmod_perlが使われていることもあって、最近はOSSでの大規模サイトではmod_proxy + mod_perlを利用したサイトの構築が増えてきているように思います。 Java Servlet,PHP,Apache moduleベンチマークのページやITmediaの記事など、Perl(CGI/mod_perl)とPHPを比較したベンチマークをたまに見かけて、非常に興味深い結果を見ることができますが、ほとんどが単純ループで簡単な処理を行うだけのものが多く、実際の業務のことを考えると、残念ながらあまり参考にならないことが多いです。 というのも、本来プログラムと言うのは「極力、ループを使ってはならない」ものだと思うからです。 (詳細な説明は省きますが、これはクイックソートとバブルソートの実行速度の差を考えれば明らかで、アセンブラの時代から速度を追求するプログラマは単純ループよりも美しいアルゴリズムで高速化を行ってきました。今はCPUが高速化されているので、そんなことお構いなしに強引にループでぶん回す人も沢山いるようですが、新人プログラマとウィザードの差はここで出ると思います) 本来であれば、実運用予定のシステムのシナリオに沿った、ファイルI/Oの速度やデータベースからのfetch速度、連想配列やオブジェクト操作などの複数の要素に対しての「実践的なベンチマーク」を行う必要があるように思います。 そこで、私がよくあるシステム構成で使われるような「実践的なベンチマーク」をやってやろうと考えて色々と環境構築を行っていたのですが、途中であることに気づいてベンチマークは取りやめることにしました。 何故かと言うと、試しに単純ループでベンチマークを取ってみたところ、Perl5.8とPHP4.3の頃はPerlの方が1.5〜2倍度速速いくらいだったのに、Perl5.8とPHP5.2とではPHPの方が1.5倍程度速いという結果が出たからです。 PHP5.0が出た頃はPHP4よりも遅いと言われていて、PHP5.1以降は高速化されたとは聞いていましたが、正直ここまでとは・・・。 こちらは純粋にコマンドラインから実行したものの速度であって、HTTPベース(つまりCGIやmod_perl/mod_php)での実行速度ではないのですが、既に言語仕様(というかインタプリタ)自体でこれだけ速度差が出ている状況では、モジュール云々以前の問題で、もはやベンチマークになりません。 もし要望があれば改めてmod_phpとmod_perlの比較をやってみようと思いますが、言語のバージョンの他にも、コードの書き方にもかなり依存することになるので、あまり意味がないような気がします。 とりあえずここでの結論は、現状では「mod_perl隆盛の時代ですが、PHP使いの人にはmod_phpで問題はなさそうである」ということでしょうか。 もっとも、Perl6/Parrotになると話は変わってくるのかもしれませんがね。 #ちなみに、実行したコードはこんなかんじの非常に単純なものです。 2007-02-02T23:59:59+09:00 携帯電話端末用GPS機能を利用した緯度経度情報の利用方法(その1) http://php.to/tips/9/ 最近の携帯電話では、GPS機能を利用して、その端末を中心としたアバウトな緯度経度が取得できます。 ただ、キャリアや機種ごとに取得方法・測地系が異なるため、実装の際は色々と注意が必要です。 以後、数回に渡って、携帯電話端末を利用したGPS取得のサンプルを掲載していきます。 参考になれば幸いです。 なお、緯度経度の測地系には日本測地系(TOKYO)と世界測地系(WGS84)が存在しますが、他のWebサービスAPIとの連携などを考慮して、以降は全て世界測地系に変換して処理することにします。 この際、下記のような関数を利用すると、日本測地形と世界測地系の座標が相互変換できます。(ただし、変換時の丸め誤差によって数十m程度の誤差が発生します) また、町名などの地名と組み合わせるには、国土地理院が公開しているメッシュ情報データベースを利用すれば、紐付けが可能となりますので、参考にしてください。 2007-01-10T23:59:59+09:00 captchaの作成方法(マルチバイト版) http://php.to/tips/8/ 前章のcaptchaの作成方法でGDを用いたcaptchaのサンプルを作成しました。 しかし、最近のBOTNET(ロボットの略。自動で情報を収集するプログラムなどです)はOCR機能を用いて、画像の文字列でさえ認識して突破してくることもあります。 そこで、日本語のcaptchaを作成してみました。 日本語の文字列を画像で出力するためには、imagettftext()関数と日本語のTrueTypeフォントが必要です。 imagettftext()関数を使うためには、あらかじめFreeTypeのインストールが必要ですので、もし入っていない場合はインストールしてください。 (必ずFreeType→PHPの順番で入れないといけません。もし先にPHPをインストールした場合は、make cleanしてからconfigureしてください) また、フォントに関しても、ライセンス的に問題がないものを使う必要があります。 今回はM+ と IPAフォントの合成フォントのアーカイブに含まれている、IPAフォントを使用することにしました。 さて、実行してみたら分かりますが、問題なく日本語(ひらがな)でcaptchaが動いています。 こんなかんじです。 ソースを見てみれば分かりますが、前章のcapthcaとほとんどソースは変わっていませんので、簡単だと思います。 また、この方式のソースですと漢字も問題なく使えます。サンプルとして、小学校1年生で習う漢字のcapthcaも作ってみましたので、よかったら使ってみてください。内容は、ひらがなの部分を漢字にしただけですので、誰でも簡単に改変可能です。 こちらはこんなかんじです。 これで、少なくとも日本語が読めて日本語が入力できる環境以外からのアクセスは排除することができると思います。 2006-12-11T23:59:59+09:00 captchaの作成方法 http://php.to/tips/7/ 「captcha」と言ったところで、分かる人は少ないかもしれません。 そこで、「画像認証」とでも言えば、「ああ、あれか」と思っていただける方が多いのではないかと思います。 そう、こんなのですね。 例えば、Googleのサイトの登録などで使われている、ランダムな文字列を表示し、かつ、それに対して適当なノイズを入れたり、歪ませるなどして画像を自動識別しにくくし、「操作している側が人間かどうか」を判定するために使われる技術です。 (詳しくは、WikipediaのCaptchaの項をご覧ください) PHP用のモジュールとして、PEAR::TextのText_Captchaで公開されているようですが、環境に依存するつくりになっていることと、多くのcaptchaはセッションを使っていることが多いため、cookieを使えない環境のためにセッションを使わないで再現できるcaptchaを作成してみました。(需要があるかどうかは謎ですが…) あえてポイントを挙げるなら、あえて一定のアルゴリズムで算出したキーを乱数の種(random seed)とすることで、入力値が同じであれば、作成される文字列を固定させています。 ただし、キーが単一にならないよう、下記のロジックを組み込んであります。  1. 通常は一般閲覧者には非公開である(と思われる) 環境変数を用いて、環境に依存した値を加えたものにMD5演算を行い、キー値を算出するようにしている  2. キーの算出時に日時情報を含めることにし、かつ、この日時情報を元に、画像の有効期間を一定期間のみとさせ、ブルートフォース対策としている 難しくはないので、詳しくはソースを読んでください。 (実行にはGDおよびJPEG/PNGライブラリのインストールが必要です) 2006-12-01T23:59:59+09:00 ファイルを添付してメールを送信する方法 http://php.to/tips/6/ 例えば、問い合わせフォームやダウンロードフォームなどのシステム側から、画像ファイルや圧縮ファイルなどを添付したメールを送信したいことがあります。 その際は、PEAR の Mail_Mime パッケージを使うのが常套手段です。 その他にもGoogleなどで検索すると、PHPの添付メール用クラスを自作されているサイトがいくつか引っかかりますが、いずれもかなり高度なことができるため、コードが比較的長めになっています。 メールを送るだけならもっとシンプルに作成できますので、ここでは自分で機能追加したい場合などのことを想定して、簡単なものを作成してみました。 なお、メールヘッダなど、ある程度SMTPプロトコルの知識があることを想定しています。 例えば、CCを利用したい場合などは、CC: CC-mail-address@example.com などの行を $additional-header に追加してください。 また、ここではコードを短くするため、MIME-typeの取得にfinfo_file()関数を使っていますが、この代わりに自作関数などを利用することも可能です。 詳しくは、0005. MIME-typeを定義する方法をご覧ください。 2006-11-08T23:59:59+09:00 MIME-typeを定義する方法 http://php.to/tips/5/ アップロードされたファイルの形式をPHPで判定したり、ファイルをダウンロードまたはメールに添付して送信する際のContent-Typeのために、MIME-typeの定義を行うことは欠かせません。 ファイルアップロードの際は、基本的に連想配列 $_FILES['変数名']['type'] の中に自動的に入ってくれるので、あまり気にする必要はありません。 問題はダウンロードなどのときで、このときはダウンロードさせるファイルに合った形式のMIME-typeをContent-Typeヘッダとともに返してやる必要があります。 このMIME-typeをPHPで定義する方法は下記のように、いくつか存在します。 PEARのFileinfoパッケージを用いる方法 mime_content_type()関数を使う方法 自力でファイル名の拡張子に応じて判定する方法 それぞれの利点・欠点などを説明します。 1. PECLのFileinfoパッケージを用いる方法FileinfoパッケージはPECLによる同パッケージのインストールが必要です。 (PHPマニュアルにはPEARとなっていますが、実際にはPECLです) 同パッケージがインストールされている、またはインストールできる環境であるなら、最も簡単にfinfo_file()を用いてMIME-typeを得ることができます。 なお、このパッケージは内部で libmagic を呼んでいるだけです。同パッケージのインストール後は、コンパイルされたモジュールをphp.iniでextention = /path/to/fileinfo.so のように指定するか、動的にロードする必要があります。 具体的な使用方法は、0006. ファイルを添付してメールを送信する方法を参照してください。 この関数で検出できるMIME-typeは「確実」ではありませんが、多くのファイル形式を含んだデータベースファイルの中から特定のバイナリ文字列をサーチして判定しており、後に述べる2つの形式に比べて、遥かに高い精度での自動検出が可能です。 詳細は、O'REILLY JAPANから発行されている「BINARY HACKS」などの文献を参考にしてください。 2. mime_content_type()関数を使う方法mime_content_type()関数を使う場合は、PHPのconfigure時に --with-mime-magic オプションの追加が必要であり、Windows環境やApache以外のhttpdを使っている場合は、php.ini内の mime_magic.magicfile ディレクティブに maginc.mime ファイルへのpathが必要です。 この関数はApacheの設定ファイルの一つである mime.typesファイル (またはMimeMagicFileディレクティブで定義されたファイル) を利用してMIME-typeの自動判定を行います。 特定のバージョンでしか使用できず、将来的に廃止予定の関数であるのに加え、ここに定義されていないファイル形式はFileinfoパッケージのように自力でバイナリ構造を調べて設定ファイルに追記する必要があるので、まず使うことはないでしょう。 3. 自力でファイル名の拡張子に応じて判定する方法自力でファイル名の拡張子から判定する方法としては、例えば下記のようなコードで実現することができます。 ただし、これはあくまでファイル名の拡張子を元に単純な判定を行っているだけですので、前述の2つの判定方式に比べて確実性は大きく劣ります。 前述の2つの方式が使えない環境でのみ使用すべきでしょう。 なお、特にMIME-typeの指定は必要ないがダウンロードだけはさせたい場合などでは、単純に Content-Type: application/octet-stream と指定するのが最も実用的です。 これは、「ファイルの形式は分からないものの、中身はバイナリである」という意味になりますので、通常のブラウザであれば勝手にMIME-typeに紐付けられたアプリケーションが起動することなく、ダウンロードダイアログを開いてくれます。 (MS-Officeなどが入っている環境では、MIME-typeを無視してダウンロードする拡張子に応じて勝手に起動したりすることがあるようなので、この限りではありませんが・・・) 2006-11-08T23:59:59+09:00 一括して入力パラメータのサニタイジングを行う方法 http://php.to/tips/4/ セキュリティを考慮すると htmlspecialchars() や strip_tags() などを用いて、入力値のサニタイジングを行うことと思いますが、面倒なので下記のように再帰処理を用いて一括してサニタイジングを行い、以後はそちらで各種処理を行うような癖をつけると後が楽です。 ただし、文字長チェックなどでサニタイズ前の変数を使いたくなることもあるので、オリジナルの元の値も残しておき、適時使い分けましょう。 2006-11-02T23:59:59+09:00 セキュリティを考慮して、特定の関数を使用不可能にする方法 http://php.to/tips/3/ これは普通にPHPのマニュアルに載っているのですが、知らない人が結構多かったので公開します。 PHPの設定ファイルである、php.iniファイルを開き、下記のように指定します。 disable_functions = 使用不可にしたい関数1, 使用不可にしたい関数2, 使用不可にしたい関数3 ... 例えば下記のように設定すれば、メール送信関連の関数を使用不可にできます。 「セーフモードでは厳しすぎる」というレンタルサーバ用途や、PHPの特定の関数に脆弱性が見つかって一時的にその関数を使えなくしたいときなどにいいかもしれません。 disable_functions = mail, mb_send_mail 2006-11-02T23:59:59+09:00 正規表現を用いて、外部テンプレートファイルにダイレクトに変数を埋め込む方法 http://php.to/tips/2/ Webアプリケーションにおいて、稼動後にちょっとした文面の変更が発生することは結構あります。 こういったケースのため、ロジックとデザインの分離するために Smartyなどのテンプレートエンジンを用いるケースも多々あると思いますが、例えばECサイトのシステムでお客が商品を購入した際にシステムから送信する確認用メールの文面を変更したい場合など、HTML以外の用途のものにSmartyなどを導入するのも大仰です。 テンプレートエンジンなどを用いずに、直接コードの中に文面を挿入しているケースも巷でよく見かけますが、その際にPHPの知識のない運営担当者がプログラムの動作に影響する部分を書き換えてしまう可能性を考慮すると、あまり上手いやり方ではありません。(実際問題、こういう実装をしてトラブルが起こっているケースがよくあるようです) そこで今回は、PHPの知識のない運営担当者でも変数の埋め込みができるなど、柔軟な方式な対応が出来る、簡単なサンプルを紹介します。 この方式を使えば、プログラムを直接メンテナンスする必要がなくなり、運営担当者はテンプレートファイル(テキストファイル)のメンテナンスをするだけで良くなります。 これは実際、私が複数のシステムに導入してきたものなので、[余計な情報を埋め込まない]という点のみきちんと配慮しながら使えば、かなり利便性が高いことを実感してもらえることでしょう。 簡単に説明すると、preg_match 関数を使って、変数のバインド対象となるフォーマット(下記のサンプルでは{%変数名})とマッチした場合、str_replace() 関数を通して変数に置換するというものです。 似たようなことは eval() 関数でも出来ますが、変数の置換のみに制限される分、安全です。 関数化するときは連想配列に入れた後にextract()するなどの工夫を凝らしてください。 2006-11-01T23:59:59+09:00 PHP4で1970年1月1日以前のデータをtime関数互換のinteger型で扱う方法 http://php.to/tips/1/ 通常であれば、PHP4で時刻関連の処理を行うには、UNIXエポック時間(1970/01/01 00:00:00 GMT)からの通算秒数を返す time() 関数を用います。 この関数で取得できる値(time_t型とも言います)を用いると、閏年の計算などを考慮しなくても、秒単位で簡単に日時計算を行うことが可能になります。 ただし、これは内部的には32bitのsigned int型であるため、1970/01/01 00:00:00 GMT(内部的には0)〜2038/01/19 03:14:07 GMT(内部的には231-1)の間の日時しか扱えないという制限があります。 そこで、誕生日の入力のために1969年以前の日時を扱う必要があるときや、スケジューラのために2038/01/20以降の日時を扱いたい際に、どのように扱えばよいかということが焦点になります。(参考:2038年問題) 最も簡単な方法は、ADOdbライブラリの中に含まれているadodb-time.inc.phpを include() して使うことです。 ADOdbライブラリ内の日時関数は 64bit int型(float型)で処理するように作成されていますので、ほぼPHPの時刻関数と同じ書式で、紀元前や西暦3000年などの日時を扱うことが出来ます。 ※PHP5.1以降では、time()関数も64bit intでの表現が可能になっていますので、ADOdbライブラリを使う必要はありません 2006-11-01T23:59:59+09:00