首页 > php > WordPress 2.5.1 500 错误解决方法

WordPress 2.5.1 500 错误解决方法

随时听人讲有500错误。
今天在楚云blog上重现了。
抓住机会debug。
结果很快出来:
当你第二次用同样的标题并且标题中含有多字节文字时,有很大机会触发wp一个死循环,然后服务器cpu直接到100%,当运行时间超过max_execution_time时候出现500错误。
死循环在这里:wp-include/post.php

<?php
......
if ( 'draft' != $post_status ) {
    $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d AND post_parent = %d LIMIT 1", $post_name, $post_type, $post_ID, $post_parent));

    if ($post_name_check || in_array($post_name, $wp_rewrite->feeds) ) {
        $suffix = 2;
        do {
            $alt_post_name = substr($post_name, 0, 200-(strlen($suffix)+1)). "-$suffix";
            // expected_slashed ($alt_post_name, $post_name, $post_type)
            $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = '$alt_post_name' AND post_type = '$post_type' AND ID != %d AND post_parent = %d LIMIT 1", $post_ID, $post_parent));
            $suffix++;
        } while ($post_name_check);
        $post_name = $alt_post_name;
    }
}

死循环触发点:wp-include/wp-db.php

<?php
......
/**
 * Prepares a SQL query for safe use, using sprintf() syntax
 */
function prepare($args=NULL) {
    if ( NULL === $args )
    return;
    $args = func_get_args();
    $query = array_shift($args);
    $query = str_replace("'%s'", '%s', $query); // in case someone mistakenly already singlequoted it
    $query = str_replace('"%s"', '%s', $query); // doublequote unquoting
    $query = str_replace('%s', "'%s'", $query); // quote the strings
    array_walk($args, array(&$this, 'escape_by_ref'));
    return @vsprintf($query, $args);
}

post_name 中的的多字节文字被 urlencode 成这样 "%e6%88%91%e6%93%8d%ef%bc%81",只要 % 后面跟了 bcdeufFosxX 中任意一个(覆盖了大半个中文区域),就造成 vsprintf 函数调用失败,返回 false,而上层的循环一直在等它返回一个非false的值,直到程序死掉。

解决方法很简单:
修改 wp-include/wp-db.php
用下面的代码替换掉之前贴出的代码:

<?php
......
/**
 * Prepares a SQL query for safe use, using sprintf() syntax
 */
function prepare($args=NULL) {
    if ( NULL === $args )
    return;
    $args = func_get_args();
    $query = array_shift($args);
    $query = str_replace("'%s'", '%s', $query); // in case someone mistakenly already singlequoted it
    $query = str_replace('"%s"', '%s', $query); // doublequote unquoting
    $query = str_replace('%s', "'%s'", $query); // quote the strings
    array_walk($args, array(&$this, 'escape_by_ref'));

    // 旧的方法会引起其他问题
    // $query = preg_replace("#(%[0-f]{2})#sie", "urldecode('$1')", $query);
    // $query = @vsprintf($query, $args);
    // $query = preg_replace("#([\x80-\xff])#se", "strtolower(urlencode('$1'))", $query);

    // 新的方法只针对重复标题时的死循环问题
    $reg = "#post_name = '((?:%[0-9a-f]{2})+.+)'#Usi";
    if (preg_match($reg, $query, $match)) {
        $he = $match[1];
        $hd = urldecode($he);
        $query = str_replace($he, $hd, $query);
        $query = @vsprintf($query, $args);
        $query = str_replace($hd, $he, $query);
    } else {
        $query = @vsprintf($query, $args);
    }

    return $query;
}

后来楚云坚持认为wp可以不用修改任何原始代码解决所有问题,所以找到了下面的方法:
下载这个文件:db.tgz 解压后得到 db.php 将它放到 wp-content/ 下。
---------
或许这只是其中一个造成500的原因,下次遇到再说吧。
--------- update --------
补充,此db.php为2.5.1的,后来才知道2.5.1比2.5.0也有更新,不保证其他版本没有意外情况。
--------- update 2008/05/10 --------
发现bug,更新了方法以及db.php下载链接。以前的方法太粗暴,一些其他的查询也被强制转码造成数据错误。
解决方法:重新下载db.php或按照前文代码重新修改wp-db.php。已经出错的数据,可重新编辑保存。已知会引发错误的地方:http://yourwpuri/wp-admin/widgets.php (也就是说你使用了之前的 db 文件后,有设置过 widgets 功能,最好重新设置一遍)

分类: php 标签:
  1. 2008年5月1日13:27 | #1

    一定要使用一模一样的多字节标题(比如中文),才会触发这个问题。

    所以每次保存草稿后发布就容易挂。

    可怜我的 blog 上很多同样标题的文章……

  2. 2008年5月2日01:46 | #2

    我的仅仅是在提交空的comment时会出现500 error。还在寻求解决方案

  3. 2008年5月2日03:12 | #3

    很好很强大:)

  4. 2008年5月30日01:22 | #4

    我遇到一些触发500 error的条件更加“丰富多彩”:更换外观、激活插件都可能造成500 error错误;请问如何显示debug信息?

  5. Kafeifei
    2008年5月31日00:33 | #5

    手动设断点调试,不过前题是能完整重现bug。

  6. 2008年6月27日16:28 | #6

    我前天更新了一遍文章的tag后也遇到同样的500报错,一步步echo的查代码对数据,最后发现表wp_options中的category_children这一行被删掉了.我只找出这一点变化,前后数据都一样.
    后来十再不高兴查了,重新当了个wp重装再还原以前的数据备份,ok了-_-

  7. Danny
    2008年7月25日01:15 | #7

    用了這解决方法後卻產生另一問題:permalink的設定不可更改,會出現:WordPress database error: [Query is empty] ... wp-admin/options-permalink.php

  8. 2008年8月7日11:20 | #8

    还是没有说清楚

  9. wangpei
    2008年8月8日22:01 | #9

    谢谢,我把这个茬给忘了。
    现在换回2.5,问题也解决了。

  10. 2009年6月13日07:22 | #10

    А вот по моему мнению, эта тема слишком сложная для новичка :)

  11. 2009年12月3日10:19 | #11

    widgets.php 已终止操作

  12. 2010年3月17日01:32 | #12

    路过,支持一下,O(∩_∩)O~ 站点很漂亮。

  13. 2010年9月8日14:36 | #13

    话说我的博客发表完文章就出现http://blog.rengang.org/post.php 500错误页面
    刷新下后台又出来了
    郁闷中
    2.92

  1. 2008年5月1日01:25 | #1
  2. 2008年5月1日01:26 | #2
  3. 2008年5月1日14:26 | #3
  4. 2008年5月10日22:31 | #4