使用like子句执行准备好的PDO语句

Ell*_*lle 5 php sql pdo prepared-statement

我是PHP的新手,我正在尝试学习使用PDO连接到测试MySQL数据库.我有以下内容:

try {
    $db = new PDO('mysql:dbname=MYDBNAME;host=MYHOST', 'USERNAME', 'PASSWORD');

    $query = "select * from books where ? like '%?%'";
    $stmt = $db->prepare($query);
    $stmt->execute(array($searchtype, $searchterm));  
} catch(PDOException $e) {
    echo 'PDOException: ' . $e->getMessage();
}
Run Code Online (Sandbox Code Playgroud)

当我尝试它时,我收到以下警告:警告:PDOStatement :: execute()[pdostatement.execute]:SQLSTATE [HY093]:无效的参数号:绑定变量的数量与令牌的数量不匹配

当我删除like子句和$ searchterm参数时,它会正确返回结果.我想 - 比如'%?%' - 可能不是用双引号创建这个查询的合法方式,所以我尝试转义',这不起作用.我四处寻找解决方案,发现有人将'%和%'移到$ searchterm所在的位置:

$query = "select * from books where ? like ?";
...
$stmt->execute(array($searchtype, '\'%'.$searchterm.'%\'')); 
Run Code Online (Sandbox Code Playgroud)

我得到了相同的结果.
任何帮助表示赞赏.谢谢!

/ UPDATE **** /我在http://us3.php.net/manual/en/pdo.prepared-statements.php的例子12中找到了

Example#12使用占位符无效

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));

// Below is What they suggest is the correct way.
// placeholder must be used in the place of the whole value 
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?> 
Run Code Online (Sandbox Code Playgroud)

我试过这个,即使我不再收到警告,我也没有得到任何结果.但是当我直接执行查询时,我会得到几个结果.有什么想法吗?

bob*_*nce 2

$stmt->execute(array($searchtype, \'\\\'%\'.$searchterm.\'%\\\'\')); \n
Run Code Online (Sandbox Code Playgroud)\n\n

这不是参数化查询的工作方式。插入的参数已经充当文字字符串,您不必在它们周围添加引号分隔符或转义它们(这就是重点),如果您尝试,您实际上是在与字符串单引号进行比较-searchterm-单引号。

\n\n

因此,如果您(正如我怀疑的那样)打算将特定列与文字字符串进行比较,则无需参数化列名称。目前,您正在将一个文字字符串与另一个文字字符串进行比较,因此无论行中的数据如何,它要么始终为真,要么始终为假!

\n\n

所以我想你的意思可能是:

\n\n
$query= "SELECT * FROM books WHERE $searchtype LIKE ?";\n$like= "%$searchterm%";\n$stmt->execute(array($like)); \n
Run Code Online (Sandbox Code Playgroud)\n\n

自然地,您必须非常小心,$searchtype以避免 SQL 注入。通常,在使用它之前,您会将其与可接受的列名称列表进行比较。

\n\n

(旁白:有一种方法可以将任意字符串放入可用于列的模式名称中,但这很烦人,不同数据库有所不同,并且没有标准的转义函数。在 MySQL 中,您可以使用反斜杠-转义反引号字符、引号和反斜杠,并用反引号包围名称。在 ANSI SQL 中,您使用双引号,内部有双引号。在 SQL Server 中,您使用方括号。但实际上,您很少需要执行任何操作这是因为实际上您只想允许一些预定义的列名称。)

\n\n

(另外:如果您希望能够允许$searchterm在\xe2\x80\x94中使用带有文字百分比、下划线或反斜杠的值,那么用户可以搜索\xe2\x80\x9c100%\xe2\x80\x9d,而无需与in匹配任何字符串100\xe2\x80\x94你必须使用显式转义字符,这有点乏味:)

\n\n
$query= "SELECT * FROM books WHERE $searchtype LIKE ? ESCAPE \'+\'";\n$like= str_replace(array(\'+\', \'%\', \'_\'), array(\'++\', \'+%\', \'+_\'), $searchterm);\n$stmt->execute(array("%$like%")); \n
Run Code Online (Sandbox Code Playgroud)\n