rosell-dk / exec-with-fallback
具有回退到模拟(proc_open等)的exec()函数
Requires
- php: ^5.6 | ^7.0 | ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.11
- phpunit/phpunit: ^9.3
- squizlabs/php_codesniffer: 3.*
Suggests
- php-stan/php-stan: Suggested for dev, in order to analyse code before committing
README
某些共享主机可能已禁用 exec(),但保留了 proc_open()、passthru()、popen() 或 shell_exec()。如果您想轻松地使用其中之一模拟 exec(),您已经找到了正确的库。
如果您正在编写旨在在广泛系统上运行的代码,则此库很有用,因为它可以使您的exec()调用在这些系统上成功。
用法
只需将当前的 exec() 调用替换为 ExecWithFallback::exec()。签名完全相同。
use ExecWithFallback\ExecWithFallback; $result = ExecWithFallback::exec('echo "hi"', $output, $result_code); // $output (array) now holds the output // $result_code (int) now holds the result code // $return (string | false) is now false in case of failure or the last line of the output
请注意,尽管签名相同,但错误并不完全相同。这是有原因的。在某些系统上,当函数被禁用时,真实的 exec()
调用会导致致命错误。也就是说:无法捕获的错误。您可能不希望在某些系统上停止执行,但在其他系统上则不希望如此。但如果你这样做,请使用 ExecWithFallback::execNoMercy
而不是 ExecWithFallback::exec
。如果没有可用的模拟,它将调用 exec,确保与正常 exec 相同的错误处理。
如果您在代码中有 function_exists('exec')
,您可能希望将它们更改为 ExecWithFallback::anyAvailable()
安装
composer require rosell-dk/exec-with-fallback
实现
ExecWithFallback::exec() 首先检查 exec() 是否可用,如果可用则调用它。如果 exec 不可用(在服务器上已禁用),或exec()返回false,则继续检查 passthru() 是否可用,依此类推。顺序如下:
- exec()
- passthru()
- popen()
- proc_open()
- shell_exec()
如果所有函数都不可用,则抛出一个正常异常(类:Exception)。这比真正的exec()更温和,在有些系统上,当函数被禁用时,它抛出致命错误。如果您需要完全相同的错误,请使用 ExecWithFallback::execNoMercy
,它将抛出异常而不是调用 exec,这将导致抛出异常(为了支持旧版PHP,您需要捕获Exception和Throwable。请注意,您无法在所有系统上捕获,因为有些抛出致命错误)。
如果没有成功,但至少有一个通过返回false失败,则返回false。再次模仿 exec() 的行为。
PS:由于 shell_exec() 不支持 $result_code,它只有在未提供 $result_code 时才会使用。system() 未实现,因为它无法返回输出结果的最后一行,并且没有方法检测您的代码是否依赖于该功能。
如果您出于某种原因想要运行特定的exec()模拟,您可以直接使用相应的类,例如 ProcOpen::exec()。
这值得吗?
好吧,通常这些函数要么全部启用,要么全部禁用。因此,在大多数系统上,这不会造成任何区别。但另一方面:此库易于安装,非常轻量级,并且经过彻底测试。
易于安装
使用composer安装(composer require rosell-dk/exec-with-fallback
)并替换您的 exec() 调用。
轻量级
该库非常轻量。如果exec()可用,则立即调用,并且只自动加载主文件。如果所有这些都不可用,它只花费一点点循环,总共五次function_exists()调用,并且再次,只自动加载主文件。如果exec()不可用,但其中之一可用,则仅自动加载该实现,除了主文件。
经过充分测试
我确保该函数的行为与exec()完全一致,并编写了大量的测试用例。它在ubuntu、windows、mac(多个版本)上进行了测试。它在PHP 5.6、7.0、7.1、7.2、7.3、7.4、8.0、8.1和8.2上进行了测试。它在禁用不同功能的组合中进行了测试(即“exec”被禁用、“passthru”被禁用,以及“exec”和“passthru”都被禁用等)。在每次发布之前都会运行这些组合的巨大测试。此外,每月还会测试具有未来PHP版本的夜间构建,这使我能够及早发现潜在问题。状态:
将得到维护
该库在webp-convert和webp-express中使用,这两个库都用于许多项目。因此,它得到了广泛的应用,并且任何未来的问题都注定会被发现。虽然我不认为这个项目需要太多的维护,但如果需要,它将会在那里。
缺点:被识别为恶意软件的风险存在一点风险,即懒惰的恶意软件制作者会使用这个库来制作恶意软件。然而,风险非常小,因为这个库不适合恶意软件。首先,这个库不尝试system(),因为这个函数不返回输出,因此不能用来模拟exec()。恶意软件制作者会希望尝试所有可能的方式执行他的恶意软件。其次,恶意软件制作者可能不会使用composer来制作恶意软件,并且可能希望有一个单一的功能,而不是分散在多个文件中。第三,这个库在确保模拟的函数与exec()的行为完全一致上投入了大量精力。对于恶意软件制作者来说,这个担忧可能不存在,他们可能更关心恶意软件运行的效果。最后,恶意软件制作者可能想要编写自己的函数,而不是复制从互联网上找到的代码。复制东西会带来一种可能性,即代码会被另一个恶意软件制作者使用,这增加了反恶意软件软件将其识别为恶意软件的风险。
你喜欢我所做的事情吗?
也许你想要支持我的工作,这样我就可以继续这样做:
谢谢!