安全的方式来循环PDO声明

时间:2015-10-06 16:34:47

标签: php mysql pdo

问题:

循环执行准备好的PDO语句,检查重复项,如果没有重复项执行查询?

当前的PDO声明:

$STH = $DBH->prepare("INSERT INTO inbox (id,efrom,subject,msg,eread,date) VALUES ('',:efrom,:esubject,:emsg,:eread,:edate)");
$STH->bindParam(':efrom', $inbox_from[0]);
$STH->bindParam(':esubject', $inbox_subject[0]);
$STH->bindParam(':emsg', $inbox_msg[0]);
$STH->bindParam(':eread', $inbox_read[0]);
$STH->bindParam(':edate', $inbox_date[0]);

为什么需要循环:

我需要递增数组$inbox_*然后查询,直到它到达数组的末尾。

示例:

$inbox_from('hello','how','are','you');

someloop(somecondition) {
    //output would be:
    $STH->bindParam(':efrom', $inbox_from[0]);
    $STH->bindParam(':efrom', $inbox_from[1]);
    $STH->bindParam(':efrom', $inbox_from[2]);
    $STH->bindParam(':efrom', $inbox_from[3]);
    //It ends at [3] index because its the end of the array.
}
$STH = execute();
//So now it executes and should have put the 4 array indexes into different efrom columns. So column id 1 has 'hello' and id 4 has 'you'.

也许:

for($i = 0; //Something to check if array ended; ++$i) {
//Someway to Properly bind the arrays and execute?
}

或使用While循环?

希望我尽力解释。

这里使用的最佳做法是什么?

2 个答案:

答案 0 :(得分:1)

使用编号参数代替命名参数,并动态构建查询和参数。

$sql = "INSERT INTO inbox (efrom,subject,msg,eread,date) VALUES ";
// array_fill will create an array of N "(?, ?, ?, ?, ?)" strings
// implode will then join them together with comma separators
$sql .= implode(', ', array_fill(0, count($inbox_from), "(?, ?, ?, ?, ?)"));
$STH = $DBH->prepare($sql);
$params = array();
// Populate the $params array with all the input values
foreach ($inbox_from as $i => $from) {
    $params[] = $from;
    $params[] = $inbox_subject[$i];
    $params[] = $inbox_msg[$i];
    $params[] = $inbox_read[$i];
    $params[] = $inbox_date[$i];
}
$STH->execute($params);

您可以将id字段保留在列列表之外,并使用自动增量自动填充。

要删除重复的邮件,您可以执行以下操作:

$check_stmt = $DBH->prepare("SELECT COUNT(*) AS count FROM inbox WHERE msg = :msg");
$check_stmt->bindParam(':msg', $msg);
$messages_seen = array();
foreach ($inbox_msg as $i => $msg) {
    // Check if the message is already in the DB
    $check_stmt->execute();
    $first_row = $check_stmt->fetch(PDO::FETCH_OBJ);
    $check_stmt->fetchAll(); // Fetch the rest of the query to get in sync
    if ($first_row->count > 0) {
        $messages_seen[$msg] = true; // Remember that we already saw this message
    } elseif (!isset($messages_seen[$msg])) // If we haven't already seen this message
        $params[] = $inbox_from[$i];
        $params[] = $inbox_subject[$i];
        $params[] = $msg;
        $params[] = $inbox_read[$i];
        $params[] = $inbox_date[$i];
        $messages_seen[$msg] = true; // Remember that we added this message
    }
}
$sql = "INSERT INTO inbox (efrom,subject,msg,eread,date) VALUES ";
// There's 1 (...) group for every 5 parameters, so divide the length of $params by 5 to know how many of them to put in the SQL
$sql .= implode(', ', array_fill(0, count($params)/5, "(?, ?, ?, ?, ?)"));
$STH = $DBH->prepare($sql);
$STH->execute($params);

在TEXT数据类型上添加索引时,必须指定要在索引中存储的文本的字节数。所以它应该是这样的:

CREATE INDEX ix_msg ON inbox (msg(200));

答案 1 :(得分:0)

如果您使用Insert to same table

,则可以创建一个大查询
INSERT INTO table (columns) VALUES (....), (....)...., (...) 

它比为每行调用sql更好。更快