在我知道任何事情之前很久 - 不是我现在知道的很多 - 我在php中设计了一个web应用程序,它在通过htmlentities()
运行值后将数据插入到我的mysql数据库中。我最终醒悟过来,取消了这一步,把它放在输出而不是输入中,继续我的快乐方式。
然而,我不得不重新审视一些旧的数据,不幸的是我有一个问题,当它显示在屏幕上时,我显示的值显示有效两次。
那么,是否有一种mysql或phpmyadmin方法可以将所有较旧的受影响的行重新更改为相关字符,还是必须编写脚本来读取每一行,解码并更新12个表中的所有1700万行? / p>
编辑:
感谢大家的帮助,我在下面用一些代码编写了我自己的答案,它不是很漂亮,但是之前的测试数据很有用,所以当我在床上的时候禁止有人在我的代码中指出一个明显的错误我明天将在备份数据库上运行它,然后在实时数据库上运行它,如果运行正常的话。
答案 0 :(得分:5)
我最终使用了这个,不是很漂亮,但我很累,现在是凌晨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
}
}
答案 1 :(得分:4)
由于PHP是编码方法,因此您需要使用它进行解码。您可以使用html_entity_decode将其转换回原始字符。得循环!
请注意不要解码不需要它的行。不知道你将如何确定。
答案 2 :(得分:2)
我认为在这种情况下编写php脚本是件好事。正如Dave所说,您可以使用html_entity_decode()函数将文本转换回来。
首先在几个条目的表上尝试您的脚本。这将使您节省大量的测试时间。当然,记得在运行php脚本之前备份你的表。
我担心没有更短的可能性。无论您如何转换数据集,数百万行的计算仍然非常昂贵。所以去一个PHP脚本......这是最简单的方法
答案 3 :(得分:1)
这是我的防弹版本。它遍历数据库中的所有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";
}
}
}
?>
欢呼声 罗兰
答案 4 :(得分:0)
这有点笨拙,但我认为大规模更新是唯一的方法......
$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);
}
这是简化的,没有错误处理等。 不确定数百万行的处理时间是多少,因此您可能需要将其分解为块以避免脚本超时。
答案 5 :(得分:0)
我遇到了完全相同的问题。由于我有多个客户端在生产中运行应用程序,我想避免运行PHP脚本来为每个客户端清理数据库。
我想出了一个远非完美的解决方案,但却无痛苦地完成了工作。
将您的&#34;显示数据更改为HTML&#34;方法是这样的:
返回html_entity_decode(htmlentities($ chaine,ENT_NOQUOTES),ENT_NOQUOTES);
撤消 - 重做过程有点荒谬,但它确实起作用了。每次用户更新不正确的数据时,您的数据库都会慢慢清理。