提问人:RobertPitt 提问时间:7/2/2011 最后编辑:PaulGRobertPitt 更新时间:8/4/2014 访问量:20165
在 PHP 中禁用 echo 和 print
Disable echo and print in PHP
问:
这似乎是一个有趣的问题,但实际上并非如此,我想禁用 ,以及其他可能输出到缓冲区的函数,例如 .echo
print
readfile
我想这样做的原因是为了防止客户端使用或超出我的应用程序的规则,迫使他们编译其内容并将其发送到输出类,以便管理整个缓冲区。echo
print
现在我知道我可以在脚本开始时设置一个输出缓冲区并丢弃任何内容,但这不包括 和 之类的内容,所以我的问题可以解释为如何控制响应头的缓冲区header
set_cookie
有没有可能的方法来管理PHP输出的所有方面,例如将回调分配给主缓冲区,而不仅仅是响应正文?
答:
最后,没有有效的方法可以实现这一点,因为至少不是一个函数,而是一个语言结构,不能被禁用。您可以使用输出缓冲(等),但这不会阻止其他代码再次禁用输出缓冲。echo
ob_start()
在我看来,没有办法,只能确保只有“好的代码”。我不知道,你说的“阻止客户端”是什么意思,但无论如何我都不会执行任意代码。如果它是由纪律严明的开发人员编写并经过测试的,那么应该没有问题。
评论
echo
echo
headers already sent
除了编辑和重新编译之外,我不相信您可以禁用输出的函数。对于绕过输出缓冲的函数,您的 SOL.
但是,您可以使用内联输出缓冲来控制非标头输出。最好的部分是它的嵌套功能:
ob_start();
echo 'The first output!',"\n";
ob_start();
echo 'The second output.';
$output2 = ob_get_clean();
ob_flush();
echo $output2;
将输出:
The first output!
The second output.
评论
您想要做的事情 - 防止在运行时输出 - 是不可能的。它只是不会发生。不过,如果您执行以下两项操作,则可以非常接近:审核代码中是否有可以产生输出的关键字,以及缓冲输出,同时阻止访问输出缓冲区控制函数。
- 以编程方式审核代码,以确保不存在某些无法捕获的情况(由您来有效地缓存审核结果,或者只是在每次页面视图上承担审核成本 - 不推荐)。
您可以使用 token_get_all()
来审核输出关键字,例如 and(此处是所有可能的标记的列表)。不要试图在这里禁用对关键字以外的任何内容的访问,有太多方法可以欺骗它(变量、data:// 流等)您只在此处屏蔽了某些关键字。T_ECHO
T_PRINT
eval()
不要忘记 、 、 和 。这些不仅可以用于包含未经审计的代码(例如写入临时文件的 PHP 代码),而且使用一些更高级的文件包装器,这些代码本身可用于生成输出。T_INCLUDE
T_INCLUDE_ONCE
T_REQUIRE
T_REQUIRE_ONCE
使用 PHP ADB 扩展通过重命名某些方法来禁用对它们的访问。不要尝试禁用输出函数,它只是行不通,生成输出的方法太多了。挑选出像 和 这样的特殊方法,但对于实际输出,有无数种方法可以产生输出。阻止这种情况的唯一可靠方法是使用输出缓冲,但禁用对输出缓冲器控制方法的访问,以便它们无法绕过缓冲。
set_cookie()
header()
class YourApplicationControllingClass { final protected function callUserCode($pathToUserCodeFile) { // We want this to be a local variable so there's no way to get to it // with PHP Reflection $suspender = new SuspendFunctions(); ob_start(); // You may need to add more here, this is just my superficial pass $suspender->suspend("ob_clean", "ob_end_clean", "ob_end_flush", "ob_flush", "ob_get_clean", "ob_get_contents", "ob_get_flush", "ob_get_length", "ob_get_level", "ob_get_status", "ob_implicit_flush", "ob_list_handlers", "ob_start", "output_add_rewrite_var", "output_reset_rewrite_vars", "set_cookie", "set_raw_cookie", "header_register_callback", "header", "header_remove", "http_response_code", "register_shutdown_function", "register_tick_function", "unregister_tick_function", "set_error_handler", "restore_error_handler", "set_exception_handler", "restore_exception_handler" ); $this->callUserCodeSandbox($pathToUserCodeFile); // Restore our original execution environment $suspender->resume(); $content = ob_get_clean(); // If you want to be aggressive, check to see if they produced any output // and blacklist them if they even try. if ($content !== '') $this->blacklistUserCode($pathToUserCodeFile); } private function callUserCodeSandbox($pathToUserCodeFile) { require($pathToUserCodeFile); } } final class SuspendFunctions { private $suspendedFunctions = array(); /** * Suspends certain functions from being executable. * @param string $function,... Names of functions to suspend, you may pass multiple * @return void */ function suspend($function) { $functions = func_get_args(); foreach($functions as $function) { // Make sure we don't double-suspend a function if (isset($this->suspendedFunctions[$function])) continue; // Make new names unguessable, and make it very unlikely that we end up with a collision. $newName = '_'.md5($function.microtime(true).mt_random()); // Rename to the unguessable name rename_function($function, $newName); // Keep a record for ourselves what this new name is so we can resume later $this->suspendedFunctions[$function] = $newName; } } /** * Resumes functions for calling */ function resume() { foreach($this->suspendedFunctions as $function=>$newName) { rename($newName, $function); unset($this->suspendedFunctions[$function]); } } }
请注意,无论您在这方面有多擅长,几乎肯定会有一种方法可以绕过(例如,也许他们的代码会修补您的应用程序文件之一的内容以再次允许输出)。PHP太灵活了,无法牢牢地锁定它。PHP有一个类似的项目,叫做安全模式,他们最终放弃了这个项目,因为不可能完全安全地锁定所有东西。只要用户有一个完整的执行环境,你可以做任何事情来阻止他们,他们都可以撤消。一般来说,在不手动审核每一行的情况下执行用户贡献的代码是非常不明智的(甚至很危险)。
这样做:
function trace($message) {
$echo = true;
if ($echo)
echo $message . "<br>";
}
然后只需调用trace(“your message”);在需要时随时,$echo 切换到 false 以全局禁用它
下一个:在框架中创建模块系统
评论