Sennaのsnippet udfを使うSQLは:
SELECT snippet(文書, snippetの長さの最大バイト数, snippetの最大個数, 文書の文字コード, htmlエンコーディングの有無, snippetの開始タグ, snippetの終了タグ, 単語1, 単語1の前につけられるタグ, 単語1の後につけられるタグ, 単語2, 単語2の前につけられるタグ, 単語2の後につけられるタグ, ...);
となっている。単語の数に応じて引数の数が変化するので、PreparedStatementを使えない。
簡単のためにフレーズ検索は考えないことにする。検索窓とかからスペース区切りの検索フレーズを受け取ったら、snippet関数の第8引数以降を何とかして生成したい。
against()の中はPreparedStatementを使えるので、prepareするSQL文は以下のようになるかなー (AND検索する場合):
SELECT title, snippet(body,256,2,'utf8',1,'','',あとで追加する部分) AS snip FROM items WHERE MATCH(title,body) AGAINST(? in boolean mode) order by MATCH(title,body) AGAINST(? in boolean mode);
で、空白区切りのクエリを受け取ったら:
$queries = explode(' ',$q);
$snip = "";
$against = "";
foreach($queries as $idx => $each){
$snip .= ','.mysql_real_escape_string($each).",'<span class=\"query q$idx\">','</span>'";
$against .= '+'.$each;
}
$sql = "SELECT title, snippet(body,256,2,'utf8',1,'',''$snip) AS snip FROM items WHERE MATCH(title,body) AGAINST(? in boolean mode) order by MATCH(title,body) AGAINST(? in boolean mode)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $against, $against);
って感じ? 定石はどんななんだろ。