17

背景:我下载了我的 WordPress 站点数据库的*.sql备份,并将旧数据库表前缀的所有实例替换为一个新实例(例如,从默认wp_到类似asdfghjkl_)。

我刚刚了解到 WordPress 在数据库中使用了序列化的 PHP 字符串,而我所做的将会破坏序列化字符串长度的完整性。

问题是,我在得知这一点之前删除了备份文件(因为我的网站仍然运行良好),并从那时起安装了许多插件。因此,我无法恢复原状,因此我想知道两件事:

  1. 如果可能的话,我该如何解决这个问题?

  2. 这会导致什么样的问题?

这篇文章指出,例如 WordPress 博客,可能会丢失其设置和小部件。但这似乎并没有发生在我身上,因为我博客的所有设置仍然完好无损。但我不知道有什么可能在内部被打破,或者它在未来会带来什么问题。因此这个问题。)

4

6 回答 6

19

访问此页面:http ://unserialize.onlinephpfunctions.com/

在该页面上,您应该看到这个示例序列化字符串:a:1:{s:4:"Test";s:17:"unserialize here!";}。拿一块—— s:4:"Test";。这意味着“字符串”,4 个字符,然后是实际的字符串。我很确定您所做的事情导致数字字符计数与字符串不同步。使用上述网站上的工具,例如,如果将“Test”更改为“Tes”,您会看到出现错误。

您需要做的是让这些字符数与您的新字符串匹配。如果您没有损坏任何其他编码(删除冒号或其他内容),那应该可以解决问题。

于 2013-02-28T15:34:36.377 回答
11

在尝试将域从 localhost 更改为真实 URL 后,我遇到了同样的问题。经过一番搜索,我在 Wordpress 文档中找到了答案:

https://codex.wordpress.org/Moving_WordPress

我将引用那里写的内容:

为避免该序列化问题,您有以下三种选择:

  • 如果可以 > 访问您的仪表板,请使用 Better Search Replace 或 Velvet Blues Update URLs 插件。
  • 如果您的托管服务提供商(或您)已安装 WP-CLI,请使用 WP-CLI 的搜索替换。
  • 在您的数据库上手动运行搜索和替换查询。注意:仅对 wp_posts 表执行搜索和替换。

我最终使用了 WP-CLI,它能够在不破坏序列化的情况下替换数据库中的内容: http ://wp-cli.org/commands/search-replace/

于 2015-09-22T18:56:26.260 回答
3

我知道这是一个老问题,但我想迟到总比没有好。我最近遇到了这个问题,在继承了一个对序列化数据执行了查找/替换的数据库之后。经过几个小时的研究,我发现这是因为字符串计数关闭了。不幸的是,有很多数据有很多转义和换行符,在某些情况下我不知道如何计算,而且我有很多数据,我需要一些自动化的东西。

一路上,我偶然发现了这个问题,Benubird 的帖子帮助我走上了正确的道路。他的示例代码不适用于复杂数据的生产使用,包含大量特殊字符和 HTML,嵌套非常深,并且不能正确处理某些转义字符和编码。因此,我对其进行了一些修改,并花费了无数个小时来解决其他错误,以使我的版本“修复”序列化数据。

// do some DB query here
while($res = db_fetch($qry)){
    $str = $res->data;
    $sCount=1; // don't try to count manually, which can be inaccurate; let serialize do its thing
    $newstring = unserialize($str);
    if(!$newstring) {
        preg_match_all('/s:([0-9]+):"(.*?)"(?=;)/su',$str,$m);
#           preg_match_all("/s:([0-9]+):(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")(?=;)/u",$str,$m); // alternate: almost works but leave quotes in $m[2] output
#           print_r($m); exit;
        foreach($m[1] as $k => $len) {
            /*** Possibly specific to my case: Spyropress Builder in WordPress ***/
            $m_clean = str_replace('\"','"',$m[2][$k]); // convert escaped double quotes so that HTML will render properly
            // if newline is present, it will output directly in the HTML
            // nl2br won't work here (must find literally; not with double quotes!)
            $m_clean = str_replace('\n', '<br />', $m_clean); 
            $m_clean = nl2br($m_clean);  // but we DO need to convert actual newlines also
            /*********************************************************************/
            if($sCount){
                $m_new = $m[0][$k].';'; // we must account for the missing semi-colon not captured in regex!
                // NOTE: If we don't flush the buffers, things like <img src="http://whatever" can be replaced with <img src="//whatever" and break the serialize count!!!                  
                ob_end_flush(); // not sure why this is necessary but cost me 5 hours!!
                $m_ser = serialize($m_clean);
                if($m_new != $m_ser) {
                    print "Replacing: $m_new\n";
                    print "With: $m_ser\n";
                    $str = str_replace($m_new, $m_ser, $str);
                }
            }
            else{
                $m_len = (strlen($m[2][$k]) - substr_count($m[2][$k],'\n'));
                if($len != $m_len) {
                    $newstr='s:'.$m_len.':"'.$m[2][$k].'"';
                    echo "Replacing: {$m[0][$k]}\n";
                    echo "With: $newstr\n\n";
                    $str = str_replace($m_new, $newstr, $str);
                }
            }
        }
        print_r($str); // this is your FIXED serialized data!! Yay!
    }
}

关于我的更改的一些令人讨厌的解释:

  • 我发现尝试以 Benubird 的代码为基础进行计数对于大型数据集来说太不准确了,所以我最终只使用序列化来确保计数是准确的。
  • 我避免了 try/catch,因为在我的情况下,try 会成功,但只是返回一个空字符串。因此,我改为检查空数据。
  • 我尝试了许多正则表达式,但只有 Benubird 上的一个 mod 可以准确处理所有情况。具体来说,我必须修改检查“;”的部分 因为它会在 CSS 上匹配,例如 "width:100%; height:25px;" 并打破了输出。所以,我使用了积极的前瞻来匹配“;” 在双引号集之外。
  • 我的案例有很多换行符、HTML 和转义的双引号,所以我必须添加一个块来清理它们。
  • 有一些奇怪的情况,数据会被正则表达式错误地替换,然后序列化也会错误地计算它。我在任何网站上都找不到任何帮助解决此问题的方法,最后认为它可能与缓存或类似的东西有关,并尝试刷新输出缓冲区(ob_end_flush()),这很有效,谢天谢地!

希望这对某人有所帮助...花了我将近 20 个小时,包括研究和处理奇怪的问题!:)

于 2016-04-03T03:19:33.410 回答
2

此脚本 ( https://interconnectit.com/products/search-and-replace-for-wordpress-databases/ ) 可以帮助在任何地方使用适当的 URL 更新 sql 数据库,而不会遇到序列化数据问题,因为它将更新“字符数”,这可能会在出现序列化数据时使您的 URL 不同步。

步骤是:

  1. 如果您已经导入了一个混乱的数据库(小部件不工作,主题选项不存在等),只需使用 PhpMyAdmin 删除该数据库。也就是说,删除上面的所有内容。然后导出并获得旧数据库的未经编辑的转储。

  2. 现在您必须将(未编辑的)旧数据库导入新创建的数据库。您可以通过导入或从 PhpMyAdmin 复制数据库来执行此操作。请注意,到目前为止,我们还没有进行任何搜索和替换;我们只是将旧的数据库内容和结构放入具有自己的用户和密码的新数据库中。此时您的网站可能无法访问。

  3. 确保您已将 WordPress 文件新上传到服务器上的正确文件夹,并编辑您的 wp-config.php 以使其与新数据库连接。
  4. 将脚本上传到与 wp-admin、wp-content 和 wp-includes 相同级别的“秘密”文件夹中 - 只是出于安全原因。一旦发生搜索和替换,不要忘记将其全部删除,因为您可能会将您的数据库详细信息提供给整个互联网。
  5. 现在将您的浏览器指向秘密文件夹,并使用脚本的精细界面。这是非常不言自明的。使用后,我们将继续将其从服务器中完全删除。

这应该可以正确更新您的数据库,而不会出现任何序列化数据问题:新的 URL 将在任何地方设置,并且序列化数据字符数将相应更新。

小部件和主题设置将被传递——这是 WordPress 中使用序列化数据的两个典型位置。

完成并经过测试的解决方案!

于 2018-02-08T02:10:25.190 回答
1

如果错误是由于字符串的长度不正确(我经常看到的),那么您应该能够调整此脚本来修复它:

foreach($strings as $key => $str)
{
    try {
        unserialize($str);
    } catch(exception $e) {
        preg_match_all('#s:([0-9]+):"([^;]+)"#',$str,$m);
        foreach($m[1] as $k => $len) {
            if($len != strlen($m[2][$k])) {
                $newstr='s:'.strlen($m[2][$k]).':"'.$m[2][$k].'"';
                echo "len mismatch: {$m[0][$k]}\n";
                echo "should be:    $newstr\n\n";
                $strings[$key] = str_replace($m[0][$k], $newstr, $str);
            }
        }
    }
}
于 2016-01-04T09:30:13.823 回答
1

我个人不喜欢在 PHP 中工作,也不喜欢将我的数据库凭据放在公共文件中。我创建了一个 ruby​​ 脚本来修复可以在本地运行的序列化:

https://github.com/wsizoo/wordpress-fix-serialization

上下文编辑:我通过首先通过正则表达式识别序列化,然后重新计算所包含数据字符串的字节大小来解决序列化问题。

$content_to_fix.gsub!(/s:([0-9]+):\"((.|\n)*?)\";/) {"s:#{$2.bytesize}:\"#{$2}\";"}

然后我通过转义的 sql 更新查询更新指定的数据。

escaped_fix_content = client.escape($fixed_content)

query = client.query("UPDATE #{$table} SET #{$column} = '#{escaped_fix_content}' WHERE #{$column_identifier} LIKE '#{$column_identifier_value}'")
于 2016-10-13T23:14:43.950 回答