プロフィール

けい

Author:けい
公開したWebサービス・アプリ一覧はこちら

※2014年12月、私が個人で開発したWebサービス・アプリへの
累計アクセス数は8億を超えました。
負荷対策頑張ります。日々精進していきます!!


■■■ 業務経歴 ■■■
社会人1年目:携帯電話開発。画面周りを1年間
2年目 :海外向け携帯電話ミドルウェア開発
     ブラウザとプロトコルスタック周り
2年目後半~:携帯電話の通信専用チップ開発
3年目:カーナビ。画面周りの開発
3年目後半~:BDビデオカメラ
     組み込みLinux カーネルと
     ドライバの開発。
4年目12月:プロジェクト途中で退社
~ここまではC、またはC++で開発~

~ここからJavaがメインの開発~
4年目1月:Web系の会社に転職
       ~4ヶ月間の研修
5年目5月:製造業向け生産管理システム開発
6年目9月:証券会社向けシステム開発
7年目10月~携帯電話向けコミックサイトの運用・開発
8年目12月:プロジェクト途中で退社

~ここからPHPがメインの開発~
8年目1月~仲介手数料が無料の不動産屋の社内SEに転職
交渉しほぼ完全に裁量労働が可能な立場になる。
業務内容はシステム全般ですが、
最近はSEO対策の作業が多いです。
現在14年目 まだ、しばらくはこの会社に居るつもりです。

あと、全ての記事がリンクフリーです。

最近の記事

過去ログ

全ての記事を表示する

全ての記事を表示する

カテゴリー

FC2カウンター

RSSフィード

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
--.--.--    [ Myカテゴリ:スポンサー広告 ]

PHPでZendDBを使用している際のプレースホルダの注意点まとめ


世間はメリークリスマスと言って浮かれているはずの日なのですが、
不具合が起きたので夜中まで調査しておりました。
ググッても解決できなかったので誰かの為になるようにブログに書いておくことにします。

なお、この注意点は厳密にはZendDBの仕様と言うよりも、PDOの仕様の注意点なのですが、
フレームワークを使っていたために原因の特定が難しかったということもあり、
ZendDBの使用者向けに書いています。


まず、プレースホルダとはクエリの以下のような「?」で記載することができる
動的変数のことです。
++++++++++++++++++++++++++++++++++++++++++
SELECT
*
FROM
table
WHERE
id = ? -- <これ
++++++++++++++++++++++++++++++++++++++++++
通常は以下のように名前付きプレースホルダを使用します。
++++++++++++++++++++++++++++++++++++++++++
SELECT
*
FROM
table
WHERE
id = :id -- <これ
++++++++++++++++++++++++++++++++++++++++++
で、問題なのがプレースホルダを記載できる箇所の制限が実はかなり多いということ。
例えば、MERGE テーブルのように同じレイアウトのテーブルがたくさんある場合に、
以下のように書きたくなるのですが、こういう書き方はできません。
++++++++++++++++++++++++++++++++++++++++++
SELECT
*
FROM
:table
++++++++++++++++++++++++++++++++++++++++++
理由は簡単でプレースホルダを展開すると以下のように
クォーテーション付きで展開されるからです。
++++++++++++++++++++++++++++++++++++++++++
SELECT
*
FROM
'table'

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use nea・・・
++++++++++++++++++++++++++++++++++++++++++
同じ理由からカラム名にも使用できません。
++++++++++++++++++++++++++++++++++++++++++
SELECT
:id
FROM
table

↓以下のように展開される

SELECT
'id'
FROM
table
++++++++++++++++++++++++++++++++++++++++++
上記例の場合には以下のような結果が出力されます。

+----+
| id |
+----+
| id |



| id |
+----+
15 rows in set (0.00 sec)

よって、クエリとして使用可能な箇所が限られます。
ではクォーテーションが付いている状態で、実行できないようなSQL文は実行できないのかというと
そう言うことでもないらしく・・・

++++++++++++++++++++++++++++++++++++++++++
SELECT
id
FROM
table
LIMIT :start, :end

↓以下のように展開される

SELECT
id
FROM
table
LIMIT '0', '1'
++++++++++++++++++++++++++++++++++++++++++
上記クエリは、クエリとしてプロンプトから実行すると以下のエラーがでます。
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''0', '1'' at line 5

しかし、プログラム上から動かすと正しい結果が得られます。

++++++++++++++++++++++++++++++++++++++++++
-- 以下は正常に実行可能です
$sql = "
SELECT
id
FROM
table
LIMIT :start, :end
";
$bind = array(
'start' => 0, 'end' => 1
);
ZendDBのInstance()->fetchRow($sql, $bind);
++++++++++++++++++++++++++++++++++++++++++

他にもサブクエリの中のサブクエリで動かしたら、動かなかったりと
地雷的な要素が多い。
う~む。単純な機能の割には制約が多いなぁ。
制約が多いのは構わないのですが、その制約が情報としてまとまっていないことも
不信感が強まります。

数値でクエリを吐きたい時も文字列になってしまうのもパフォーマンス的に宜しくないですし、
なまじ中途半端に動いてしまう場合があるから、何が原因なのかがよけいわかりにくかったです。
これだけ不明瞭な制約が多いと自作したほうが良いと思える・・・

ちなみにZendだとプレースホルダしか使っていないのに「?」がどうとか表示されて
悩みました

PHP Zend_Db_Statement_Exception: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?\n


暫定対処
一日寝て思いついたのですが、
そもそも名前付きプレースホルダを使用する理由は以下になります。
・動的にクエリを書きたい
・SQLインジェクションの心配をしたくない
・$select . ' id FROM' . $table のようなクォーテーションだらけの
可読性の低いプログラムを書きたくない。

->ヒアドキュメントがいいのではないだろうか。

ヒアドキュメントならばクォーテーションを意識しなくてよいし、
プレースホルダと変数を違和感無く書き分けることができるわけです。
(もちろんルールは厳密にする必要がありますが)


++++++++++++++++++++++++++++++++++++++++++
//ヒアドキュメント使用パターン
const $tableName = 'tableName';
$sql = <<<EOI
SELECT
*
FROM
{$tableName}
WHERE
id = :id
EOI;

$bind = array(
'id' => $id
);
ZendDBのInstance()->fetchRow($sql, $bind);
++++++++++++++++++++++++++++++++++++++++++

上記のように、ユーザーが画面で入力した値は名前付きプレースホルダ。
それ以外の動的に変更したい箇所はヒアドキュメント内の変数に入れる形にすれば
可読性を損なうこと無く動的にクエリを書けます。

え?{$tableName}の所が、危険に見える?
確かにそうなのですが、そこはConstの値のみを入れるなどの
ルールを徹底させることにより回避しています。

とりあえず私は上記の方法でプログラムを行なっておりますが、
他に何かいい案が御座いましたら教えて頂ければ幸いです。
スポンサーサイト
コメント(0)   2011.12.25    [ Myカテゴリ:技術の話 ]
Template Designed By
ぐらいんだぁ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。