当名称包含撇号时,通过表单与MySQL数据库匹配名称的脚本中断


Script to match names submitted via a form with MySQL database breaks when name contains apostrophe

我有一个脚本,使用mysql_real_escape_string将名称输入MySQL数据库,以便正确处理撇号。我遇到的问题是下面的脚本,检查使用另一种形式输入的名称是否与数据库中已经存在的名称相对应,如果找到名称,则更新行。

当我尝试在此脚本处理的表单中输入带有撇号的名称时,我得到一条错误消息,指出没有找到该名称,并且错误消息中的名称在撇号之前包含反斜杠,这显然是问题所在。

那么问题是,我如何修改下面的脚本,使它能够与带有撇号的名称一起工作?

谢谢,尼克

$row_count = count($_POST['name']);
if ($row_count > 0) {
    mysql_select_db($database, $connection);
    $name = array();
    $workshop = array(); 
    $not_found = array();
    for($i = 0; $i < $row_count; $i++) {
        // variable sanitation...
        $name[$i] = mysql_real_escape_string(ucwords($_POST['name'][$i]));
        $workshop[$i] = mysql_real_escape_string($_POST['workshop'][$i]);
    }
    $names = "('".implode("','",$name)."')";
    $not_in = Array();
    // lets say all names doesn't exist in `conference`
    foreach($name as $value) {
        // names in array are keys, not values
        $not_in[$value] = true;
    }

    $query = mysql_query("SELECT Name FROM conference WHERE Name IN $names"); 
    while(list($dbname) = @mysql_fetch_row($query)) {
        // delete those name from $not_in who exists
        unset($not_in[$dbname]);
    }
    // names in $not_in array are keys, not values
    $not_in = array_keys($not_in);
    if(empty($not_in)) {
        // its ok, all names have been found. do the magic.
        for($i = 0; $i < $row_count; $i++) {
            $sql = "UPDATE conference SET Workshop = '$workshop[$i]' WHERE Name LIKE '$name[$i]'";
            mysql_query($sql);
            $body .= "Name: " . $name[$i] . "    Workshop: " . $workshop[$i] . "'n'n";
        }

嗯!我想我可能找到问题了。问题可能不在于查询,而在于PHP代码。我将在下面用你的例子John O'Shea来解释。

for($i = 0; $i < $row_count; $i++) {
    // variable sanitation...
    $name[$i] = mysql_real_escape_string(ucwords($_POST['name'][$i]));
    $workshop[$i] = mysql_real_escape_string($_POST['workshop'][$i]);
}
$names = "('".implode("','",$name)."')";
$not_in = Array();
// lets say all names doesn't exist in `conference`
foreach($name as $value) {
    // names in array are keys, not values
    $not_in[$value] = true;
}

在上面的代码之后,数组$not_in将包含转义的键,因为$name已经包含了使用mysql_real_escape_string()转义的值。因此,例如:

$not_in[John] = true;$not_in[John O''Shea] = true;

$query = mysql_query("SELECT Name FROM conference WHERE Name IN $names"); 
while(list($dbname) = @mysql_fetch_row($query)) {
    // delete those name from $not_in who exists
    unset($not_in[$dbname]);
}

现在,上面代码中的$dbname包含从DB检索到的未转义的值,例如没有反斜杠的John O'Shea。因为这不是$not_in所包含的内容,所以unset()将不起作用。这意味着所有撇号值都保留在$not_in数组中。

因此,修复方法是在$not_in中保留未转义的值。

希望这是有意义的!

==========编辑:在响应如何保持未转义值在$not_in:

这个想法是只在需要的地方进行转义。以下是您可以对代码进行的更改:

重写第一个for()如下:

for($i = 0; $i < $row_count; $i++) {
    // variable sanitation...
    //$name[$i] = mysql_real_escape_string(ucwords($_POST['name'][$i]));
    $name[$i] = ucwords($_POST['name'][$i]);
    $workshop[$i] = mysql_real_escape_string($_POST['workshop'][$i]);
}
$names = "('" . mysql_real_escape_string(implode("','",$name)) . "')";

并将UPDATE语句重写为:

$sql = "UPDATE conference SET Workshop = '$workshop[$i]' WHERE Name LIKE '" . mysql_real_escape_string($name[$i]) . "'";

顺便说一下,根据你的代码,如果有一个名字不存在于数据库中,UPDATE将不会运行。是否绝对有必要只在数据库中找到所有$_POST['name']时才运行UPDATE ?如果没有,可以显著减少代码量。

我还没有测试以上的变化,但我认为他们应该工作。如果你有任何问题,请告诉我。

==========编辑2:用于更新已存在的记录并为不存在的记录生成错误的代码片段

嘿,Nick,我认为只有写下面的代码才能达到目的:

$row_count = count($_POST['name']);
if ($row_count > 0) {
    mysql_select_db($database, $connection);
    for ($i = 0; $i < $row_count; $i++) {
        mysql_query("UPDATE conference SET Workshop = '" . mysql_real_escape_string($_POST['workshop'][$i]) . "' WHERE Name LIKE '" . mysql_real_escape_string($_POST['name'][$i]) . "'");
        $affectedRows = mysql_affected_rows();
        if ($affectedRows == 0) {
            echo '<br>Name did not exist - ' . $_POST['name'][$i];
        }
    }
}

希望这对你有帮助!