PHPプロ!TIPS+

1. PEAR::Text_Highlighterでソースコードに色づけ

ソースコードをWebサイト上で表示したいときなど、シンタックスに色を付けて見やすく表示したいと思ったりしませんか?短いソースコードならば自分の手でHTMLの要素を駆使し行っても良いかもしれませんが、長いものになるとそう簡単にはいきません。PHPにはそれを簡単に実現するための方法がいくつか用意されています。今回はその中からPEAR::Text_Highlighterを紹介したいと思います。ソースコードの中のシンタックスに色を付ける方法としてPHPにはhighlight_string()という関数があります。この関数を使用しても色を付けることはできるのですが、PHP4ではHTMLのfont要素を用いて、PHP5の場合はstyle属 性を用いて色づけが行われたり、対象ソースコードがPHPだけだったりと、なかなか自由がききません。しかし、今回紹介するPEAR::Text_Highlighterを使うとそれらの不満が解消され、さらに行番号を表示するといったこともできます。では、早速使ってみましょう。

このPEAR::Text_Highlighterはまだベータということで

pear install Text_Highlighter-beta

で、インストールします。以下のソースコードをhighlighter.phpというファイル名で保存して実行してみてください。

<style type="text/css">
.hl-main {font-family: monospace;}
.hl-default { color: #000000; }
.hl-code { color: #7f7f33; }
.hl-brackets { color: #009966; }
.hl-comment { color: #7F7F7F; }
.hl-quotes { color: #00007F; }
.hl-string { color: #7F0000; }
.hl-identifier { color: #000000; }
.hl-reserved { color: #7F007F; }
.hl-inlinedoc { color: #0000FF; }
.hl-var { color: #0066FF; }
.hl-url { color: #FF0000; }
.hl-special { color: #0000FF; }
.hl-number { color: #007F00; }
.hl-inlinetags { color: #FF0000; }
</style>
<?php
require_once "Text/Highlighter.php";
require_once 
"Text/Highlighter/Renderer/Html.php";

$renderer = new Text_Highlighter_Renderer_Html(array("numbers" =>
HL_NUMBERS_LI"tabsize" => 4));

$hlHtml =& Text_Highlighter::factory("PHP");
$hlHtml->setRenderer($renderer);
$local_data file_get_contents("./highlighter.php");
echo 
$hlHtml->highlight($local_data);
?>

シンタックスに色が付き、且つ左側には行番号が表示されていると思います。

処理の流れを説明すると、まず、Text_Highlighter_Renderer_Htmlのインスタンスを作成します。このときオプションとして行番号の形式(numbers)とタブの幅(tabsize)を指定しています。行番号の形式にはHL_NUMBERS_LIとHL_NUMBERS_OI、HL_NUMBERS_TABLEの三種類があり、それぞれ行番号を表示、行番号なし、HTMLのtable要素を用いて行番号を表示、となっています。

次に色づけを行う対象のソースコードの形式は何なのか、Text_Highlighterのサブクラスを使ってその形式に応じたオブジェクトを作成します。今回はPHPのソースコードに対して色づけを行うので、引数に"PHP"と指定しています。ちなみに、このPEAR::Text_Highlighterでサポートしている形式は、現在C++、CSS、diff、DTD、HTML、Java、Javascript、MySQL、Perl、PHP、Python、Ruby、SQL、XMLです。

あとはPHPのソースコードを読み込んで表示するだけになります。PEAR::Text_Highlighterでは各シンタックスに対してCSSのクラスを使って色づけを行うので、CSSを書く必要があります。この部分がちょっと大変かもしれませんが、様々な形式に対して色づけを行うことができ、行番号や色のカスタマイズといったことが簡単にできます。興味のある方は使ってみてはいかがでしょうか。

PEAR::Text_Highlighter : http://pear.php.net/package/Text_Highlighter/

2. eAcceleratorでスピードアップ

今回は、PHPの処理速度を簡単に上げることができるモジュール、eAcceleratorをご紹介します。eAcceleratorはスクリプトを最適化しコンパイルされた状態でキャッシュすることで、スクリプト実行速度を飛躍的に上昇させます。(付属の説明によると最大 10倍!)では、早速インストール手順を説明します。

apache1.3以上、mod_php4.1以上、autoconf、automake、libtool、m4が必要ですが、大抵の環境では条件を満たしていると思います。万が一足りないものがあったらインストールして下さい。なお、CGIモードのPHPではeAcceleratorを使うことはできません。

1.ソースの入手、解凍、展開

http://sourceforge.net/projects/eaccelerator/からソースコードをダウンロードします。現在の最新版はバージョン0.9.5です。(2006/10/31現在)ダウンロードしたら、適当な場所(例えば/usr/local/srcなど)に移して解凍、展開します。

2.configure、make、make install

次に、展開したディレクトリに移動して、以下のようにconfigure、makeを実行します。以下のexportコマンドはbashで、PHPが/usrにインストールされている場合です。環境に合わせて適宜変更して下さい。

export PHP_PREFIX="/usr"

$PHP_PREFIX/bin/phpize
./configure --enable-eaccelerator=shared \
--with-php-config=$PHP_PREFIX/bin/php-config
make
sudo make install

3.インストール後の設定

インストールができたら、設定を行います。通常はphp.iniに設定を追加します。/etc/php.dがある場合は、eaccelerator.iniをコピーし、必要に応じて編集します。

eAcceleratorはZend、PHPどちらのエクステンションとしてもインストールできます。 ここではPHPのエクステンションとしての設定例を紹介します。以下の記述をphp.iniに追加します。

extension="eaccelerator.so"
eaccelerator.shm_size="16"
eaccelerator.cache_dir="/tmp/eaccelerator"
eaccelerator.enable="1"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="1"
eaccelerator.debug="0"
eaccelerator.filter=""
eaccelerator.shm_max="0"
eaccelerator.shm_ttl="0"
eaccelerator.shm_prune_period="0"
eaccelerator.shm_only="0"
eaccelerator.compress="1"
eaccelerator.compress_level="9"

eaccelerator.cache_dirで指定したディレクトリにキャッシュが保存されます。このディレクトリは予め作っておく必要があります。

mkdir /tmp/eaccelerator
chmod 0777 /tmp/eaccelerator

4.動作確認

設定できたら、apacheを再起動して実際にeAcceleratorが動いているか確認します。確認する方法はいろいろあります(phpinfo()を見てみる、デバッグモードにしてログの確認など)が、今回は先ほど作ったキャッシュ用のディレクトリを見てみましょう。 ディレクトリ内に更に階層のディレクトリが作成されていて、キャッシュデータが作られているのが確認できるはずです。

以上で完了です。これだけでスピードアップできるので、興味のある方はぜひ試してみて下さい。

最後に、本当のところどれくらい速度が上がるのか、手近なスクリプトで試した結果を紹介しておきます。テストにはapacheに付属しているベンチマークプログラム、abを使用し、接続数1000、同時接続数10で実験しました。abは

ab -n 1000 -c 10 http://hogehoge.com/index.php

のように使います。

また、試したのは自作のプログラム2つです。両方ともテンプレートエンジンにSmartyを使用しており、データベースから持ってきたデータを一覧で表示するプログラムです。 1つ目のプログラムにはforeachなどで合計数千回のループ処理を行っています。(2つ目は20回くらい)以下、結果の一部です。

1つ目のプログラム eAcceleratorなし

Time taken for tests:   122.555273 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      180828000 bytes
HTML transferred:       180444000 bytes
Requests per second:    8.16 [#/sec] (mean)
Time per request:       1225.553 [ms] (mean)
Time per request:       122.555 [ms] (mean, across all concurrent requests)
Transfer rate:          1440.89 [Kbytes/sec] received

1つ目のプログラム eAcceleratorあり

Time taken for tests:   84.62285 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      180828000 bytes
HTML transferred:       180444000 bytes
Requests per second:    11.90 [#/sec] (mean)
Time per request:       840.623 [ms] (mean)
Time per request:       84.062 [ms] (mean, across all concurrent requests)
Transfer rate:          2100.69 [Kbytes/sec] received

2つ目のプログラム eAcceleratorなし

Time taken for tests:   51.725834 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      7345000 bytes
HTML transferred:       6939000 bytes
Requests per second:    19.33 [#/sec] (mean)
Time per request:       517.258 [ms] (mean)
Time per request:       51.726 [ms] (mean, across all concurrent requests)
Transfer rate:          138.65 [Kbytes/sec] received

2つ目のプログラム eAcceleratorあり

Time taken for tests:   25.616275 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      7345000 bytes
HTML transferred:       6939000 bytes
Requests per second:    39.04 [#/sec] (mean)
Time per request:       256.163 [ms] (mean)
Time per request:       25.616 [ms] (mean, across all concurrent requests)
Transfer rate:          279.98 [Kbytes/sec] received

Requests per secondの値が一秒あたりの処理数で一番分かりやすいと思います。

1つ目のプログラムでは、

8.16 → 11.90 (約1.46倍)

2つ目のプログラムでは

19.33 → 39.04 (約2.02倍)

と、確かに早くなっていることが確認できました。

3. CURLのセッションを引き継ぐ方法

WebサイトのHTML情報を取得する際にcurlを使用することがあります。curlとはWebブラウザのコマンドライン版のようなもので、与えられたコマンドを元にページ情報を取得する機能です。curlを使用すれば、ログインフォームにPOSTでデータを渡してログイン 処理を行い、ログイン後のページ情報を取得するようなことも可能です。ですが、ログイン処理を行った後、ログイン後にしか行けないような別のページの情報を取得しようとすると、セッションが引き継げずHTMLが取得できない場合があります。今回はそのような場合に対処する方法をお教えします。

まずは、curlを使用してログイン処理を行い、ログイン後のページを表示するスクリプトです。ここではPHPプロ!にログインする処理を記述しています。

<?php
    $params 
array(
        
"login-name" => "name",
        
"login-pass" => "pass"
        "submit"         
=> "ログイン",
    );

  
$ch curl_init("http://www.phppro.jp/members/login.php");
  
curl_setopt($chCURLOPT_RETURNTRANSFER1);
  
curl_setopt($chCURLOPT_FOLLOWLOCATION1);
  
curl_setopt($chCURLOPT_POSTTRUE);
  
curl_setopt($chCURLOPT_POSTFIELDS$params);
  
$output curl_exec($ch);
  
curl_close($ch);

  print 
$output;
?>

これが成功すると、ログイン後のページが出力されるはずです。「PHPプロ!」メンバーページへようこそ! の文字が表示されていると思います。

それでは次は、ログイン後に別のページに遷移し、そのページのHTMLを取得するスクリプトを書いて見ましょう。ここではPHPプロ!にログイン後にポイント使用履歴のページを取得するスクリプトを作成しています。

<?php
  $params 
array(
    
"login-name" => 'nakamuraya',
    
"login-password" => 'gerogero',
    
"submit"  => "ログイン"
  
);

  
$fp fopen("tmp""w");
  
$ch curl_init("http://www.phppro.jp/members/login.php");
  
curl_setopt($chCURLOPT_RETURNTRANSFER1);
  
curl_setopt($chCURLOPT_FOLLOWLOCATION1);
  
curl_setopt($chCURLOPT_COOKIEJAR"cookie");
  
curl_setopt($chCURLOPT_POSTTRUE);
  
curl_setopt($chCURLOPT_POSTFIELDS$params);
  
curl_setopt($chCURLOPT_WRITEHEADER$fp);  $
  
output curl_exec($ch);
  
fclose($fp);  curl_close($ch);
  print 
"CURL OUTPUT:\n{$output}\n";

  
$ch curl_init("http://www.phppro.jp/members/history.php");
  
curl_setopt($chCURLOPT_RETURNTRANSFER1);
  
curl_setopt($chCURLOPT_FOLLOWLOCATION1);
  
curl_setopt($chCURLOPT_COOKIEJAR"cookie");
  
curl_setopt($chCURLOPT_COOKIEFILE"tmp");
  
curl_setopt($chCURLOPT_POSTTRUE);
  
$output curl_exec($ch);
  
print_r(curl_getinfo($ch));
  
curl_close($ch);
  print 
"CURL OUTPUT:\n{$output}\n";

?>

このスクリプトでは、COOKIE情報を tmp というファイルに保存して引き継いで います。成功すると、ログイン後のページに続いてポイント使用履歴のページが表示され るはずです。使えるワザですのでぜひ一度試してみてください。

バックナンバーについて

TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。

Tipsꗗy[W 

Pick Up Q&A

Q
array_mergeの再帰処理の動作について
 このエントリーをはてなブックマークに追加 
A
>1個になったとき$leftを返しますが、 >このとき、最終的な$leftはnullになるかと思います。 いいえ、最後は「渡された配列をそのまま」返します。要素が2以上あるときとの違いは(並べ替えずに戻るので...

>>続きを読む

再帰関数は最初の内は混乱しますが、非常に上手く使える場面もいずれ出てきます。これを機会に学んでいけるといいですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)