伊藤清徳の垂直落下式ムーンサルトプレス

PerlとかPHPとかMySQLとか...がんばっても8割だ。

Category: PHP (page 2 of 5)

PHPをEXEにコンパイル

PHPをWindowsのアプリケーション .exeにコンパイルするっていう話。

5年ほど前PHPがまだ4系全盛だった頃に一回やったことがあったのだが、
今回、再びやらなければならないことが出てきたので、調べた結果をあげておく。


まず、PHPという言語をWindowsで扱う際、
いいことは、基本的には、Windowsだからといって、
よほど複雑なことをしない限りは、
LinuxやBSD系とそれほど変わらない感覚で使える点。
他のインタプリタで言えば、
Perlをよく使うのだが、Perlなどはファイル名に日本語が入る可能性がある場合などは、
別個にモジュールをロードしてくる必要がある、
よく使うよなと思うモジュールがWindows用にコンパイルされたバイナリがない
など骨が折れることもおおいけれど、
PHPならよほど変なことをしなければ、
php.iniをいじるなどでどうにかできる。

ただし、IronRubyとかには負けちゃうけどね…
 
ま、とにかく、なんだかんだ言われながらもよく使う言語であるPHPで
さくっと小さなアプリが作れるのは楽だ。


5年ほど前に、日本でよく紹介されていた、
PHPを.exeにコンパイルするツールは
http://www.bambalam.se/bamcompile/
これ。
当時使ってみたが、まぁ特に問題もなく。
EXEができた記憶がある。
開発が止まっていて、使えるバージョンはPHP4.4.4。
小さなバッチを書くには十分かなと。

でも、せっかくなら、PHP5で書きたいよなーって調べていたら、あった。
しかも日本人が作ってたのが、、、
これだ

1…
2…
3…
http://hirata-create.cocolog-nifty.com/blog/HC-Standalone-B.html

コンパイルツールがGUIで用意されているのが楽。
これを使えば、WindowsGUIアプリも作れる。
使われているPHPのバージョンは5.3.8。
こういったプロジェクトは、放棄される可能性が高いが、
メンテも頻繁に行われいるようで、いいねいいね


PHPをexeにする仕組みは、

  1. PHPをバイトコードにコンパイルする
  2. windowsのexeファイルを作るプロジェクトの中にバイトコードとPHPのコアであるphp.dllを内包する
  3. コンパイル
  4. 実行時、exeファイルのリソースのなかで、PHPのコードをdllに読ませる

という仕組みでできているようだ。
http://www.sukikamo.jp/users/norihiro/programming/20111104.html
▲参考

つまり、ランタイムとコードをまるごとexeの中に入れちゃってるっていう仕組みである。


上記の、ひらたクリエイトさんのツールの場合、
php.dllを独自にカスタマイズしたものを使っているようで、
それに合わせて、PHPのモジュールも独自のものを使わなくてはならないようだ。
PHPの全資産がそのままつかえるわけではないのがちょっとぐぬぬとなる点である。
(他のコンパイルツールは、同バージョンのPHPのエクステンションdllがそのまま使えるものが多い)


exeにコンパイルした場合の注意点としては、
前述のような、リソースのなかにすべてのものを同梱して
インタプリタに解釈させるという仕組みから、
たとえば、テキストファイルを相対パスで指定したりする場合には、
インタプリタから見たパスの場所がずれるため、
通常どおりのパスが指定できない点を注意する。

この解決方法はRES://というURLスキーマを利用する。

$file = '../data/data.txt';
$usage_path  =  'res:///PHP/' . strtoupper(md5($file));

このように書くと、php.dllから見た相対パスが取得できる。

この点を注意すればあとは通常どおりのPHPでWindowsアプリケーションが作れる。


これまで、PHPの他、Perlやなでしこなどを使ってexeファイルを作ってきたが、
速度の面ではPHPが圧倒的に早いようだ。
今後も使ってみようと思う。


追伸。
Perlをexeにする場合は、
http://www.activestate.com/perl-dev-kit
を使うとできる。
なんと、こいつ、PerlをCOM用のDLLを作ることもできるのだが、
仕組みがわかったので、PHPでもDLLつくれるんじゃねぇの?ということに気づいたため、
今度作ってみようと思う。多分誰も得しないが。。。

PHPのodbc関数はデフォルトではLONG*型は取得できない

PHPのODBC関数でドハマりしたのでメモ
表題の通りPHPのodbc関数では、LONG◯◯型の値を全て取得できない。
たとえば、LONG VARCHAR型は VARCHAR型のサイズに縮められて返される。


php.iniまたは関数でLONG*型の取得が可能になる。
他の設定と例に違わず、php.iniのほうが優先される場合もあるので注意。

関数を利用する場合、odbc接続の前に

odbc_binmode(0, 1); 
odbc_longreadlen(0, 0); 

を渡しておけばOK。これで、ダメな場合は、php.iniの設定を変えます。

odbc.defaultlrl = 0
odbc.defaultbunmode = 0

このようにします。

このあたりはちゃんと調整しないと、
レスポンスに影響が出るようです。


【修正】
php.iniを

odbc.defaultlrl = 0
odbc.defaultbunmode = 0

のようにしていると、接続先データソースのタイプによっては、
INT型などの数値型がNULL or 0の数値によるBooleanに変更されてしまうことがあるようです。
出力してみて、おかしいようならば

odbc.defaultlrl = 4096
odbc.defaultbunmode = 2

とします。
defaultlrlはLONG*型を読み込む最大長(バイト)になるので、
データソースに合わせて変更してください。
odbc.defaultbunmodeは2を指定すると、
全ての値をchar型として処理します。
したがって、BLOB型を扱うような場合は、設定に注意をしてください。

楽天レビューを無茶して取得

楽天APIからレビューを取得することができないので、
PHPで楽天のレビューを取得する方法を書いておきます。

具体的にはHTMLをパースして、
必要なデータを引っこ抜いてくるという仕組みです。


正規表現がめんどくさいので、phpqueryを使います。
http://code.google.com/p/phpquery/
phpqueryはjqueryライクな書き方で、HTMLのパースができる便利なライブラリ。
比較的低いバージョンのPHPでも動くところがいい。
動作テスト環境はPHP.5.1.6です。
 


【実戦投入への注意点】

  • 楽天へのアクセスはfile_get_contentsで書いてますが、実戦投入の際は、curl関数などを使ったほうがいいですね
  • 表示させようとする度に、phpqueryで解析するのは重いので、なんだかのキャッシュ機能はつけたほうがいいですね

		require_once( 'phpQuery.php' );
		
		//レビューページ取得
		$url = '楽天のレビューページのURL';
		$code = file_get_contents($url);
		
		//UTF-8に変換したうえで、phpqueryのインスタンスを「EUC-JP」指定で作成
		$code = mb_convert_encoding( $code, 'UTF-8', 'EUC-JP' );
		$doc = phpQuery::newDocumentHTML( $code, 'EUC-JP' );
		
		
		$list = array();
		$i = 0;
		$cnt = $doc['#reviewList .summary']->length();
		while( $i < $cnt )
		{
			$list[$i] = array();
			
			//ポイント
			$list[$i]['point'] = $doc['#reviewList .summary:eq(' . $i . ') .description .title span.eval']->html();
			
			//日付
			$list[$i]['date'] = $doc['#reviewList .summary:eq(' . $i . ') .description .date']->html();
			
			//名前
			$names = explode(
					mb_convert_encoding( 'さん', 'EUC-JP', 'UTF-8'),
					$doc['#reviewList .summary:eq(' . $i . ') dl:eq(0) dt a']->html()
			);
			$list[$i]['name'] = $names[0];
			
			//タイトル
			$list[$i]['title'] = $doc['#reviewList .summary:eq(' . $i . ') .description .reviewtitle .reviewTitle']->html();
			
			//中身
			$list[$i]['text'] = $doc['#reviewList .summary:eq(' . $i . ') .description .text']->html();
			
			$i ++ ;
		}
		
		//ここにポイント日付名前タイトル評価文がリストされる。
		var_dump( $list );

 
ざくっとこんな感じ。
名前のところは余計な情報もくっついてくるので
「さん」のところで分割して名前だけ持ってくるようにする。

phpquery便利。

CodeigniterでFileMakerをごにょごにょする

ライセンス関連でごにゃごにゃもめとるCodeigniter(以下CIと略す)ですけど、
まぁ基本商用においては問題なさそうなので、
仕事では引き続き使っている案件もあります。

なんだかんだ、CIは高速で便利なPHPフレームワークです。
2.0以降CLIからの実行も考慮されていて
http://codeigniter.jp/user_guide_ja/general/cli.html
ローカルアプリケーションを作るのにおいても、結構活躍してくれます。

PHPでFileMakerへODBC接続して、データを取得してこなければならない仕事があるので、
CIでどうにかならんかなと思ってやってみた次第。

結論

$db['default']['hostname'] = 'Driver=FileMaker ODBC;Host=localhost;PRT=2399;database=データベース名;UID=ユーザーID;PWD=パスワード;';
$db['default']['username'] = '';
$db['default']['password'] = '';
$db['default']['database'] = '';
$db['default']['dbdriver'] = 'odbc';
$db['default']['dbprefix'] = '';
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = '';
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_general_ci';
$db['default']['swap_pre'] = '';
$db['default']['autoinit'] = TRUE;
$db['default']['stricton'] = FALSE;

これで接続できます。
で、

上記のCLIからのCIの利用を参考に

php index.php controller_name method_name

これで起動できます。

FileMakerからはpetaexecuteプラグインなどを利用すれば標準出力を取得できるので、なかなか面白いアプリケーションがつくれそうです。

なんども私のブログで出てきましたが、FileMakerで利用できるSQLは、SQL標準に従ってない部分もあります。
したがってSQLを実行する際は、ActiveRecordは使わずにSQL直書きする方が無難でしょう。

Smartyで $obj->method()を実行してみる覚書

smartyで

$obj->method()

を呼べるのかと思って

{$obj->method()}

と書いたら普通に実行できた。


 
たとえばMVCなフレームワークでSmartyを実行しているとき、
コントローラーに

public function test()
{
    return 'テスト';
}

というメソッドを作っておく。
で、Smartyにコントローラーオブジェクトを渡しておいて、
($controllerにその参照が渡っているものとする)

{$controller->test()}

と記述すればコントローラーのメソッド「test」が実行され、
「テスト」と出力される。

返り値がHTMLとして出力されるようだ。

引数も問題なく渡せた。


 
が引数には落とし穴があった。

{$obj->method( 'test', 'test2' )}

などとすると、エラーが起きる。
引数中にかっこがあるとパースエラーが起きるらしい。
可読性は低くなるが、

{$obj->method('test','test2')}

と記述する必要がある。
 
まぁ、そもそもViewにそんなもん書いていいもんかという話だが、
便利なので、覚書。

PHPでレコメンドエンジン

レコメンデーション

ECサイトなどでは、レコメンデーションを実装するのが、普通になってます。
個人的には、サイト回遊率が上がるけど、
コンバージョンのための終着ポイントを明示するのが少し難しくなるので、
商材などにより入れていい場合とそうでない場合があるなと思ってますが、
使いどころは多いので調べてみました。


よくあるのは、ASP提供型のサービスですね。
有名なのはこのへんですかね▼
http://recommend.submit.ne.jp/
 
あとこの会社の社長を知っているのですが、なかなか熱い方で、いいですよ!
http://www.otegaru-recommend.com/


とはいえ、このへんは月額数千円かかります。
売上100万円程度のお店に導入するには、5000円でも結構な額です。
(個人的には売上200万円程度いかないと、総合的には赤字路線だとは思いますが)
 
ということで、オープンソースで自社導入出来る仕組みがないかしらべたところ、
実用レベルで2つありました。

cicindela http://labs.edge.jp/cicindela/
vogoo http://sourceforge.net/projects/vogoo/
 
前者はライブドアが開発したレコメンドエンジンで、
汎用エンジンとしてはかなり強力なエンジンですが、
それだけ導入するには、ハードルは高くなります。

後者は、アプリケーション自体がPHPのライブラリとして動いてくれるものですが、
解析パターンがひとつしかありません。

導入障壁が低いほうがいいので、今回は、後者を利用しました。
「Vogoo」←なんて読むかわかりません(汗


残念なことに開発はすでに終了しているようで、メンテなども行われず、
インストールはMySQL4前提です。でも、普通にMySQL5でも動いています。

調べるとすでに使われている方がいますね。
http://blog.y-110.net/log/eid130.html
http://www.multiburst.net/sometime-php/2009/02/recommendation-engine-vogoo-with-php/
http://labs.unoh.net/2006/04/_vogoo.html
http://www.atyks.org/blog/2011-07-06-1.html
・・・古い記事は、2006年かぁ・・・


 
インストールはインストーラーを走らせて、
vogooのインストールディレクトリをinclude_pathに追加、
あとは、
http://www.atyks.org/blog/2011-07-06-1.html
http://blog.y-110.net/log/eid130.html
この2つの記事の内容を参考にすれば、実装できます。
(レコメンデーションの仕組みをだいたいわかって人ならという前提ですが)

いただけないことにグローバル変数を利用してるのがアレですが…。

あと、サイト内回遊をポイント評価することで、
似た回遊パターンや購入パターンの人を探して、
おすすめするという仕組みでうごいていますが、
デフォルトで0.66ポイント以上のものだけを結果として返すようになっています。
これは、実装の仕方によっては、
まったく結果が得られない可能性もあります。
ポイント評価の方法や、取得評点の閾値は
サイトにあわせて自分で考えたほうが良いと思います。


実は、協調フィルタリングパターンのレコメンデーションは、
5年前にPerlで作ってたのですが、繰り返しPCを変えてるうちに、
元データがどっかにいってしまいました。。。
当時バージョン管理システムを作らずに開発していたせいですね。。。はぁ。。。

PHPカンファレンス関西に行ってきました。

4月2日にPHPカンファレンス関西に行ってきました。
大阪ですよ。大阪。
いつも梅田駅で迷う、小名古屋人の私にとっては、
どきどきの出発でしたが、それほど道のりは遠くなくて良かったです。


なぜ、PHPerではない(と言い張っているだけ)の私がわざわざ大阪に行ったかといいますと、
前の記事に書きましたUst番組『バニトーク』に出てやるぜ!っていうのと、
Twitterで仲良くさせていただいている、
@yat8823jpさん(以下、YATさん)、
@alphabet_hさん(以下、こしあんさん)
に会えるぜ!っていうのでした。


YATさんはECに携わってらっしゃるということで、
Twitterでもマインドを同じくしているので、
開場前に早めにお会いして、色々話をしましたが、
いいですね!適度な熱さと冷静さをもっている方でした。

そして、こしあんさんは、
まっすぐにPHPやらJSやらの言語の真ん中のところを追いかけている方だということは、
Twitterで存じ上げていましたが、
こしあんさんも、また適度な熱さと冷静さをもってらっしゃり、
僕好みの人間性を持っている方でした。

やっぱり会うって大きいと思います!
仲良くさせていただいている某団体(通販の運営者の団体)の代表の方が常々、
「TwitterやFacebookは、あくまでリアル世界のソーシャルの延長」
と仰っている意味が、ものすごく分かった気がします。

YATさん、こしあんさん、今後とも仲良くしましょう。


さて、肝心のPHPカンファレンスの中身は、
「クラウド」をテーマの中心においているせいか、
PHPカンファレンスなのに、
クラウド技術のお話だったり、JSのお話だったりと、
想像していたものと違って面食らってしまいましたが、
内容としては、良いノウハウの宝庫で、それはそれで良かったのかなと思っています。

また、ライトニングトークの枠もあったのですが、
さすが、こちらはdisられてもPHPerを名乗る方々のライトニングトークです。
PHPに対する思いがひしひしと伝わってきて、面白い内容ばかりでした。

ただ、CodeIgniter使いが少なくてしょんぼり…
やっぱ、CakeとSymfonyは強いですね…


本編終了後は、懇親会がありましたが、名古屋で行われる各イベントと異なり、
懇親会の中でも、ライトニングトークがあり、
本編の補足的な内容があったり、
有用なノウハウを伝えるものがあったり、
知らなかった会合やセミナーのお知らせがあったり、
と、ぶっちゃけ本編より充実してるんじゃないかと
錯覚させるような内容で、
お酒のちからもあるのでしょうが、
しゃべって終わりではなく、
みんながみんなどのような立場の人々なのかが分かるような懇親会でした。


名古屋からは@ahomuさんも行って、
はからずも名古屋のCMSの人がそれぞれ行くという布陣で行くことになりましたが、
強豪揃いのPHPerたちの前では、あえなく散ってしまう僕らでした。。。orz


というわけで、大阪人の熱さ、PHPerの熱さを感じることができた良い旅でした。
そして、名古屋、、、まだまだだなぁと感じた旅でした。
今後も何か大阪に関われたらなぁと思います。


あれ?集合写真の真ん中にアウエーの僕が…

CodeIgniterのいいとこ色々

先日CodeIgniterが2.0にバージョンアップしたり、
はてぶ界隈で
http://h2o-space.com/blog_ver2/diary/195
こちらの記事が話題となっているようですので、
CodeIgniterを使い始めて3ヶ月の私がちょっと反応してみます。
 


 私がCIを利用しはじめた理由は、

  • コーディング規約がゆるゆる
  • インストールにコマンドがいらない
  • 拡張がらくちん
  • 比較的広いPHPのバージョンに対応
  • モデルの扱いがゆるい

というところでした。
 
モデルのあたりは、前述の話題サイトにも書かれていますね。


実際に使い始めて特にいいなと思ったのが、
ユーザーガイドのページの使いやすさ・読みやすさです。
PHPさえちゃんとできれば、
ユーザーガイドのページを見ながら開発をラクに進められます。
書籍などはいらないと言ってよいです。
学習コストが異常なほど低いです。
 


そして、コントローラーの頭の良さに驚きを隠せないです。
一度ルーティングが成功してしまえば、
どこからでも、コントローラーインスタンスを呼び出すことができるので、
値をシステム内で縦断させて、参照/変更がかなり簡単にできます。
 
また、ローダーと呼ばれる、
ライブラリや設定ビューを呼び出す機能も、頭が良いです。
 
私はCodeIgniterを使う前、自作のフレームワークを利用していたのですが、
こちらのFWに使っていたライブラリ類の移植が、
コントローラーとローダーの頭の良さで、
非常に簡単に移植できました。
 
またCI自身のコアの拡張も分かりやすく、簡単にできます。
 


で、何が一番驚きって、とにかく高速。
ぶっちゃけ、普通のサイト作ったり、
モデルパターンの少ないWEBサービスだったら、
DBのクエリの速度以外は気にしないでいいレベルです。
 


常々私はEC専業のPGだと嘘ぶいていますが、
ECはページの魅せ方を色々変える必要があったり、
決済などの問題で、色んな拡張の必要性に迫られるケースが多々あるのですが、
そのへんでCIはパワーを発揮してくれます。
 
たとえばCakePHPは、良く言えば機能満載で、
痒いところに手が届いてサイト作りをラクにしてくれますが、
悪く言えばおせっかい機能満載で、
サイトの性質や、サイト作りの方針によっては足かせになります。
 
私のECサイト構築の立場では後者の立場だったのでCIはそのへんを解決してくれました。
 


 
とは言え、CIいいところばかりでは有りません。
 
前述の通りモデルやDB周りの実装がゆるゆるで、
ぶっちゃけモデルなんかナシでどうにかできちゃいますが、
ActiveRecordの機能は有しているものの、
Cakeよりは、ずっと「DBを操作している感」のある使い方になると思います。
また、DB操作が多いサイト作りの場合、
モデルファイルが大量になるかもしれません。
 
そして、CIを使ううえでPHPerが一番戸惑うのが、セッションでしょうね。
CIのセッションは、PHPのセッションは使わず独自実装です。
cookieに全てのデータを突っ込むcookieセッションか、
DBへデータを保存するDBセッションの2パターンが用意されていますが、
やっぱりファイルを使ったセッションもほしいところ。
ファイルセッションを利用する場合は、
自作でライブラリを作るか、別に配布されているライブラリを利用擦る必要があります。
(ただ、前述のとおりライブラリづくりは比較的簡単です。)
 
デフォルトで$_GETを破棄するという豪快な仕様になっているので、
そのへんを扱うのを最初戸惑うかもしれません。
(設定さえ覚えれば、すぐに慣れますが)
私の場合は、$_REQUESTを取り回す自作ライブラリで対応しています。
@kenji_sさんから

デフォルトで$_GETを破棄するのは CodeIgniter 1.x の仕様で 2.0.0 (Reactor) からはデフォルトで$_GETが使えるように変更されています

とご指摘いただきました。ありがとうございます。ちょっと不勉強でした。
 
あと、これは良いと言う人と悪いという人がいますが、
CIのviewは基本的に生PHPです。
私の場合は、生PHPは「うーん」な人なので、Smarty拡張しました。
(ただし、Smartyも「うーん」ですwwPHPTALにしようかなとか考えています)
 


というわけで、とにかくCIは頭がイイんだぜ!って話になっちゃいましたが、
よくないところを吸収するには、それなりのPHPの知識も必要というわけです。
以前書いたPHPのフレームワーク選択の記事でも書きましたが、
CIは、良くも悪くもちゃんとPHPが使えているということが前提条件であるFWでしょう。 

CodeIgniter2.0でSmarty

CodeIgniterが2011年1月28日付で2.0にバージョンアップされました。

ちょうど今日スタートの案件で、CodeIgniterを使おうと思って、
ダウンロードしにいったら2.0になっててびっくり。
 
社内で Perl→Template::Toolkit PHP→Smarty という刷り込みを行ってきたので、
オープンソースのFWを採用してもSmartyを使いたい。
ということで、こちらのような方策をとったのですが、
果たして、2.0ではどうでしょう?
 
とりあえず、前回の記事のように処理したら、
コンパイル済みテンプレートファイルの格納ディレクトリがないと警告。
 
CIの1.x系では、システムディレクトリの中にアプリケーションディレクトリがあるという構造でしたが、2.xからこれらが分離して、すこしディレクトリ構造が変わったのが原因でした。
 
前回の記事からのリンク先の説明にある、
config/smarty_parser.phpの

$config['compile_dir'] = BASEPATH.'cache/';

$config['compile_dir'] = APPPATH.'cache/';

にすれば動きました。
 
一安心。
 
CodeIgniteゆるゆるで素晴らしいよ!

CodeIgniterでSQLiteに接続。

今から作るアプリケーションでSQLiteを使わなくてはならなくなりました。
 
というわけで、CodeIgniterでSQLiteを使うにはどうしたらよいか。
 
system/application/config/database.phpの接続設定を

$db['default']['hostname'] = "";
$db['default']['username'] = "";
$db['default']['password'] = "";
$db['default']['database'] = "データベースファイル";
$db['default']['dbdriver'] = "sqlite";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";

ドライバに「sqlite」にして、
dbnameはデータベースファイルへのパスを指定します。
データベースファイルへのパスは相対パスも場合、
index.phpからの相対パスです。
APPPATHとかで、絶対パスを指定したほうがいいかもです。
 


この方法で使えるSQLiteは「SQLite2」ですのでご注意ください。
SQLite3を使いたい場合は、
http://codeigniter.com/wiki/PDO_SQLite3/
こちらを参考に。
配布アプリの場合は権限とか設定とかの問題があるので、
あまりやらないほうがいいかな。。。

CodeIgniterに同梱のSQLite用ドライバは、
バグがあるようです。
http://zidane27.blog119.fc2.com/blog-entry-11.html
このへんを参考に。これ以外情報がないので、バグにぶつかったら自分で直すしかなさそう…。

まぁいろいろアレだけど、SELECTとかINSERTとか基本的なとこは問題なさそう。

Older posts Newer posts