问题 如何从数据库中删除htmlentities()值?


早在我知道之前 - 不是我现在知道的很多 - 我在php中设计了一个web应用程序,它在运行值后通过我的mysql数据库插入数据 htmlentities()。我最终意识到并取消了这一步并将其粘在输出而不是输入中,然后继续我的快乐方式。

然而,我已经不得不重新审视一些旧的数据,不幸的是我有一个问题,当它显示在屏幕上我得到的值显示有效htmlentitied两次。

那么,是否有一种mysql或phpmyadmin方法可以将所有较旧的受影响的行更改回相关的字符,还是我必须编写脚本来读取每一行,解码并更新12个表中的所有1700万行?

编辑:

感谢大家的帮助,我在下面用一些代码编写了我自己的答案,它不是很漂亮,但它早先在测试数据上工作,所以当我在床上时,禁止有人指出我的代码中的一个明显错误我将是明天在备份数据库上运行它,然后在实时数据库上运行它,如果运行正常的话。


5688
2018-05-14 23:28


起源

HTML实体有什么问题?他们绝对是特别适合非英语语言的方式...... - nico
熟悉的问题,我害怕我还没有解决它... - jeroen
@nico html实体没什么问题,只是我更喜欢输入时存储的数据,输出时可以通过htmlentities运行。这是我在启动网站后做出的选择,但需要对所有行进行标准化。 - TooManyCooks
@Chris将其保存在数据库中作为HTML实体,每次显示时都可以保存对htmlentities的调用。无论如何,我认为没有捷径可以做到这一点......在整个数据库中循环。 - nico
将HTML编码的数据放入数据库是疯狂的。很多时候输出不是HTML(例如,邮件地址,要获取的URL,要丢弃到某些CSV或PDF的数据,等等);此外,将编码数据保留在数据库中会破坏使用数据库级字符串处理功能的能力,包括各种匹配/索引。用于识别错误的OP +1!数据应保持原始形式,并且只有在插入到上下文中时才会针对特定上下文(例如HTML)进行转义。 - bobince


答案:


我最终使用了这个,不是很漂亮,但我很累,现在是凌晨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
            }
    }

5
2018-05-15 01:13



在 MySQL的 你可以生成一个列表 表 运用 SHOW TABLES; 并在 PostgreSQL的 生成一个列表 表 运用 SELECT table_name FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema') ORDER BY table_name ASC; 如果你想让脚本更有活力。 - John


由于PHP是编码方法,因此您需要使用它进行解码。您可以使用 html_entity_decode 将它们转换回原始字符。得循环!

请注意不要解码不需要它的行。不知道你将如何确定。


4
2018-05-14 23:29



是的,我知道函数的使用,如果我必须更新我将使用它的每一行,但我想知道在mysql或phpmyadmin中是否有更短的方法,即大规模更新在受影响的行上。他们隐藏了一些模糊不清的功能。 - TooManyCooks
@webbie至于你的编辑点,是的,我很幸运,我有我写的源和日志文件的旧备份,所以我知道代码被改变的时候,并且在那个时候围绕DB的行发出的声音也确认一下。 - TooManyCooks
呼。你做的好事! - webbiedave


我认为在这种情况下编写php脚本是件好事。正如Dave所说,您可以使用html_entity_decode()函数将文本转换回来。

首先在几个条目的表上尝试您的脚本。这将使您节省大量的测试时间。当然,记得在运行php脚本之前备份你的表。

我担心没有更短的可能性。无论您如何转换数据集,数百万行的计算仍然非常昂贵。所以去一个PHP脚本......这是最简单的方法


2
2018-05-14 23:34



是的,这是我怀疑的,但是我一直希望它是某种有用的功能phpmyadmin可能隐藏在某个地方,而不是自己做。至少如果我写它,我可以分享它。 - TooManyCooks
我明白了...我想说的是,即使phpMyAdmin有这样的功能(它可能有),它只会通过php执行一个mysql查询。您不会在执行时间和/或资源方面保存任何内容。但我认为在这种情况下编写脚本不应该那么难,你会得到很好的数据集:) - Simon


它有点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);
}

这是简化的,没有错误处理等。 不确定数百万行的处理时间是多少,因此您可能需要将其分解为块以避免脚本超时。


0
2018-05-15 01:10





我有同样的问题。由于我有多个客户端在生产中运行应用程序,我想避免运行PHP脚本来为每个客户端清理数据库。

我想出了一个远非完美的解决方案,但却无痛苦地完成工作。

  1. 在插入数据之前跟踪代码中使用htmlentities()的所有位置,并删除它。
  2. 将“显示数据作为HTML”方法更改为以下内容:

    return html_entity_decode(htmlentities($ chaine,ENT_NOQUOTES),ENT_NOQUOTES);

撤消 - 重做过程有点荒谬,但它完成了这项工作。每次用户更新不正确的数据时,您的数据库都会慢慢清理。


0
2018-05-10 08:49





这是我的防弹版本。它遍历数据库中的所有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";
        }
    }
}
?>

干杯 罗兰


0
2017-11-01 21:58