防止wp_debug污染插件内的AJAX

时间:2015-04-14 作者:orionrush

我遇到了一个问题wp_debug 通知扰乱了我的ajax响应。

法典suggests 使用ob_clean 在返回或回应之前:

要解析AJAX,必须通过管理AJAX重新加载WordPress。php脚本,这意味着在初始页面加载中遇到的任何php错误也将出现在AJAX解析中。如果启用了error\\u报告,这些将被回送到输出缓冲区,从而用错误消息污染AJAX响应。

因此,在调试Ajax时必须小心,因为返回的任何PHP通知或消息都可能会混淆结果的解析或导致Javascript出错。

如果您无法消除这些消息,并且必须在启用调试的情况下运行,那么一个选项是在返回数据之前立即清除缓冲区。

因此,我在下面的ajax函数末尾完成了这项工作,但这会创建一个ob_clean(): failed to delete buffer. No buffer to delete.

虽然缓冲区可能是空的,但仍有错误消息进入我的响应中,法典似乎建议ob\\U clean将其清除。进一步Im使用exit() 返回结果,以及的手册页中的注释表明它也会刷新缓冲区。我知道有很多方法wp_config.phpconditionally disable wp_debug, 但我真的希望插件本身能够处理这个问题。

请原谅,我已经包含了下面的大部分函数。我只是不知道该怎么处理这件事。

/*
 * Process the ajax request
 * add_action(\'wp_ajax_title_check\', \'duplicate_title_check_callback\');
 * action must appear in the main plugin file, not in as separate ajax function file
 * 
 * @uses:       title_check
 * @global:     $wpdb
 * @wp-hook:    wp_ajax_title_check
 *
 */

    function duplicate_title_check_callback()
{
    global $wpdb;
    $title = $_POST[\'post_title\'];
    $post_id = $_POST[\'post_id\'];
    header(\'Content-Type: application/json\');
    $sim_query = "SELECT ID FROM $wpdb->posts WHERE post_status = \'publish\' AND post_type = \'venue\' AND post_title LIKE \'%%%s%%\' AND ID != \'%d\'";
    $sim_results = $wpdb->get_results( $wpdb->prepare( $sim_query, like_escape($title), $post_id ) );
    if ($sim_results)
    {
        $notice = array("head" => "Whooa there! We found the following venue(s) with a similar heading:", "foot" =>"Consider deleting any duplicates and/or moving this post to the trash.");
        foreach ($sim_results as $sim_result)
        {
            $venue[\'title\'] = get_the_title($sim_result->ID);
            $path = \'post.php?post=\' . $sim_result->ID . \'&action=edit\';
            $venue[\'link\'] = esc_url(admin_url($path));
            $venue[\'city\'] =  wpcf_api_field_meta_value( \'city\', $sim_result->ID );
            $venue[\'ID\'] =  $sim_result->ID;
            $posts[] = $venue;
        }
        $return_json = array("status" => "true", "notice" => $notice, "posts"=>$posts );
    } else {
        $return_json = array("status" => "false", "notice" => "This Venue title looks unique!");
    }
    ob_clean();
    exit(json_encode($return_json)); // This should flush buffers to default point http://php.net/manual/en/function.exit.php#101204
    //echo(json_encode($return_json)); // Same result
    wp_die(); // terminate the wp instance, exit should be sufficient.
}
我还看到:How to define WP_DEBUG as true outside of wp-config.php?

编辑:根据@Czerspaluate的建议和@bosco的一篇伟大的文章,这就是我现在的想法。一些级联错误在很大程度上是问题所在,但更全面地实现bosco的“更健壮”方法实际上可以捕获并记录错误。原则上我理解,但鉴于我目前的经验,我不希望if( ob_get_length() ) ob_clean(); 实际清除缓冲区,因为到目前为止它还没有工作。但这是朝着正确的方向迈出的一步,并且假设检查将头调用返回到更合适的位置,这也是一个加号。先生们,谢谢。

function duplicate_title_check_callback()
{
    global $wpdb;
    $title = $_POST[\'post_title\'];
    $post_id = $_POST[\'post_id\'];
    $sim_query = "SELECT ID FROM $wpdb->posts WHERE post_status = \'publish\' AND post_type = \'venue\' AND post_title LIKE \'%%%s%%\' AND ID != \'%d\'";
    $sim_results = $wpdb->get_results( $wpdb->prepare( $sim_query, $wpdb->esc_like($title), $post_id ) );
    if ($sim_results)
    {
        $notice = array("head" => "Whooa there! We found the following venue(s) with a similar heading:", "foot" =>"Consider deleting any duplicates and/or moving this post to the trash.");
        foreach ($sim_results as $sim_result)
        {
            $venue[\'title\'] = get_the_title($sim_result->ID);
            $path = \'post.php?post=\' . $sim_result->ID . \'&action=edit\';
            $venue[\'link\'] = esc_url(admin_url($path));
            $venue[\'city\'] =  wpcf_api_field_meta_value( \'city\', $sim_result->ID );
            $venue[\'ID\'] =  $sim_result->ID;
            $posts[] = $venue;
        }
        $return_json = array("status" => "true", "notice" => $notice, "posts"=>$posts );
    }
    else
    {
        $return_json = array("status" => "false", "notice" => "This Venue title looks unique!");
    }
    if( ob_get_length() )
        ob_clean();
        header(\'Content-Type: application/json\');
        // http://php.net/manual/en/function.exit.php#101204
        exit(json_encode($return_json));

}

1 个回复
最合适的回答,由SO网友:bosco 整理而成

“如何防止意外输出到达浏览器/干扰AJAX响应?”

安装中的问题是产生“意外输出”,也就是说,如果WordPress运行顺利,它会创建不应该存在的内容或数据。这可能意味着服务器环境配置错误、WordPress安装错误、数据库连接错误、插件陈旧、主题试图在不应该显示的情况下显示内容,或者您自己的代码中存在问题—关键是,由于任何原因生成的错误、内容或通知都会在不应该出现的地方弹出。

最稳定的WordPress环境往往是那些不产生无关输出或消息的环境,即使在WP_DEBUG 已启用;因此,最好的做法是检查意外的输出,确定其来源,并解决问题,以便唯一的输出是正确、干净的响应。理想情况下,生产安装不应产生任何错误、警告或通知。

然而,在开发过程中,暂时忽略来自您当前未处理的源或您无法控制的源的意外输出可能是有益的(例如,如果源是另一个团队成员的责任,或者您必须处理的主题,但尚未收到预期的更新)。如果生产中出现非关键性错误,您当然不希望它们干扰最终用户的体验;最好的做法是将它们记录到文件中,以便以后处理它们。

The fact remains: the only true solution is to locate the individual problems creating unexpected output and solve them one-by-one. 其他一切都应该被视为暂时的“黑客”

简而言之,要回答您的问题,ob_clean() 如果没有缓冲区或缓冲区为空,则确实会失败。如果在成功调用后仍收到意外输出ob_clean(), 这意味着您的代码正在以某种方式创建输出—在提供的代码中,可能是调用exit(json_encode($return_json));, 或者甚至是对ob_clean() 它本身添加一个只清理预先存在的非空缓冲区的检查可能是您正在寻找的解决方案(在旁注中,放置header(\'Content-Type: application/json\'); 在输出响应之前立即调用以防止ob_clean() 在嵌套缓冲区或任何header()-相关错误):

if( ob_get_length() )
  ob_clean();

header(\'Content-Type: application/json\');
echo json_encode( $return_json );
exit;
如果此时仍收到意外输出,json_encode() 很可能因为试图处理$return_json - 再次检查变量的内容,并json_encode()\'s要求。

如果问题仍然存在,强制将输出缓冲区与上述内容结合使用可能会解决问题。This is more of a speculative hack than a legitimate solution, though, and would best be avoided. 请尝试以下操作之一:

更改php.ini 配置文件(位置依赖于服务器环境)并重新启动Web服务器:output_buffering onwp-config.php: ini_set( \'output_buffering\', \'on\' );<如果不行,只需拨打ob_start() 在同一个文件中可能会产生结果,但有干扰更复杂的环境和安装的风险.htaccess WordPress安装根目录中的文件:

<IfModule mod_php5.c> php_value output_buffering On </IfModule>

如果以上都不起作用,恐怕我已经没有主意了!

一个更强大的黑客,我在开发自己的插件时,采用了一种复杂的方法来解决这个潜在的问题,考虑到其他超出我控制范围的代码可能会产生意想不到的输出,就像我自己的一样-我必须承认,它还没有经过彻底的测试,但到目前为止对我很有用。毫无疑问,有更简单的解决方案,但我打算提供一种比法典建议的更有用的方法。我相当肯定我自己的实现也有很大的改进空间。

PHP使用一堆嵌套的输出缓冲区控制输出,根据安装和启用的服务器和PHP扩展(以及PHP脚本本身的功能),其他缓冲区可能位于PHP默认缓冲区之上。或者甚至可能没有输出缓冲区(如果PHP ini指令output_buffering 已禁用,并且脚本本身尚未创建)。

I should note that several PHP extensions use buffers to do things like URL rewriting and output compression - my solution below should be used for troubleshooting and development purposes only, as will almost certainly prevent these mechanisms from functioning properly on your AJAX responses. 通常这种影响可以忽略不计,但它会在更复杂的环境和站点中产生问题。抄本中描述的黑客也有类似的风险,尽管风险较小,因为它并没有像我一样完全删除缓冲区。

因此,当我开始调试AJAX处理程序时,我首先转储任何嵌套缓冲区的内容,并明确地从堆栈中丢弃每个缓冲区,然后使用最上面的缓冲区(如果不存在,则创建一个)捕获在处理AJAX请求过程中生成的任何消息(以及预先存在的顶级缓冲区中包含的任何消息):

if( defined( \'DOING_AJAX\' ) && DOING_AJAX ) {
  $bufferContents = array();

  // Capture nested buffer contents and discard them
  while( 1 < ob_get_level() )
    $bufferContents[] = ob_get_clean();

  // Ensure that a top-level buffer is available to capture any unexpected output
  if( ! ob_get_level() )
    ob_start();
}
The$bufferContents 然后,如果需要,可以将数组写入调试日志,或记录到其他地方以供参考。

处理完请求后,在调度响应之前,我捕获了新的顶级缓冲区的内容,该缓冲区现在包含与AJAX处理程序脚本相关的任何意外输出:

// If the output buffer contains data, get rid of it to prevent mucking up the JSON response
if( 0 < ( $bufferLength = ob_get_length() ) ) {
  $bufferContents = ob_end_clean();
}

header( "Content-Type: application/json" );
echo $ajaxResponse;
exit;
再一次$bufferContents 变量可能包含有用的信息,可以根据需要进行处理。

更具体地说,我喜欢用JSON对象响应AJAX请求-启用调试后,我会将缓冲区的内容附加到对象中,这样我就可以在Chrome的检查器控制台中对其进行检查,并将其保存到文件中,无论是否启用调试。例如:

$ajaxResponse  = array(
  \'status\' => $status || \'error\',
  \'data\'   => $response
);

// If the output buffer contains data, get rid of it to prevent mucking up the JSON response
if( 0 < ( $bufferLength = ob_get_length() ) ) {
  $bufferContents = ob_end_clean();

  // If debugging is enabled, pass any unexpected output to the client in the form of an additional \'phpBuffer\' property
  if( WP_DEBUG ) {
    $ajaxResponse[ \'phpBuffer\' ] => $bufferContents;
  }

  // Take note of the situation in the log files
  if( WP_DEBUG_LOG ) {
    $bufferLogFile  = plugin_dir_path( __FILE__ ) . \'debug.buffer.log\';
    $bufferContents = date(\'m/d/Y h:i:s a\', time()) . \':\' . chr(10) . $bufferContents . chr(10) . chr(10);

    error_log( $bufferLength . \' characters of unexpected output were generated while processing an AJAX request in "\' . plugin_dir_path( __FILE__ ) . __FILE__ . \'". They have been recorded in "\' . $bufferLogFile . \'".\';

    // Save the buffer contents to file.
    file_put_contents( $bufferLogFile, $bufferContents, FILE_APPEND );
  }
}

header( "Content-Type: application/json" );
echo json_encode( $ajaxResponse );
exit;

结束

相关推荐

致命错误:使用AJAX调用未定义的函数get_post()

我有一个index.php 带有about链接的页面,可以从WordPress仪表板中创建的名为about的页面(帖子)获取作者内容。我正在使用Magnific Popup poups插件。我有about.php 其中包括以下关于页面的内容:<?php $pageid = 2; // 2 is the id of about page/post $about = get_post($pageid); ?> <div id=\"custo