bindParamとbindValue

2008/10/01 | PDO

pdoを使ってプリペアードステートメントから各値をバインドするための関数が2つ用意されている。bindParamとbindValueだ。bindValueはコマンドが発行される都度SQL文に値がセットされるのに対し、bindParamは参照で値が渡され、execute実行時に初めて値に変換される。とりあえずマニュアルを読んで理解していたつもりだったのだが、やっぱり「つもり」だった。

$sql=’INSERT INTO table VALUES (?,?)';

上記のSQL文をプリペアードステートメントとしてセットし値をバインドしていくわけだが、こんなことをしてしていた。

$values=array(1=>3,2=>5);
foreach($values as $name => $value){
$preparedStatementObj->bindParam($name,$value);
}
$preparedStatementObj->execute();

こうすると、tableには(3,5)というデータが格納されてほしいのに、(5,5)というデータが入ってしまう。最初はまったく意味がわからなくて30分くらい悩んでしまった。そこでマニュアル読み直し。「参照渡し」「execute実行時に初めて・・・」。あ、そうか。値を渡すときに使う変数がいつも$valueだから、execute実行時には最後の$valueの値に置き換えられてしまっていたのか。

問題を解決する方法はbindValueを使うか、値をセットする都度異なる変数名を使用するか、のいずれか。どちらで試しても大丈夫だった。まさしく生兵法は怪我の基だった。

データベース操作はPDOで

2008/09/20 | PDO

最近の流行はPDOらしい。ということで今後はPDOを使うことにした。というのもZend_FrameworkでもPDO推奨らしいから。

PDOのマニュアルを見ると、プリペアードステートメントを使うことが基本のように見える。もちろんそのほうが、SQLインジェクションに悩まされることもないのだから当たり前といえば当たり前。これを機会に自分もそういう方向性で作業を進めることにする。でももうこれでPHP4には戻れない(戻るつもりもないけれど)。

とりあえず自分用に最低限のサンプルをメモしておく。

  1. $pdo=new PDO(“mysql:host=localhost; dbname=myDB”,”user”,”password”);
  2. $sql=’SELECT * FROM samples';
  3. $stmt=$pdo->prepare($sql);
  4. $stmt->execute();
  5. while($row=$stmt->fetch(PDO::FETCH_ASSOC)){
  6. var_dump($row);
  7. }

1行目でデータベースに接続してPDOオブジェクトの作成。DSNがちょっと今までと違うので注意が必要。2行目でSQLを用意して、3行目でprepareしているのだが、こんな簡単なSQLならprepareせずに直接queryメソッドを使うのもありだろう。prepareすると、その返り値はオブジェクトになっていて、以降そのオブジェクト(PDOStatementオブジェクト)に対して処理することになる。4行目でprepareしたSQL文を実行する。本来ならSQL文に「?」などのパラメータを使って値を格納する「箱」を用意しておき、3行目と4行目の間でbindParamなどを使って、それぞれの箱に値を代入して、それからSQLを実行することになる。実行結果はfetchメソッドを使って1行ずつ処理、ということだ。

特に難しいことはない。ただ今まで使っていたものに対して、汎用性を持たせて作りこむのが面倒だ。

高機能メール受信クライアントQdmailReceiver

2008/08/29 | PHPライブラリ

1ヶ月ぶりくらいの更新。ここのところ本業で忙しかったから、新しい技術に触れる機会がなかった。

以前携帯から写メールを送信し、それをPOPして添付ファイルを取り出してアルバムを作成するような仕組みを作った。その際はPEARを試したり、Zendを試したりいろいろ試行錯誤しつつ、結局は自分でかなりのスクリプトを書かなくてはいけなかった(実際書いたのは数十行だけど、試行錯誤段階から考えれば1000行以上は書いたと思う)。

今回、とあるクライアントから同等(もしくはそれ以上)の機能を実現できないか打診を受けた。しかし上記の「なんちゃってスクリプト」では申し訳ないし、うまい方法がないかと考えていたら、大変すばらしいライブラリに出会えた。

QdmailReceiver Multibyte mail decoder & POP Client

作者の方はメール関連のライブラリをいくつか記述していらっしゃるが、どれも大変すばらしい(といっても2本試しただけなのだけれど)。上記のライブラリを使うとメールをPOPしてあっという間にメール本文と添付ファイルに分割してくれる優れものだ。そしてHTMLメールにも対応しているので、文句のつけようがない。これで0.1.1アルファ版だというのだから作者の謙虚さにも恐れ入る。

実際のスクリプトは以下のように記述した。

require_once(‘qdmail_receiver.php’);
$server = array(
‘protocol’=>’pop3′,
‘host’=>’mail.example.com’,
‘user’=>’username’,
‘pass’=>’password’,
);
$receiver = QdmailReceiver::start(‘pop’, $server);
for($i = 1 ; $i <= $receiver->count() ; $i++){
$receiver->header(‘subject’);
var_dump($receiver->bodyAutoSelect());
$attachments = $receiver->attach();
foreach($attachments as $attachment){
var_dump($attachment);
}
$receiver->next();
}

11行目で本文を取り出しているのだが、なぜか10行目にあるようにヘッダに対して何らかの処理をしないと本文を取得できなかった。仕様だろうか。しかしまぁ、ヘッダは当然のように処理しなくてはいけないのでなんら問題はない。これでまた楽ができそうだ。

Smarty使用時のダウンロード処理

2008/06/25 | Smarty

ファイルのダウンロード処理をおこないたいときにテンプレートエンジンを使っている場合、どんな具合にプログラムを書けばよいか迷うことがよくある。フレームワークを使っていない場合はプログラム内にダウンロード処理を直書きしてしまうけれど、フレームワーク使用時は直書きするのはなんとなく美しくない。やっぱり通常通りの処理を通過して、テンプレート内だけで処理できればスマートだと思っている。Smartyの場合だが、今回はテンプレートファイルの最初にこんな具合におまじないを記述することでダウンロード処理を実現できた。

{php}
header(“Cache-Control: public”);
header(“Pragma: public”);
header(“Content-Type: application/csv”);
header(“Content-Disposition: inline; filename=data.dat”);
header(“Content-Transfer-Encoding: binary”);
header(“Accept-Ranges: none”);
{/php}

キャッシュ制御系はSSL使用時のIEバグ対策。Content-type、Content-Dispotion、Content-Transfer-Encodingは適宜指定。実際にダウンロードさせたい部分は、この後ろに記述すればよい。

でも、実はヘッダ的には一つ足りないんだと思う。それはダウンロードさせる容量Content-Lengthだ。この記述が必要なら、上記の記述の前に事前にダウンロードデータを以下のように記述して、容量を計算して出力すればいいかもしれない。

{capture name=download}
(ダウンロードさせたいデータを記述)
{/capture}
{header_content_length var=$smarty.capture.download}

いったん出力データを変数に格納して、別途ヘッダ出力用のカスタム関数(header_content_length)を用意しておいてそれに食わせてやればいい。カスタム関数が必要でしたら・・・各自でどうぞ(今回は作らなくても動いてくれたので作らなかった)。

Smartyでフォーム(ラジオボタンとチェックボックス)

2008/06/16 | Smarty

以前は「フォーム作成 = QuickForm」なくらいQuickFormを多用したけれど、近頃はめっきりQuickFormを使用しなくなった。QuickFormにはvalidation機能もあるし、なんといってもfreeze機能が便利なのだが、QuickForm2の安定版が出ないことには、多用する勇気が出ない。
QuickFormに変わってフォーム生成はSmartyのカスタム関数と自作のライブラリを使用している。基本的にはSmartyのカスタム関数だけで十分だけど、エラーを出力したり、確認画面を出したり、Smartyだけでは事足りない部分がいくつかあるからだ。
Smartyの便利なカスタム関数でラジオボタンを生成してくれるhtml_radiosとチェックボックスを生成してくれるhtml_checkboxesの使い方をメモしておく。

■html_radios、html_checkboxes共通のオプション(★多用、☆その他)

★name
フォーム要素のname属性に相当。html_checkboxesの場合は名前の後ろに[]を自動で付加して配列形式で受け取ることができるようにしてくれる。

★options(配列で与える)
value値(配列のキー)と表示する値(配列の値)の形式で与える。

★selected
初期で選択されている値(optionsのキーを指定)。html_checkboxesの場合、配列で与えると複数の項目にチェックを入れることができる。

☆separator
それぞれの項目を区切るための文字列を指定できる。<br />を指定すれば改行で区切られる。

☆valuesとoutput
optionsの代用で値と表示をそれぞれ別の配列で指定する。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net