honto から Amazon.co.jp のカスタマーレビューを開くブックマークレット
javascript:void(function(d,w){r=d.evaluate('//li[contains(.,"ISBN:")]/text()',d,null,XPathResult.STRING_TYPE,null);if(r&&r.stringValue){w.open('http://www.amazon.co.jp/gp/search/?field-isbn='+encodeURIComponent(r.stringValue.substr(5).trim())+'#customerReviews');}})(document,window)
これに ISBN 検索で結果が一件だったら商品ページにリダイレクトする user.js を組み合わせて使用しています。
if (document.getElementById('s-result-count').firstChild.data.indexOf('1件') === 0) { location.href = 'http://www.amazon.co.jp/dp/' + document.getElementById('result_0').getAttribute('data-asin') + location.hash; }
なんかやり口が古そうなのでつっこみ歓迎。
配列のキーキャストでハマりそうな例
注目すべきは、3つ目の要素のキーが string(2) "00" になっていること!!
フォームから送られてくる数値(のように見える文字列)とか、データベースでCHARで格納してるけど運用上数値しか入れてないのものなど、「配列のキーに入れればintになってくれるでしょ」と思い込んでるとちょっとハマるので注意しましょう、ということでした。
連想配列のキーに渡したときの暗黙のキャスト - いちいの日記
具体例を考えてみました。普段は困ることはなさそうですが、同じようなデータなのに持ち方が違うと割とハマりやすそうです。どちらも ID を格納しているけれど片や配列、片や DB のような。
- $cart
- SESSION とかに入った配列のおかいものかご
- $id
- カートに入れたい商品 ID のフォーム値
- $db
- DB インタフェースオブジェクト
一個だけ PEAR DB 固有だったので legacy だけどそれで - item
- 商品マスタテーブル
同じものが違う要素に
// array(商品 ID => 注文個数) なお買い物かご $cart = array( 20 => 1, 23 => 1, ); $id = '023'; // なんかまかり間違って 0 がついたままきちゃった $statement = $db->prepare('SELECT * FROM item WHERE id = ?'); $result = $db->execute($statement, array($id)); if (!DB::isError($result) && $result->numRows() > 0) { // id カラムが int なので WHERE id = '023' で 23 のレコードが選択される // item は存在するからカートに入れる if (isset($cart[$id])) { // *ここが false* $cart[$id]++; } else { $cart[$id] = 1; // 新しく追加されてしまう } }
- 商品も配列で持っていれば、存在チェックでこける
- isset($item_list[$id])
- 商品 ID が int な cart テーブルに入れれば int になる
回避策
- 取得した商品データの ID を使う
$item = $result->fetchRow(DB_FETCHMODE_ASSOC);
$id = $item['id'];
見つかるんだけど見つからない
$cart = array( 20 => 1, '023' => 1, // さっきの状況で入ってしまった string な商品 ID ); $item_list = array(); $args = implode(', ', array_map(array($db, 'smartQuote'), array_keys($cart))); $result = $db->simpleQuery("SELECT * FROM item WHERE id IN ($args)"), while ($item = $result->fetchRow(DB_FETCHMODE_ASSOC)) { $id = $item['id']; $item_list[$id] = $item; $item_list[$id]['order'] = $cart[$id]; // Undefined index: 23 }
なんかインデックスが効かない
- 今度は逆に int に変換されることを考慮していない状況
- id は固定長文字列で zero padding されているとする
$cart = array( '00331' => array('order' => 1), '15910' => array('order' => 1), // キーが int になる ); $statement = $db->prepare('SELECT * FROM item WHERE id = ?'); foreach (array_keys($cart) as $id) { $result = $db->execute(array($id));
execute
から呼ばれる quoteSmart
は is_int
が true だと quote しないので
SELECT * FROM item WHERE id = '00331'; +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | item | const | PRIMARY | PRIMARY | 7 | const | 1 | | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ SELECT * FROM item WHERE id = 15910; +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+ | 1 | SIMPLE | item | ALL | PRIMARY | NULL | NULL | NULL | 99999 | Using where | +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+