0

所以场景是我有一个使用输出缓冲的应用程序,除了预期的结果之外,该应用程序还返回了一些额外的数据。我可以操纵将预期结果添加到输出缓冲区的点,以确认在应用程序的这一点上,发送到输出缓冲区的数据是正确的,因此意外的额外数据必须来自另一个来源。

我怀疑这个问题是一个不在 PHP 脚本标签内的杂散字符,但我没有运气弄清楚哪些(如果有)文件是罪魁祸首。据我所知,可能包含一些文件实际上正在echo对额外数据进行显式处理。

所以我希望捕获写入输出缓冲区的任何文件的文件名和行号,但这证明比我预期的要困难得多。我知道首字母在哪里ob_start,所以我一直在尝试使用自定义output_callback. 以下是我已经尝试过的一些事情:

ob_start(function($string) { 
    return __FILE__ . ":" . __LINE__ . " : " $string; 
});

这将返回定义函数的文件名和行号,而不是调用它的位置(正如预期的那样,我猜,但开始不好)。

ob_start(function($string) { 
    return print_r(debug_print_backtrace(), true) . " : " $string; 
});

这会引发有关销毁 lambda 函数的错误。

ob_start(function($string) { 
    return var_dump(debug_backtrace()) . " : " $string; 
});

这有好坏参半的结果。我承认我不完全确定为什么。但在大多数情况下,var_dump解析为一个空字符串(什么都没有),但在一种情况下,它似乎生成了一些跟踪数组,但没有任何反映 ob_start 调用来源的东西(换句话说,无论它输出什么,实际调用的源文件echo不是跟踪的一部分)。

请记住,根据上述内容,我一直在进行一些非常基本的测试,只是为了弄清楚output_callback当我准备将其放入故障排除上下文时自定义函数会是什么样子。所以这个问题不是特定于应用程序的,我只是想找到一种通用的方法来拦截输出函​​数(echo、print 等)并获取有关输出调用起源的信息。

4

1 回答 1

2

可能的解决方案

1

如果您的代码使用输出缓冲来吐出该杂散字符,则以下解决方案可以提供帮助。您也是对的,它仅在刷新/检索输出缓冲时才起作用,而不是在每个 print/echo 语句中。此外,所有本机函数都不能在回调函数中工作,并且 print_r是其中之一,但我们可以抛出Exception. 请尝试以下代码,看看它是否可以帮助您解决问题。

ob_start(function($buffer) {
    try {
        $stackTrace = debug_print_backtrace();
        throw new \Exception($stackTrace, 1);
    } catch (\Exception $ex) {
        //This line can be logged to a file instead of appending to the buffer
        $buffer .= PHP_EOL.$ex->getTraceAsString().PHP_EOL.PHP_EOL;
    }
    return $buffer;
});

2

如果第一个解决方案不能帮助解决您的问题,您可能需要使用高级调试和分析工具,例如Xdebug

3

如果您真的不关心在当前行之前已经回显的内容,或者如果您想将来证明类似的问题将来不会发生,您可以在 ob_start 之前使用 ob_end_clean 清除缓冲区。

ob_end_clean();
ob_start();

4

在结束标记后查找所有 PHP 空白:

pcregrep -rMl '\?>[\s\n]+\z' *

或者

pcregrep -rM '\?>[\s]+[^\S]*$' *.php
于 2017-12-14T03:35:45.357 回答