早在我知道之前 - 不是我现在知道的很多 - 我在php中设计了一个web应用程序,它在运行值后通过我的mysql数据库插入数据 htmlentities()
。我最终意识到并取消了这一步并将其粘在输出而不是输入中,然后继续我的快乐方式。
然而,我已经不得不重新审视一些旧的数据,不幸的是我有一个问题,当它显示在屏幕上我得到的值显示有效htmlentitied两次。
那么,是否有一种mysql或phpmyadmin方法可以将所有较旧的受影响的行更改回相关的字符,还是我必须编写脚本来读取每一行,解码并更新12个表中的所有1700万行?
编辑:
感谢大家的帮助,我在下面用一些代码编写了我自己的答案,它不是很漂亮,但它早先在测试数据上工作,所以当我在床上时,禁止有人指出我的代码中的一个明显错误我将是明天在备份数据库上运行它,然后在实时数据库上运行它,如果运行正常的话。
我最终使用了这个,不是很漂亮,但我很累,现在是凌晨2点,它完成了它的工作! (编辑:关于测试数据)
$tables = array('users', 'users_more', 'users_extra', 'forum_posts', 'posts_edits', 'forum_threads', 'orders', 'product_comments', 'products', 'favourites', 'blocked', 'notes');
foreach($tables as $table)
{
$sql = "SELECT * FROM {$table} WHERE data_date_ts < '{$encode_cutoff}'";
$rows = $database->query($sql);
while($row = mysql_fetch_assoc($rows))
{
$new = array();
foreach($row as $key => $data)
{
$new[$key] = $database->escape_value(html_entity_decode($data, ENT_QUOTES, 'UTF-8'));
}
array_shift($new);
$new_string = "";
$i = 0;
foreach($new as $new_key => $new_data)
{
if($i > 0) { $new_string.= ", "; }
$new_string.= $new_key . "='" . $new_data . "'";
$i++;
}
$sql = "UPDATE {$table} SET " . $new_string . " WHERE id='" . $row['id'] . "'";
$database->query($sql);
// plus some code to check that all out
}
}
由于PHP是编码方法,因此您需要使用它进行解码。您可以使用 html_entity_decode 将它们转换回原始字符。得循环!
请注意不要解码不需要它的行。不知道你将如何确定。
我认为在这种情况下编写php脚本是件好事。正如Dave所说,您可以使用html_entity_decode()函数将文本转换回来。
首先在几个条目的表上尝试您的脚本。这将使您节省大量的测试时间。当然,记得在运行php脚本之前备份你的表。
我担心没有更短的可能性。无论您如何转换数据集,数百万行的计算仍然非常昂贵。所以去一个PHP脚本......这是最简单的方法
它有点kludgy但我认为大规模更新是唯一的方法...
$Query = "SELECT row_id, html_entitied_column FROM table";
$result = mysql_query($Query, $connection);
while($row = mysql_fetch_array($result)){
$updatedValue = html_entity_decode($row['html_entitied_column']);
$Query = "UPDATE table SET html_entitied_column = '" . $updatedValue . "' ";
$Query .= "WHERE row_id = " . $row['row_id'];
mysql_query($Query, $connection);
}
这是简化的,没有错误处理等。
不确定数百万行的处理时间是多少,因此您可能需要将其分解为块以避免脚本超时。
我有同样的问题。由于我有多个客户端在生产中运行应用程序,我想避免运行PHP脚本来为每个客户端清理数据库。
我想出了一个远非完美的解决方案,但却无痛苦地完成工作。
- 在插入数据之前跟踪代码中使用htmlentities()的所有位置,并删除它。
将“显示数据作为HTML”方法更改为以下内容:
return html_entity_decode(htmlentities($ chaine,ENT_NOQUOTES),ENT_NOQUOTES);
撤消 - 重做过程有点荒谬,但它完成了这项工作。每次用户更新不正确的数据时,您的数据库都会慢慢清理。
这是我的防弹版本。它遍历数据库中的所有Tables和String列,确定主键并执行更新。
它旨在从命令行运行php文件以获取进度信息。
<?php
$DBC = new mysqli("localhost", "user", "dbpass", "dbname");
$DBC->set_charset("utf8");
$tables = $DBC->query("SHOW FULL TABLES WHERE Table_type='BASE TABLE'");
while($table = $tables->fetch_array()) {
$table = $table[0];
$columns = $DBC->query("DESCRIBE `{$table}`");
$textFields = array();
$primaryKeys = array();
while($column = $columns->fetch_assoc()) {
// check for char, varchar, text, mediumtext and so on
if ($column["Key"] == "PRI") {
$primaryKeys[] = $column['Field'];
} else if (strpos( $column["Type"], "char") !== false || strpos($column["Type"], "text") !== false ) {
$textFields[] = $column['Field'];
}
}
if (!count($primaryKeys)) {
echo "Cannot convert table without primary key: '$table'\n";
continue;
}
foreach ($textFields as $textField) {
$sql = "SELECT `".implode("`,`", $primaryKeys)."`,`$textField` from `$table` WHERE `$textField` like '%&%'";
$candidates = $DBC->query($sql);
$tmp = $DBC->query("SELECT FOUND_ROWS()");
$rowCount = $tmp->fetch_array()[0];
$tmp->free();
echo "Updating $rowCount in $table.$textField\n";
$count=0;
while($candidate = $candidates->fetch_assoc()) {
$oldValue = $candidate[$textField];
$newValue = html_entity_decode($candidate[$textField], ENT_QUOTES | ENT_XML1, 'UTF-8');
if ($oldValue != $newValue) {
$sql = "UPDATE `$table` SET `$textField` = '"
. $DBC->real_escape_string($newValue)
. "' WHERE ";
foreach ($primaryKeys as $pk) {
$sql .= "`$pk` = '" . $DBC->real_escape_string($candidate[$pk]) . "' AND ";
}
$sql .= "1";
$DBC->query($sql);
}
$count++;
echo "$count / $rowCount\r";
}
}
}
?>
干杯
罗兰