“如何防止意外输出到达浏览器/干扰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 on
尝试在脚本级别启用输出缓冲。将以下行添加到wp-config.php
: ini_set( \'output_buffering\', \'on\' );
<如果不行,只需拨打ob_start()
在同一个文件中可能会产生结果,但有干扰更复杂的环境和安装的风险如果PHP作为Apache模块运行,则可以从.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;