憂鬱なSQLのためのアレ
公開日:
by USAMI Kenta@tadsan
スライドテキスト
Page 2
近況報告
PHPカンファレンス北海道で喋ってきました
- 「仕事で使えるComposer」
http://niconare.nicovideo.jp/watch/kn1371 - WEB+DB Press Vol. 92にPHPからHTTPリクエストをする話を書きました
http://gihyo.jp/magazine/wdpress/archive/2016/vol92
Page 3
近況報告
- AdventCalendarではPHPマニュアルのバージョン番号をパースする話を書きました
http://qiita.com/tadsan/items/94e00f6fdf40d96c5072 - スレッドフロート掲示板を作りたかった少年時代の代償行為として、モダンPHP、ただしフレームワーク抜きで書き始めました
http://qiita.com/tadsan/items/cdbbb5b08591af2b110d
Page 4
みんな大好きPDO
PHP Data Objects
- いろんなSQLを抽象化したオブジェクト
- 学生がmysqli関数使ってたけどPDOでいい
- あとなんか、Doctrineとか使った方がいいの?
Page 5
Real World PHP
- 2015年にもなって徳丸先生がPHPカンファレンスでSQLインジェクションの話をしてるリアル
- O/Rマッパー使っとけwwwと煽ったところで、世界にはまだ文字列結合SQLが眠ってる
Page 6
みんな事故る
文字列結合の温床
- 型を指定するのはめんどくさい
- $stmt->bindValue(':id', $id, \PDO::PARAM_INT)
- 可変個数のIN句が地雷
Page 7
Real World PHP
$names = ["taro","jiro","saburo"];
$str = implode(",", array_map($name){
return sprintf('"%s"', $name);
});
$sql = "SELECT * FROM users WHERE name IN ($str)";
// ↑典型的な漏れのあるロジックの例
Page 8
PDOのラッパー作った
警告:ちゃんとしたO/Rマッパーの方がいい
- (会社で同僚が作ったのを)コピペして再実装した
- SQL内に型が書けるDSL
- PDOに乗っかって、余計なことはしない
- SQLインジェクションにある程度の耐性がある?
Page 9
composer require zonuexe/tetosql
https://github.com/BaguettePHP/TetoSQL
Page 10
<?php
namespace InspireBBS\Model;
use Teto\SQL;
/**
* 板を表現するモデル
* @copyright 2016 USAMI Kenta
* @license WTFPL
*/
final class Board {
/**
* @return Board[]
*/
public static function findAll() {
$data = SQL\Query::execute(db(), self::findAll_query, [])
->fetchAll(\PDO::FETCH_ASSOC) ?: [];
$boards = [];
foreach ($data as $b) {
$boards[] = new Board($b);
}
return $boards;
}
const findAll_query = 'SELECT `id`, `name`, `text` FROM `boards`';
}
Page 11
use Teto\SQL;
public static function find($id) {
$data = SQL\Query::execute(db(), self::findAll_query, [
':id' => $id,
])->fetchAll(\PDO::FETCH_ASSOC) ?: [];
$boards = [];
foreach ($data as $b) {
$boards[] = new Board($b);
}
return $boards;
}
const find_query = ‘
SELECT `id`, `name`, `text` FROM `boards` WHERE `id` = $id@int
';
Page 12
基本的なAPI
どうにかしてPDOのコネクションをとっておく
- $stmt = SQL\Query::execute($con, self::find_query,
[':id' => $id, ':hoge' => $hoge] );
コネクション、SQL、アサインする値を渡す
- 帰ってくる値はPDOStatementなので、
- いつもの感覚でfetch/fetchAllするだけ!
Page 13
const
- PHPのconstは(原則)実行時に変更されない
- そこにパラメータを当て嵌めるだけ、なのはなんとなく心理的な安心感がある (本当か?)
- お気付きだろうか…
- このコードがPSR-1違反であることに…
