侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

PHP 命令行工具 shell_exec, exec, passthru, system详细使用介绍

php  /  管理员 发布于 7年前   194

所有这些命令都衍生一个子进程,用于运行您指定的命令或脚本,并且每个子进程会在命令输出写到标准输出 (stdout) 时捕捉它们。

shell_exec()

shell_exec() 命令行实际上仅是反撇号 (`) 操作符的变体。如果您编写过 shell 或 Perl 脚本,您就知道可以在反撇号操作符内部捕捉其他命令的输出。例如,清单 1 显示了如何使用反撇号在当前目录中获取每个文本(.txt)的单词计数。

清单 1. 使用反撇号计算单词数量

复制代码 代码如下:

#! /bin/sh
number_of_words=`wc -w *.txt`
echo $number_of_words

#result would be something like:
#165 readme.txt 388 results.txt 588 summary.txt
#and so on....


在您的 PHP 脚本中,您可以在 shell_exec() 中运行这个简单的命令,如清单 2 所示,并获取想要的结果。这里假设在同一个目录下有一些文本文件。

清单 2. 在 shell_exec() 中运行相同的命令

复制代码 代码如下:

$results = shell_exec('wc -w *.txt');
echo $results;
?>

在图 1 中可以看到,获得的结果与从 shell 脚本得到的一样。这是因为 shell_exec() 允许您通过 shell 运行外部程序,然后以字符串的形式返回结果。
图 1. 通过 shell_exec() 运行 shell 命令的结果

注意,仅使用后撇号操作符也会得到相同的结果,如下所示。
清单 3. 仅使用后撇号操作符
复制代码 代码如下:

$results = `wc -w *.txt`;
echo $results;
?>

清单 4 给出了一种更加简单的方法。
清单 4. 更加简单的方法
复制代码 代码如下:

echo `wc -w *.txt`;
?>

通过 UNIX 命令行和 shell 脚本能够完成很多东西,知道这点很重要。例如,您可以使用竖线将命令连接起来。您甚至可以使用操作符在其中创建 shell 脚本,并且仅调用 shell 脚本(根据需要使用或不使用参数)。

例如,如果您仅希望计算该目录下的前 5 个文本文件的单词数,那么可以使用竖线 (|) 将 wc 和 head 命令连接起来。另外,您还可以将输出结果放到 pre 标记内部,让它能够更美观地呈现在 Web 浏览器中,如下所示。

清单 5. 更加复杂的 shell 命令

复制代码 代码如下:

$results = shell_exec('wc -w *.txt | head -5');
echo "".$results . "";
?>

图 2 演示了运行清单 5 的脚本得到的结果。
图 2. 从 shell_exec() 运行更复杂的 shell 命令得到的结果

在本文的后面部分,您将学习如何使用 PHP 为这些脚本传递参数。现在您可以将它看作运行 shell 命令的一种方法,但要记住您只能看到标准输出。如果命令或脚本出现错误,您将看不到标准的错误 (stderr),除非您通过竖线将它添加到 stdout。

passthru()

passthru() 允许您运行外部程序,并在屏幕上显示结果。您不需要使用 echo 或 return 来查看结果;它们会显示在浏览器上。您可以添加可选的参数,即保存从外部程序返回的代码的变量,比如表示成功的 0,这为调试提供更好的机制。

在清单 6 中,我使用 passthru() 命令运行在前面小节运行的单词计数脚本。如您所见,我还添加一个包含返回代码的 $returnval 变量。

清单 6. 使用 passthru() 命令运行单词计数脚本

复制代码 代码如下:

passthru('wc -w *.txt | head -5',$returnval);
echo "
".$returnval;
?>

注意,我不需要使用 echo 返回任何东西。结果会直接显示在屏幕上,如下所示。
图 3. 使用 return 代码运行 passthru() 命令的结果

在清单 7 中,我通过删除脚本头部的 5 前面的短横线 (-) 引入一个小错误。
清单 7. 在单词计数脚本中引入一个错误
复制代码 代码如下:

//we introduce an error below (removing - from the head command)

passthru('wc -w *.txt | head 5',$returnval);
echo "


".$returnval;
?>


注意,脚本未能按照预期运行。您得到的是一个空白的屏幕,一条水平线和返回值 1,如图 4 所示。这个返回代码通常表明发生了某些错误。如果能够测试返回代码,查找和修复错误就容易多了。
图 4. 使用 passthru() 时查看错误代码

exec()
exec() 命令与 shell_exec() 相似,不同之处是它返回输出的最后一行,并且可选地用命令的完整输出和错误代码填充数组。清单 8 展示了当运行 exec() 而不捕捉数据数组中的数据时发生的事情。
清单 8. 运行 exec() 而不捕捉数据数组中的数据
复制代码 代码如下:

$results = exec('wc -w *.txt | head -5');
echo $results;
#would print out just the last line or results, i.e.:
#3847 myfile.txt
?>

为了捕捉数组中的结果,要将该数组的名称作为第二个参数添加到 exec()。我在清单 9 中执行了这个步骤,并以 $data 作为数组的名称。
清单 9. 从 exec() 捕捉数据数组的结果
复制代码 代码如下:

$results = exec('wc -w *.txt | head -5',$data);
print_r($data);
#would print out the data array:
#Array ( [0]=> 555 text1.txt [1] => 283 text2.txt)
?>

在捕捉数组中的结果之后,您可以对每行进行一些处理。例如,您可以在第一个空格处进行划分,将分离的值存储在数据库表中,或对每个行应用特定的格式或标记。
system()
如清单 10 所示,system() 命令是一种混合体。它像 passthru() 一样直接输出从外部程序接收到的任何东西。它还像 exec() 一样返回最后一行,并使返回代码可用。
清单 10. system() 命令
复制代码 代码如下:

system('wc -w *.txt | head -5');
#would print out:
#123 file1.txt 332 file2.txt 444 file3.txt
#and so on
?>

一些例子
现在您已经了解如何使用这些 PHP 命令,但可能仍然有一些疑问。例如,什么时候应该使用哪个命令?这完全由您的需求决定。
大多数情况下,我使用 exec() 命令和数据数组处理所有东西。或者对更简单的命令使用 shell_exec(),尤其是不关心结果时。如果仅需返回一个 shell 脚本,我就使用 passthru()。通常,我在不同的场合中使用不同的函数,并且有时它们是可以互换的。这完全取决于我的心情和要实现的目的。
您可能提问的另一个问题是 “它们的长处是什么?”。如果您没有头绪,或者一个项目非常适合使用 shell 命令,但不知道如何使用,那么我在这里提供一些见解。
如果您正在编写一个提供各种备份或文件传输功能的应用程序,您可以选择使用 shell_exec() 或这里提供的其他命令之一运行 rsync 支持的 shell 脚本。您可以编写 shell 脚本使其包含必要的 rsync 命令,然后使用 passthru() 根据用户的命令或 cron 作业执行它。
例如,一位用户在您的应用程序中有适当的权限(比如管理员权限),他想将 50 个 PDF 文件从一个服务器发送到另一个服务器。那么,该用户需要在应用程序中导航到正确的位置,单击 Transfer,选择需要发送的 PDF,然后单击 Submit。在这个过程中,该表单应该有一个 PHP 脚本,它使用返回选项变量通过 passthru() 运行 rsync 脚本,这样您就知道是否发生问题,如下所示。
清单 11. 通过 passthru() 运行 rsync 脚本的示例 PHP 脚本
复制代码 代码如下:

passthru('xfer_rsync.sh',$returnvalue);
if ($returnvalue != 0){
//we have a problem!
//add error code here
}else{
//we are okay
//redirect to some other page
}
?>

如果您的应用程序需要列出进程或文件,或关于这些进程或文件的数据,您可以使用本文总结的命令之一轻松实现这个目的。例如,一个简单的 grep 命令能够帮助您找到匹配特定搜索条件的文件。将它与 exec() 命令一起使用可以将结果保存到一个数组中,这允许您构建一个 HTML 表或表单,它们又进一步允许您运行其他命令。
到目前为止,我讨论了用户生成的事件 ―― 用户只要按下按钮或单击链接,PHP 就运行相应的脚本。您还可以将独立的 PHP 脚本和 cron 或其他日程安排程序一起使用,从而实现一些有趣的效果。例如,如果您一个备份脚本,您可以通过 cron 运行它,或者将它打包到 PHP 脚本后在运行。为什么要这样做?这似乎是多余的,不是吗?不是这样的 ―― 您需要这样考虑,您可以通过 exec() 或 passthru() 运行备份脚本,然后根据返回代码执行一些行为。如果出现错误,您可以将其记录到错误日志或数据库中,或发送一封警告电子邮件。如果脚本成功,您可以将原始的输出转储到数据库(例如,rsync 有一个详尽(verbose)模式,对随后诊断问题十分有用)。

--------------------------------------------------------------------------------
安全
我们在这里简要讨论一下安全性:如果您接受用户输入并将信息传递到 shell,那么最好过滤用户输入。删除您认为有害的命令和不允许的内容,比如 sudo(作为超级用户运行)或 rm(删除)。事实上,您可能不希望用户发送开放的请求,而是让他们从列表中选择。
例如,您运行一个接受文件列表作为参数的传输程序,您应该通过一系列复选框列出所有文件。用户可以选择和取消选择文件,并通过单击 Submit 激活 rsync shell 脚本。用户不能自己输入文件或使用正则表达式。

--------------------------------------------------------------------------------
结束语
在本文中,我演示了使用 PHP 命令运行 shell 脚本和其他命令的基础知识。这些 PHP 命令包括 shell_exec()、exec()、passthru() 和 system()。现在,您应该在自己的应用程序中实践学到的知识。

您可能感兴趣的文章:

  • PHP的命令行命令使用指南
  • 如何通过Linux命令行使用和运行PHP脚本
  • php命令行(cli)下执行PHP脚本文件的相对路径的问题解决方法
  • PHP命令行脚本接收传入参数的三种方式
  • mongodb 命令行下及php中insert数据详解
  • php连接不上mysql但mysql命令行操作正常的解决方法
  • php命令行写shell实例详解


  • 上一条:
    PHP内核介绍及扩展开发指南―基础知识
    下一条:
    20个PHP常用类库小结
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 用Time Warden监控PHP中的代码处理时间(0个评论)
    • 在PHP中使用array_pop + yield实现读取超大型目录功能示例(0个评论)
    • Property Hooks RFC在PHP 8.4中越来越接近现实(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-11
    • 2017-12
    • 2018-01
    • 2018-02
    • 2018-03
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-09
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-09
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客