rosell-dk/exec-with-fallback

具有回退到模拟(proc_open等)的exec()函数

1.2.0 2021-12-08 12:09 UTC

This package is auto-updated.

Last update: 2024-09-06 18:01:10 UTC


README

Latest Stable Version Minimum PHP Version Build Status Coverage Software License Daily Downloads

某些共享主机可能已禁用 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版本的夜间构建,这使我能够及早发现潜在问题。状态:Giant test PHP 8.3 nightly PHP 8.4 nightly

将得到维护
该库在webp-convertwebp-express中使用,这两个库都用于许多项目。因此,它得到了广泛的应用,并且任何未来的问题都注定会被发现。虽然我不认为这个项目需要太多的维护,但如果需要,它将会在那里。

缺点:被识别为恶意软件的风险存在一点风险,即懒惰的恶意软件制作者会使用这个库来制作恶意软件。然而,风险非常小,因为这个库不适合恶意软件。首先,这个库不尝试system(),因为这个函数不返回输出,因此不能用来模拟exec()。恶意软件制作者会希望尝试所有可能的方式执行他的恶意软件。其次,恶意软件制作者可能不会使用composer来制作恶意软件,并且可能希望有一个单一的功能,而不是分散在多个文件中。第三,这个库在确保模拟的函数与exec()的行为完全一致上投入了大量精力。对于恶意软件制作者来说,这个担忧可能不存在,他们可能更关心恶意软件运行的效果。最后,恶意软件制作者可能想要编写自己的函数,而不是复制从互联网上找到的代码。复制东西会带来一种可能性,即代码会被另一个恶意软件制作者使用,这增加了反恶意软件软件将其识别为恶意软件的风险。

你喜欢我所做的事情吗?

也许你想要支持我的工作,这样我就可以继续这样做:

谢谢!