php 代码检查工具命令

如果您使用过PHP,那么您就会知道它是创建功能丰富的Web页面的绝佳工具。 作为一种通用的脚本语言,PHP:

  • 很容易学习。
  • 具有许多强大的框架,例如CakePHP和CodeIgniter,可以使您像任何Rails程序员一样高效。
  • 可以与MySQL,PostgreSQL,Microsoft®SQL Server甚至Oracle通信。
  • 轻松与JavaScript框架集成,例如script.aculo.us和jQuery。

不过,在某个时候,您想做更多,或者被迫做更多。 通过这种方式,我的意思是您必须直接使用运行PHP的服务器的文件系统。 您最终需要使用文件系统上的文件,了解正在运行的进程或执行其他任务。

首先,您很满意在PHP中使用诸如file()类的命令来打开文件。 但是,在某些时候,完成某件事的唯一方法是能够在服务器上运行shell命令并获取某种类型的输出。 例如,您可能需要知道某个目录中有多少文件。 或者,您可能需要知道已将几行写入一组日志文件。 或者,您可能需要对这些文件进行操作以将它们复制到另一个目录,或使用rsync将它们传输到另一个位置。

Roger McCoy在“ 命令行PHP?是,您可以!”中 ,展示了如何直接从命令行使用PHP —不需要Web浏览器。 在本文中,我从另一个角度探讨了该主题,向您展示了如何与底层Shell命令紧密集成以及如何将所有返回值折叠到您的接口和进程中。

仅当您在Linux®,Berkeley Software Distribution(BSD)或其他某种UNIX®版本上运行时,此类操作才有效。 我假设您正在Linux-Apache-MySQL-PHP(LAMP)堆栈上运行。 如果运行不同的UNIX版本,则里程可能会有所不同,因为命令的可用性因安装而异。 我知道你们中的许多人也在Mac OS X上运行,后者运行的是BSD,因此我将示例命令尽可能通用,以确保可移植性。

命令行概述

PHP命令行界面(CLI)服务器应用程序编程接口(SAPI)是在PHP V4.2.0中试验性发布的。 从V4.3.0开始,默认情况下完全支持并启用它。 PHP CLI SAPI允许您开发支持PHP的基于Shell甚至基于桌面的脚本。 确实,可以在PHP中创建直接从命令行运行的工具。 在这种情况下,PHP开发人员可以在这种情况下像Perl,AWK,Ruby或Shell脚本编写者一样高效。

本文考虑了PHP内置的工具,这些工具使您可以利用基础的shell环境和运行PHP的文件系统。 PHP提供了许多用于执行外部命令的函数,其中包括shell_exec()exec()passthru()system() 。 这些命令相似,但是为您正在运行的外部程序提供了不同的接口。 这些命令中的每一个都生成一个子进程来运行您指定的命令或脚本,并且每个命令都捕获将命令输出到标准输出( 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()运行相同的命令
<?php
$results = shell_exec('wc -w *.txt');
echo $results;
?>

如图1所示,您将获得与Shell脚本相同的结果。 这是因为shell_exec()允许您通过Shell运行外部程序,然后将结果作为字符串返回。

图1.通过shell_exec()运行shell命令的结果
一个shell_exec()结果示例

请注意,如果仅使用反引号运算符,您将获得相同的结果,如下所示。

清单3.仅使用反引号运算符
<?php
$results = `wc -w *.txt`;
echo $results;
?>

清单4显示了一个更简单的方法。

清单4.一个更简单的方法
<?php
echo `wc -w *.txt`;
?>

重要的是要注意,这里几乎允许您在UNIX命令行或shell脚本中可以执行的任何操作。 例如,您可以使用管道将命令串在一起。 您甚至可以创建一个包含所有操作的shell脚本,并根据需要调用带或不带参数的shell脚本。

例如,如果只想计算目录中前五个文本文件中的单词,则可以使用竖线( | )将wchead命令连接在一起。 此外,您可以将输出结果包装在pre标记中,以使其在Web浏览器中更可口,如下所示。

清单5.一个更复杂的shell命令
<?php
$results = shell_exec('wc -w *.txt | head -5');
echo "<pre>".$results . "</pre>";
?>

图2显示了清单5中运行脚本的结果。

图2.通过shell_exec()运行更复杂的shell命令的结果
通过shell_exec()运行更复杂的Shell命令的结果

在本文的后面,您将学习如何使用PHP将参数传递给这些脚本。 现在,只要您记住只看到标准输出,就可以将其视为运行Shell命令的一种方式。 如果脚本或命令中存在错误,则除非将其通过管道传递到stdout否则不会看到标准错误( stderr )。

passthru()

passthru()命令使您可以运行外部程序并在屏幕上显示其结果。 您无需使用echoreturn即可查看这些结果; 它们只是显示在浏览器中。 您可以添加一个可选参数,该参数保存外部程序的返回代码,例如0表示成功,这提供了更好的调试机制。

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

清单6.使用passthru()命令运行单词计数脚本
<?php
passthru('wc -w *.txt | head -5',$returnval);
echo "<hr/>".$returnval;
?>

请注意,我不必echo任何内容。 结果仅显示在屏幕上,如下所示。

图3.运行带有return代码的passthru()命令的结果
passthru()命令示例

在清单7中,我通过删除脚本头部5之前的破折号来引入代码中的一个小错误。

清单7.在单词计数脚本中引入错误
<?php
//we introduce an error below (removing - from the head command)

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

请注意,脚本未按预期运行。 如图4所示,您将得到一个空白屏幕,一个水平尺和一个返回值1。此返回码通常表明发生了某种错误。 能够测试此返回码可以更轻松地找出需要解决的问题。

图4.使用passthru()时看到错误代码
passthru()错误返回码

exec()

exec()命令与shell_exec()类似,不同之处在于它返回输出的最后一行,并可选地用命令的完整输出以及错误代码填充数组。 清单8是一个示例,如果您运行exec()而不将结果捕获到数据数组中会发生什么。

清单8.运行exec()而不在数据数组中捕获结果
<?php
$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()获取结果
<?php
$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()命令
<?php
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脚本将很明智。 您可以编写包含必要的rsync命令的shell脚本,然后使用passthru()根据用户命令或cron作业执行它。

例如,在您的应用程序中具有适当特权的用户(例如admin)可能需要将50个PDF从一台服务器传输到另一台服务器。 用户将导航到应用程序中的正确位置,单击“ 传输” ,选择要传输的PDF,然后单击“ 提交” 。 作为其动作,该表单将具有一个PHP脚本,该脚本通过带有返回选项变量的passthru()运行您的rsync脚本,因此您知道是否出现问题,如下所示。

清单11.通过passthru()运行rsync脚本的示例PHP脚本
<?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将运行脚本。 您还可以通过使用cron或其他调度程序运行独立PHP脚本来实现一些有趣的效果。 例如,如果您有备份脚本,则可以通过cron独立运行它,也可以将其包装在PHP脚本中然后运行。 你为什么想这么做? 听起来多余又浪费,对吗? 好吧,没有-如果您认为可以通过exec()passthru()运行备份脚本,则可以根据返回代码执行某些行为。 如果遇到错误,则可以在错误日志或数据库中写入条目,或发送警告电子邮件。 如果脚本成功,则可以将脚本的原始输出转储到数据库中(例如, rsync具有详细模式,可用于稍后诊断问题)。

安全

关于安全性的简短说明:如果您接受用户输入并将该信息传递给Shell,则最好对用户输入进行清理。 剥离所有您认为有害的命令并禁止使用,例如sudo (以超级用户权限运行)或rm (删除)。 实际上,您可能希望禁止用户发送打开的请求,而只允许他们从可能的替代列表中进行选择。

例如,如果您正在运行一个接受文件列表作为参数的传输程序,则可以在一行中列出所有文件,并在每个文件旁边都有一个复选框。 用户可以选择和取消选择文件,然后单击提交以激活rsync shell脚本。 不允许他们输入文件列表或使用某种正则表达式。

摘要

在本文中,我展示了使用PHP命令(如shell_exec()exec()passthru()system()运行shell脚本和其他命令的基础。 现在由您决定将这些知识用于您自己的应用程序中。


翻译自: https://www.ibm.com/developerworks/opensource/library/os-php-commandline/index.html

php 代码检查工具命令

Logo

更多推荐