PHP執(zhí)行命令的四種方法
創(chuàng)新互聯(lián)公司成立于2013年,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站制作、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢想脫穎而出為使命,1280元平順做網(wǎng)站,已為上家服務(wù),為平順各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792
方法一:使用exec函數(shù)執(zhí)行系統(tǒng)外部命令
原型:function exec(string $command,array[optional] $output,int[optional]
$return_value)
?
exec("dir",$outPut);
print_r($outPut);
?
說明:列出和PHP執(zhí)行文件同級目錄下的所有目錄及文件信息。
知識(shí)點(diǎn):exec執(zhí)行系統(tǒng)外部命令時(shí)不會(huì)輸出結(jié)果,而是返回結(jié)果的最后一行,如果你想得到結(jié)果你可以使用第二個(gè)參數(shù),讓其輸出到指定的數(shù)組,此數(shù)組一個(gè)記錄代表輸出的一行,即如果輸出結(jié)果有20行,則這個(gè)數(shù)組就有20條記錄,所以如果你需要反復(fù)輸出調(diào)用不同系統(tǒng)外部命令的結(jié)果,你最好在輸出每一條系統(tǒng)外部命令結(jié)果時(shí)清空這個(gè)數(shù)組,以防混亂。第三個(gè)參數(shù)用來取得命令執(zhí)行的狀態(tài)碼,通常執(zhí)行成功都是返回0。
方法二:使用system函數(shù)執(zhí)行系統(tǒng)外部命令
原型:function system(string $command,int[optional] $return_value)
1
2
3
?
system("dir");
?
知識(shí)點(diǎn):system和exec的區(qū)別在于system在執(zhí)行系統(tǒng)外部命令時(shí),直接將結(jié)果輸出到游覽器,如果執(zhí)行命令成功則返回true,否則返回false。第二個(gè)參數(shù)與exec第三個(gè)參數(shù)含義一樣。
方法三:使用函數(shù)passthru執(zhí)行系統(tǒng)外部命令
原型:function passthru(string $command,int[optional] $return_value)
知識(shí)點(diǎn):passthru與system的區(qū)別,passthru直接將結(jié)果輸出到游覽器,不返回任何值,且其可以輸出二進(jìn)制,比如圖像數(shù)據(jù)。
方法四:反撇號(hào)`(和~在同一個(gè)鍵)執(zhí)行系統(tǒng)外部命令
1
2
3
?
echo `dir`;
?
知識(shí)點(diǎn):在使用這種方法執(zhí)行系統(tǒng)外部命令時(shí),你要確保shell_exec函數(shù)可用,否則是無法使用這種反撇號(hào)執(zhí)行系統(tǒng)外部命令的。
1、方法一:
命令行查詢,如果已經(jīng)配置好環(huán)境變量,直接在命令行中輸入php -v,將會(huì)顯示php的版本信息。如果沒有配置環(huán)境變量,直接在命令行中進(jìn)入到php的安裝目錄后,再輸入命令php -v,在安裝目錄下輸入查詢命令,可以看到輸出的版本信息為PHP5.3.29。
2、方法二:
(1)使用預(yù)定義常量PHP_VERSION查詢,新建一個(gè)php文件,在里面輸入?php ??? echo PHP_VERSION;?。
(2)在瀏覽器中輸出對應(yīng)的網(wǎng)址,就可以查看到php的版本信息。
3、方法三:
(1)使用phpversion()函數(shù)查詢,新建一個(gè)php文件,在文件中輸入?php ??? echo phpversion();?即可。
(2)在瀏覽器中訪問,可以看到瀏覽器頁面上返回的php版本信息,跟預(yù)定義常量PHP_VERSION顯示效果一樣。
4、方法四:
(1)使用phpinfo()函數(shù)查詢,新建一個(gè)php文件,在文件中輸入?php ??? echo phpinfo();?即可。
(2)在瀏覽器中訪問,可以看到不僅可以看到PHP的版本信息,還能看到其它很多關(guān)于PHP的信息。
PHP在linux上執(zhí)行命令
目錄:
一、PHP中調(diào)用外部命令介紹
二、關(guān)于安全問題
三、關(guān)于超時(shí)問題
四、關(guān)于PHP運(yùn)行l(wèi)inux環(huán)境中命令出現(xiàn)的問題
一、PHP中調(diào)用外部命令介紹
在PHP中調(diào)用外部命令,可以用,1調(diào)用專門函數(shù)、2反引號(hào)、3popen()函數(shù)打開進(jìn)程,三種方法來實(shí)現(xiàn):
方法一:用PHP提供的專門函數(shù)(四個(gè)):
PHP提供4個(gè)專門的執(zhí)行外部命令的函數(shù):exec(), system(), passthru(), shell_exec()
1)exec()
原型: string exec ( string $command [, array $output [, int $return_var ] )
說明: exec執(zhí)行系統(tǒng)外部命令時(shí)不會(huì)輸出結(jié)果,而是返回結(jié)果的最后一行。如果想得到結(jié)果,可以使用第二個(gè)參數(shù),讓其輸出到指定的數(shù)組。此數(shù)組一個(gè)記錄代表輸出的一行。即如果輸出結(jié)果有20行,則這個(gè)數(shù)組就有20條記錄,所以如果需要反復(fù)輸出調(diào)用不同系統(tǒng)外部命令的結(jié)果,最好在輸出每一條系統(tǒng)外部命令結(jié)果時(shí)清空這個(gè)數(shù)組unset($output),以防混亂。第三個(gè)參數(shù)用來取得命令執(zhí)行的狀態(tài)碼,通常執(zhí)行成功都是返回0。
?php
exec("dir",$output);
print_r($output);
?
2)system()
原型: string system ( string $command [, int $return_var ] )
說明: system和exec的區(qū)別在于,system在執(zhí)行系統(tǒng)外部命令時(shí),它執(zhí)行給定的命令,輸出和返回結(jié)果。第二個(gè)參數(shù)是可選的,用來得到命令執(zhí)行后的狀態(tài)碼。
?php
system("pwd",$result);
print $result;//輸出命令的結(jié)果狀態(tài)碼
?
關(guān)于第二個(gè)參數(shù)結(jié)果狀態(tài)碼的簡單介紹:
如果返回0是運(yùn)行成功,
在Bash中,當(dāng)錯(cuò)誤發(fā)生在致命信號(hào)時(shí),bash會(huì)返回128+signal number做為返回值。
如果找不到命令,將會(huì)返回127。
如果命令找到了,但該命令是不可執(zhí)行的,將返回126。
除此以外,Bash本身會(huì)返回最後一個(gè)指令的返回值。
若是執(zhí)行中發(fā)生錯(cuò)誤,將會(huì)返回一個(gè)非零的值。
Fatal Signal : 128 + signo
Can't not find command : 127
Can't not execute : 126
Shell script successfully executed : return the last command exit status
Fatal during execution : return non-zero
3)passthru()
原型: void passthru ( string $command [, int $return_var ] )
說明: passthru與system的區(qū)別,passthru直接將結(jié)果輸出到游覽器,不返回任何值,且其可以輸出二進(jìn)制,比如圖像數(shù)據(jù)。第二個(gè)參數(shù)可選,是狀態(tài)碼。
?php
header("Content-type:image/gif");
passthru("/usr/bin/ppm2tiff /usr/share/tk8.4/demos/images/teapot.ppm");
?
4)shell_exec()
原型: string shell_exec ( string $cmd )
說明: 直接執(zhí)行命令$cmd
?php
$output = shell_exec('ls -lart');
echo "pre$output/pre";
?
方法二:反撇號(hào)
原型: 反撇號(hào)`(和~在同一個(gè)鍵)執(zhí)行系統(tǒng)外部命令
說明: 在使用這種方法執(zhí)行系統(tǒng)外部命令時(shí),要確保shell_exec函數(shù)可用,否則是無法使用這種反撇號(hào)執(zhí)行系統(tǒng)外部命令的。
?php
echo `dir`;
?
方法三:用popen()函數(shù)打開進(jìn)程
原型: resource popen ( string $command , string $mode )
說明: 能夠和命令進(jìn)行交互。之前介紹的方法只能簡單地執(zhí)行命令,卻不能與命令交互。有時(shí)須向命令輸入一些東西,如在增加系統(tǒng)用戶時(shí),要調(diào)用su來把當(dāng)前用戶換到root用戶,而su命令必須要在命令行上輸入root的密碼。這種情況下,用之前提到的方法顯然是不行的。
popen( )函數(shù)打開一個(gè)進(jìn)程管道來執(zhí)行給定的命令,返回一個(gè)文件句柄,可以對它讀和寫。返回值和fopen()函數(shù)一樣,返回一個(gè)文件指針。除非使用的是單一的模式打開(讀or寫),否則必須使用pclose()函數(shù)關(guān)閉。該指針可以被fgets(),fgetss(),fwrite()調(diào)用。出錯(cuò)時(shí),返回FALSE。
?php
error_reporting(E_ALL);
/* Add redirection so we can get stderr. */
$handle = popen('/path/to/executable 21', 'r');
echo "'$handle'; " . gettype($handle) . "\n";
$read = fread($handle, 2096);
echo $read;
pclose($handle);
?
1.用php -q 文件名.php 方式把php程序當(dāng)shell程序來用,
2.用php -s把自己的php程序顯示有語法高亮色彩的html源文件。這樣是不是很省心?
3.利用php的odbc功能可以在shell命令中對數(shù)據(jù)庫進(jìn)行操作。
#0 6 * * * /usr/local/bin/php /home/web/do/index.php
4.查看擴(kuò)展庫
/usr/local/php/bin/php -m
5.檢查php.ini配置是否正確
/usr/local/php/bin/php -v
6.讓php運(yùn)行指定文件
php my_script.php
php -f my_script.php
7.在命令行直接運(yùn)行 PHP 代碼。
php -r ‘print_r(get_defined_constants());’
php -r ‘phpinfo();’
8.用該參數(shù),您可以指定一個(gè)放置 php.ini 文件的目錄,或者直接指定一個(gè)自定義的 INI 文件
php -c /custom/directory/custom-file.ini my_script.php
9.顯示除去了注釋和空格的源代碼。
php -w a.php
10.php -i
該命令行參數(shù)會(huì)調(diào)用 phpinfo() 函數(shù),并打印出結(jié)果。
如何獲取PHP命令行參數(shù)
使用 PHP 開發(fā)的同學(xué)多少都會(huì)接觸過 CLI 命令行。經(jīng)常會(huì)有一些定時(shí)任務(wù)或者一些腳本直接使用命令行處理會(huì)更加的方便,有些時(shí)候我們會(huì)需要像網(wǎng)頁的 GET 、 POST 一樣為這些命令行腳本提供參數(shù)。比如在針對某些日期做統(tǒng)計(jì)的腳本,就需要傳遞一個(gè)日期給它,這樣我們就統(tǒng)計(jì)指定日期的一些數(shù)據(jù)。這類需求應(yīng)該非常常見,那么,我們都是如何來接收這些命令行的參數(shù)的呢?今天,就來介紹一下這方面的內(nèi)容。
$argv 獲得所有空格分隔的參數(shù)列表
這個(gè)變量估計(jì)是大家用得比較多的一個(gè)接參變量了。它是 PHP 為我們準(zhǔn)備好的一個(gè)固定變量,目的就是獲取傳遞給腳本的參數(shù)數(shù)組。
print_r($argv); // php 如何獲取PHP命令行參數(shù).php --a=1 -b=2 -c=3 -d=4 --e=5 ccc ddd // Array // ( // [0] = 如何獲取PHP命令行參數(shù).php // [1] = --a=1 // [2] = -b=2 // [3] = -c=3 // [4] = -d=4 // [5] = --e=5 // [6] = ccc // [7] = ddd // )
這個(gè)數(shù)組是以參數(shù)間隔的空格進(jìn)行分隔的。第1個(gè)元素是當(dāng)前運(yùn)行的腳本文件名,也就是說,不管有沒有參數(shù),這個(gè)變量一定會(huì)有一個(gè) $argv[0] 表示的是當(dāng)前的腳本文件名。
在日常的開發(fā)需求中,其實(shí)使用這個(gè)變量就已經(jīng)夠用了。但是這明顯不會(huì)是我們今天的主題,大家注意到上面的代碼中我們有很多參數(shù)是 -x=xxx 的形式,這種形式的參數(shù)是不是和 Linux 的命令選項(xiàng)非常像,沒錯(cuò),這就是我們今天要重點(diǎn)介紹的:從命令行參數(shù)列表中獲取選項(xiàng)。
getopt() 從命令行參數(shù)列表中獲取選項(xiàng)
其實(shí)就是這樣一個(gè)簡單的函數(shù),我們就可以像 Linux 的命令選項(xiàng)一樣獲取指定的命令值。而且不是像 $argv 按空格進(jìn)行分隔,命令選項(xiàng)函數(shù)會(huì)將這些命令選項(xiàng)封裝成數(shù)組,組成以選項(xiàng)名為鍵,以等號(hào)后面的內(nèi)容為值的數(shù)組,更加方便我們的使用。
// php 如何獲取PHP命令行參數(shù).php --a=1 -b=2 -c=3 -d=4 --e=5 ccc ddd print_r(getopt('a:b:c:d:e:f:')); // Array // ( // [b] = 2 // [c] = 3 // [d] = 4 // )
是不是很神奇,而且非常直觀吧,我們直接就拿到了 b 、 c 、d 的內(nèi)容并且是格式非常清晰的鍵值數(shù)組形式。有同學(xué)要問了,a 和 e 呢?還有后面的 ccc 、 ddd 呢?
首先要說明的是,ccc 和 ddd 不是標(biāo)準(zhǔn)的選項(xiàng)參數(shù),也就是說,這個(gè)函數(shù)接收的內(nèi)容是以 - 開頭的選項(xiàng),所以 ccc 和 ddd 不會(huì)在這里輸出,并且需要注意的是,非選項(xiàng)參數(shù)會(huì)中斷選項(xiàng)參數(shù)的獲取,在 ccc 之后如果繼續(xù)添加 - 開頭的選項(xiàng)也是無法獲取到的,這個(gè)我們后面還會(huì)看到。而 -- 開頭的選項(xiàng)參數(shù)呢?我們直接看下面的長選項(xiàng)功能。
長選項(xiàng) // php 如何獲取PHP命令行參數(shù).php --a=1 -b=2 -c=3 -d=4 --e=5 ccc ddd print_r(getopt('', ['a:','b:','c:','d:','e:','f:'])); // Array // ( // [a] = 1 // [e] = 5 // )
沒錯(cuò),getopt() 函數(shù)的第二個(gè)參數(shù)就是定義這種 -- 開頭的長選項(xiàng)的,而且需要注意的是,第一個(gè)參數(shù)是字符串類型,第二個(gè)長選項(xiàng)參數(shù)是數(shù)組類型的。那么我們把它們結(jié)合起來,就當(dāng)然可以獲取到全部的參數(shù)信息啦!
// php 如何獲取PHP命令行參數(shù).php --a=1 -b=2 -c=3 -d=4 --e=5 ccc ddd print_r(getopt('a:b:c:d:e:f:', ['a:','b:','c:','d:','e:','f:'])); // Array // ( // [a] = 1 // [b] = 2 // [c] = 3 // [d] = 4 // [e] = 5 // )
OK,參數(shù)選項(xiàng)獲取沒問題了吧,細(xì)心的同學(xué)肯定又發(fā)現(xiàn)了一個(gè)問題,這個(gè) getopt() 函數(shù)的參數(shù)中定義的選項(xiàng)名稱后面為啥都要加個(gè)冒號(hào)?這就涉及到我們的冒號(hào)規(guī)則了,請直接往下看。
冒號(hào)規(guī)則
getopt() 的前兩個(gè)參數(shù)都支持一套關(guān)于選項(xiàng)獲取的規(guī)則:
單獨(dú)的字符(不接受值) 后面跟隨冒號(hào)的字符(此選項(xiàng)需要值) 后面跟隨兩個(gè)冒號(hào)的字符(此選項(xiàng)的值可選)
我們還是直接通過代碼來看一下。
// 一 // php 如何獲取PHP命令行參數(shù).php --a=1 -b=2 -c=3 -d=4 --e=5 ccc ddd print_r(getopt('abcdef')); // Array // ( // [b] = // [c] = // [d] = // ) // 二 // php 如何獲取PHP命令行參數(shù).php -f print_r(getopt('f::')); // Array // ( // [f] = // ) print_r(getopt('f:')); // Array // ( // ) // 三 // php 如何獲取PHP命令行參數(shù).php -f 22 print_r(getopt('f::')); // Array // ( // [f] = // ) print_r(getopt('f:')); // Array // ( // [f] = 22 // ) // 四 // php 如何獲取PHP命令行參數(shù).php -f=22 print_r(getopt('f::')); // Array // ( // [f] = 22 // ) print_r(getopt('f:')); // Array // ( // [f] = 22 // )
這一段比較長,我們一塊一塊來看。首先是不帶冒號(hào)的 abcdef 寫法,返回的數(shù)組中都包含鍵,但沒有值,對應(yīng)上面的規(guī)則就是不接受這些參數(shù)選項(xiàng)的值,你傳了這些參數(shù)選項(xiàng)也是只有鍵名而內(nèi)容是空的。
第二段是定義了一個(gè)參數(shù),但是不給值,這時(shí),雙冒號(hào) :: 會(huì)有鍵名,而單冒號(hào) : 則什么都沒有。
第三段是空格形式的選項(xiàng)值,雙冒號(hào) :: 有鍵名但沒有值,單冒號(hào) : 鍵值正常。
第四段是等號(hào) = 形式的選項(xiàng)值,單雙冒號(hào)都正常接收到鍵值。
選項(xiàng)參數(shù)中斷
上文中我們提到過參數(shù)中斷的問題,就是在選項(xiàng)參數(shù)之后如果有一個(gè)非選項(xiàng)參數(shù)的參數(shù)出現(xiàn),getopt() 就無法再獲取到這個(gè)非選項(xiàng)參數(shù)后面的所有內(nèi)容了。
// php 如何獲取PHP命令行參數(shù).php -f=22 aa -b=33 // 選項(xiàng)的解析會(huì)終止于找到的第一個(gè)非選項(xiàng),之后的任何東西都會(huì)被丟棄。 // Array // ( // [f] = 22 // )
通過這個(gè)測試可以清晰的看出后面的 b 選項(xiàng)無法獲取。這時(shí),如果我們想知道選項(xiàng)參數(shù)在什么地方或者因?yàn)槟膫€(gè)參數(shù)而中斷的話,就可以使用 getopt() 函數(shù)的第三個(gè)參數(shù)了。
// php 如何獲取PHP命令行參數(shù).php -f=22 aa -b=33 $optind = null; getopt('f:b:', [], $optind); echo $optind, PHP_EOL; // 返回中斷位置的索引值,2 echo $argv[$optind], PHP_EOL; // 等同于 $argv 的索引順序,aa
注釋已經(jīng)寫得很清晰了,第三個(gè)參數(shù)會(huì)回調(diào)一個(gè)參數(shù)選項(xiàng)中斷位置的索引,并且這個(gè)索引是和 $argv 的索引順序位置一致的。
總結(jié)
說實(shí)話,在沒看文檔前真的只知道有一個(gè) $argv 變量可以用來獲取命令行腳本的參數(shù),通過這次學(xué)習(xí)才發(fā)現(xiàn)原來還有一個(gè)這么強(qiáng)大的選項(xiàng)參數(shù)函數(shù)。學(xué)習(xí)的過程非常簡單,如何運(yùn)用到真實(shí)的項(xiàng)目中才是關(guān)鍵所在,加油學(xué)習(xí),努力實(shí)踐吧!
測試代碼:
頭部加上超時(shí)控制,但對于很多服務(wù)器無效,因?yàn)榉?wù)器輸出超時(shí)很多在服務(wù)器控制,所以建議用cmd腳本方式運(yùn)行此程序:
?php
set_time_limit(0); //禁用腳本超時(shí)
//?Create?the?socket?and?connect
$socket?=?socket_create(AF_INET,?SOCK_STREAM,?SOL_TCP);
$connection?=?socket_connect($socket,'116。236。128。220',?14580);
//?Write?some?test?data?to?our?socket
if(!socket_write($socket,?"user?NoCall?pass?-1?vers?test?1.0?filter?b/B*?\r\n"))
{
echo("pWrite?failed/p");
}
if(!file_exists('socket_log.html')){
file_put_contents('socket_log.html',?'script
var?xx?=?setInterval(function(){ //每5秒刷新一次頁面
window.location.reload();
},?5000);
/script');
}
//?Read?any?response?from?the?socket
while($buffer?=?socket_read($socket,?64,?PHP_NORMAL_READ))
{
echo?json_encode($buffer);?//轉(zhuǎn)換為json數(shù)據(jù)輸出
//記入文件
file_put_contents('socket_log.html',?json_encode($buffer),?FILE_APPEND);
}
echo("pDone?Reading?from?Socket/p");
使用方法:用命令行方式運(yùn)行此腳本
php?script.php
腳本會(huì)一直運(yùn)行到接收數(shù)據(jù)結(jié)束,并持續(xù)將收到的數(shù)據(jù)寫入socket_log.html文件。
在瀏覽器打開socket_log.html頁面,此頁面會(huì)自動(dòng)每5秒刷新一次,來顯示最新的數(shù)據(jù)。
確保程序有權(quán)限創(chuàng)建及寫入socket_log.html文件