從版本 4.3.0 開始,PHP 提供了一種新類型的 CLI SAPI(Server Application Programming Interface,服務端應用程式連接埠)支持,名為 CLI,意為 Command Line Interface,即命令列介面。顧名思義,此 CLI SAPI 模組主要用作 PHP 的開發外殼應用。 CLI SAPI 與其它 CLI SAPI 模組有許多的不同之處,我們將在本章中詳細闡述。值得一提的是,CLI 和 CGI 是不同的 SAPI,儘管它們之間有許多共同的行為。
CLI SAPI 最先是隨 PHP 4.2.0 版本發布的,但仍舊只是一個實驗性的版本,並需要在運行 ./configure 時加上 --enable-cli 參數。從 PHP 4.3.0 版本開始,CLI SAPI 成為了正式模組,--enable-cli 參數會預設為 on,也可以用參數 --disable-cli 來屏蔽。
從 PHP 4.3.0開始,CLI/CGI 二進位執行檔的檔案名稱、位置和是否存在會根據 PHP 在系統上的安裝而不同。在預設情況下,當執行 make 時,CGI 和 CLI 都會被編譯並且分別放置在 PHP 原始檔目錄的 sapi/cgi/php 和 sapi/cli/php 下。可以注意到兩個檔案都被命名為了 php。在 make install 的過程中會發生什麼取決於設定行。如果在設定的時候選擇了一個SAPI 模組,例如apxs,或者使用了 --disable-cgi 參數,則在 make install 的過程中,CLI 將被拷貝到 {PREFIX}/bin/php,除非CGI 已經被放置在了那個位置。因此,例如,如果在設定行中有 --with--apxs ,則在 make install 的過程中,CLI 將被拷貝到 {PREFIX}/bin/php。如果希望撤銷 CGI 執行檔的安裝,請在 make install 之後執行 make install-cli。或者,也可以在設定行中加上 --disable-cgi 參數。
注意:
由於 --enable-cli 和 --enable-cgi 同時預設有效,因此,不必再配置行中加上 --enable-cli 來使得CLI 在 make install 過程中被拷貝到 {PREFIX} /bin/php。
在 PHP 4.2.0 到 PHP 4.2.3 之間的 Windows 發行包中,CLI 的檔案名稱為 php-cli.exe,相同資料夾下的 php.exe 為 CGI。從 PHP 4.3.0 版本開始,Windows 的發行包中 CLI 的執行檔為 php.exe,被放置在一個單獨的名為 cli 的資料夾下,即 cli/php.exe。在 PHP 5 中,CLI 存在於主資料夾中,名為 php.exe,而 CGI 版本名為 php-cgi.exe。
從 PHP 5 起,一個名為 php-win.exe 的新檔案隨套件發布。它相當於 CLI 版本,但是 php-win 不輸出任何內容,而且不提供控制台(不會彈出「DOS 視窗」)。這種方式類似於 php-gtk。需要使用 --enable-cli-win32 選項來設定它。
Note: 如何得知自己使用的是哪一個 SAPI?
在命令列下,運行 php -v 便能得知該 php 是 CGI 還是 CLI。請參考函數 php_sapi_name() 以及常數 PHP_SAPI。
Note:
在 PHP 4.3.2 中加入了 Unix 的 man 頁面。可以在命令列中鍵入 man php 來查看。
以下為 CLI SAPI 及其它 CLI SAPI 模組的顯著差異:
與 CGI SAPI 不同,其輸出並無任何頭資訊。儘管 CGI SAPI 提供了取消 HTTP 頭資訊的方法,但在 CLI SAPI 中並沒有類似的方法以開啟 HTTP 頭資訊的輸出。 CLI 預設以安靜模式開始,但為了確保相容性,-q 和 --no-header 參數為了向後相容仍然保留,使得可以使用舊的 CGI 腳本。在運作時,不會把工作目錄改為腳本的目前目錄(可以使用 -C 和 --no-chdir 參數來相容 CGI 模式)。出錯時輸出純文字的錯誤訊息(非 HTML 格式)。
CLI SAPI 強制覆蓋了 php.ini 中的某些設置,因為這些設置在外殼環境下是沒有意義的。
覆蓋 php.ini 設定選項
設定選項
CLI SAPI預設值
備註
html_h_errML_rhtml_m html資訊是十分困難的。因此將該選項的預設值改為 FALSE。 implicit_flush TRUE 在命令列模式下,所有來自 print 和 echo 的輸出將立即寫入輸出端,而無法立即緩衝操作。如果希望延緩或控制標準輸出,仍可使用 output buffering 設定項目。max_execution_time 0(無限值) 鑑於在外殼環境下使用 PHP 的無窮的可能性,最大運行時間被設定為了無限值。為 web 開發的應用程式可能只需運行幾秒鐘時間,而外殼應用程式的運行時間可能會長的多。
register_argc_argv TRUE 由於設定為 TRUE,且將隨時可在 CLI SAPI 中存取 argc(傳送給應用程式參數的數量)和 argv(包含實際參數的陣列)。對於 PHP 4.3.0,使用 CLI SAPI 時,PHP 變數 $argc 和 $argv 已註冊並且設定了對應的值。而在這之前的版本,這兩個變數在CGI 或 模組 版本中的建立都依賴將 PHP 的設定選項 register_globals 設為 on。除了版本和 register_globals 設定以外,可以隨時透過呼叫 $_SERVER 或 $HTTP_SERVER_VARS 來存取它們。例如:$_SERVER['argv']
Note:
這些設定無法在設定檔 php.ini 或任何指定的其它檔案中被初始化為其它值。這些預設值被限制在所有其它的設定檔被解析後改變。不過,它們的值可以在程式運行的過程中被改變(儘管對於該運行過程來說,這些設定項是沒有意義的)。
為了減輕外殼環境下的工作,我們定義瞭如下常數:
CLI 專用常數
常數名稱
ST可以用以下方法來呼叫:
<?php $stdin = fopen('php://stdin', 'r'); ?>
如果想從 stdin 讀取一行內容,可以使用
<?php $line = trim(fgets(STDIN)); // 从 STDIN 读取一行 fscanf(STDIN, "%d\n", $number); // 从 STDIN 读取数字 ?>
STDOUT 一個已開啟的指向 stdout 的流。可以用以下方式來呼叫:
<?php $stdout = fopen('php://stdout', 'w'); ?>
STDERR 一個已開啟的指向 stderr 的流。可以用以下方式來呼叫:
<?php $stderr = fopen('php://stderr', 'w'); ?>
有了以上常數,就無需自己建立指向諸如 stderr 的流,只需簡單的使用這些常數來代替流指向:
php -r 'fwrite(STDERR, "stderr\n");'
會自動完成這些操作。 CLI SAPI 不會將目前目錄改為已執行的腳本所在的目錄。以下範例顯示了這個模組與 CGI SAPI 模組之間的差異:
<?php // 名为 test.php 的简单测试程序 echo getcwd(), "\n"; ?>
在使用 CGI 版本時,其輸出為
$ pwd /tmp $ php-cgi -f another_directory/test.php /tmp/another_directory
明顯可以看到 PHP 將目前目錄改成了剛執行的腳本所在的目錄。
使用 CLI SAPI 模式,得到:
$ pwd /tmp $ php -q another_directory/test.php /tmp
這使得在利用 PHP 編寫外殼工具時獲得了巨大的便利。
Note:
可以在命令列運作時給予此 CGI SAPI 加上 -C 參數,並使其支援 CLI SAPI 的功能。
以下是 PHP 二進位檔案(即 php.exe 程式)提供的命令列模式的選項參數,隨時可以執行帶有 -h 參數的 PHP 命令來查詢這些參數。
Usage: php [options] [-f] <file> [--] [args...] php [options] -r <code> [--] [args...] php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...] php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...] php [options] -- [args...] php [options] -a -a Run interactively -c <path>|<file> Look for php.ini file in this directory -n No php.ini file will be used -d foo[=bar] Define INI entry foo with value 'bar' -e Generate extended information for debugger/profiler -f <file> Parse <file>. -h This help -i PHP information -l Syntax check only (lint) -m Show compiled in modules -r <code> Run PHP <code> without using script tags <?..?> -B <begin_code> Run PHP <begin_code> before processing input lines -R <code> Run PHP <code> for every input line -F <file> Parse and execute <file> for every input line -E <end_code> Run PHP <end_code> after processing all input lines -H Hide any passed arguments from external tools. -s Display colour syntax highlighted source. -v Version number -w Display source with stripped comments and whitespace. -z <file> Load Zend extension <file>. args... Arguments passed to script. Use -- args when first argument starts with - or script is read from stdin
CLI SAPI 模組有以下三種不同的方法來取得要執行的 PHP 程式碼:
讓 PHP 執行指定檔案。
php my_script.php php -f my_script.php
以上兩種方法(使用或不使用 -f 參數)都能夠執行給定的 my_script.php 檔案。可以選擇任何檔案來執行,指定的 PHP 腳本並非必須以 .php 為副檔名,它們可以有任意的檔案名稱和副檔名。
在命令列直接執行 PHP 程式碼。
php -r 'print_r(get_defined_constants());'
在使用此方法時,請注意外殼變數的替代及引號的使用。
Note:
請仔細閱讀以上範例,在運行程式碼時沒有開始和結束的標記符!加上 -r 參數後,這些標記符是不需要的,加上它們會導致語法錯誤。
透過標準輸入(stdin)提供需要運行的 PHP 程式碼。以上用法提供了非常強大的功能,使得可以如下範例所示,動態地產生 PHP 程式碼並透過命令列運行這些程式碼:
$ some_application | some_filter | php | sort -u >final_output.txt
以上三種運行程式碼的方法不能同時使用。
和所有的外殼應用程式一樣,PHP 的二進位(php.exe 檔案)及其執行的 PHP 腳本能夠接受一系列的參數。 PHP 沒有限制傳送給腳本程式的參數的個數(外殼程式對命令列的字元數有限制,但通常都不會超過該限制)。傳遞給腳本的參數可在全域變數 $argv 中取得。此數組中下標為零的成員為腳本的名稱(當 PHP 程式碼來自標準輸入獲直接以 -r 參數以命令列方式執行時,名稱為「-」)。另外,全域變數 $argc 存有 $argv 數組中成員變數的個數(而非傳送給腳本程式的參數的個數)。 只要传送给脚本的参数不是以 - 符号开头,就无需过多的注意什么。向脚本传送以 - 开头的参数会导致错误,因为 PHP 会认为应该由它自身来处理这些参数。可以用参数列表分隔符 -- 来解决这个问题。在 PHP 解析完参数后,该符号后所有的参数将会被原样传送给脚本程序。 除此之外,还有另一个方法将 PHP 用于外壳脚本。可以在写一个脚本,并在第一行以 #!/usr/bin/php 开头,在其后加上以 PHP 开始和结尾标记符包含的正常的 PHP 代码,然后为该文件设置正确的运行属性(例如:chmod +x test)。该方法可以使得该文件能够像外壳脚本或 PERL 脚本一样被直接执行。 假设改文件名为 test 并被放置在当前目录下,可以做如下操作: 正如所看到的,在向该脚本传送以 - 开头的参数时,脚本仍然能够正常运行。 PHP 4.3.3 以来有效的长选项: 命令行选项 选项名称 长名称 说明 -a --interactive 交互式运行 PHP。如果编译 PHP 时加入了 Readline 扩展(Windows 下不可用),那将会得到一个很好的外壳,包括一个自动完成的功能(例如可以在键入变量名的时候,按下 TAB 键,PHP 会自动完成该变量名)以及命令历史记录,可以用上下键来访问。历史记录存在 ~/.php_history 文件中。 Note: 通过 auto_prepend_file 和 auto_append_file 包含的文件在此模式下会被解析,但有些限制,例如函数必须在被调用之前定义。 -c --php-ini 用该参数,可以指定一个放置 php.ini 文件的目录,或者直接指定一个自定义的 INI 文件(其文件名可以不是 php.ini),例如: 如果不指定此选项,PHP 将在默认位置搜索文件。 -n --no-php-ini 完全忽略 php.ini。此参数在 PHP 4.3.0 以后有效。 -d --define 用该参数可以自行设置任何可以在 php.ini 文件中设置的配置选项的值,其语法为: 例子(因版面原因而折行显示): -e --profile-info 激活扩展信息模式,被用于调试/测试。 -f --file 解析并运行 -f 选项给定的文件名。该参数为可选参数,可以省略,仅指明需要运行的文件名即可。 -h and -? --help and --usage 使用该参数,可以得到完整的命令行参数的列表及这些参数作用的简单描述。 -i --info 该命令行参数会调用 phpinfo() 函数并显示出结果。如果 PHP 没有正常工作,建议执行 php -i 命令来查看在信息表格之前或者对应的地方是否有任何错误信息输出。请注意当使用 CGI 摸索时,输出的内容为 HTML 格式,因此输出的信息篇幅较大。 -l --syntax-check 该参数提供了对指定 PHP 代码进行语法检查的方便的方法。如果成功,则向标准输出写入 No syntax errors detected in 2334ac29606bf8a170583e4f7533b1f4 字符串,并且外壳返回值为 0。如果失败,则输出 Errors parsing 2334ac29606bf8a170583e4f7533b1f4 以及内部解析器错误信息到标准输出,同时外壳返回值将别设置为 255。该参数将无法检查致命错误(如未定义函数),如果也希望检测致命错误,请使用 -f 参数。 Note: 该参数不能和 -r 一同使用。 -m --modules 使用该参数,PHP 将打印出内置以及已加载的 PHP 及 Zend 模块: -r --run 使用该参数可以在命令行内运行单行 PHP 代码。无需加上 PHP 的起始和结束标识符(eaae9fd1bc1dded8026482face6dba9c),否则将会导致语法解析错误。 Note: 使用这种形式的 PHP 时,应注意避免和外壳环境进行的命令行参数替换相冲突。 显示语法解析错误的范例 这里的问题在于即使使用了双引号 ",sh/bash 仍然实行了参数替换。由于 $foo 没有被定义,被替换后它所在的位置变成了空字符,因此在运行时,实际被 PHP 读取的代码为: 正确的方法是使用单引号 '。在用单引号引用的字符串中,变量不会被 sh/bash 还原成其原值。 如果使用的外壳不是 sh/bash,可能会碰到更多问题。请将碰到的 Bug 向 » http://bugs.php.net/ 报告。注意,当试图将 shell 变量用到代码中或者使用反斜线时仍然很容易碰到问题。 Note: -r 在 CLI SAPI 中有效,在 CGI SAPI 中无效。 Note: 此选项只用于非常基本的用途。因此一些配置指令(例如 auto_prepend_file 和 auto_append_file)在此模式下被忽略。 -B --process-begin 在处理 stdin 之前先执行 PHP 代码。PHP 5 新加。 -R --process-code 对每个输入行都执行 PHP 代码。PHP 5 新加。此模式下有两个特殊变量:$argn 和 $argi。$argn 包含 PHP 当前处理的行内容,而 $argi 则包含该行号。 -F --process-file 对每个输入行都执行 PHP 文件。PHP 5 新加。 -E --process-end 在处理完输入后执行的 PHP 代码。PHP 5 新加。使用 -B ,-R 和 -E 选项来计算一个项目总行数的例子。 -s --syntax-highlight and --syntax-highlight 显示有语法高亮色彩的源代码。该参数使用内建机制来解析文件并为其生成一个 HTML 高亮版本并将结果写到标准输出。请注意该过程所做的只是生成了一个 ffbe95d20f3893062224282accb13e8f [...] 1cd55414ff5abdfea5dd958e7e547fdd 的 HTML 标记的块,并不包含任何的 HTML 头。 Note: 该选项不能和 -r 参数同时使用。 -v --version 将 PHP,PHP SAPI 和 Zend 的版本信息写入标准输出。例如: -w --strip 显示除去了注释和多余空白的源代码。 Note: 该选项不能和 -r 参数同时使用。 -z --zend-extension 加载 Zend 扩展库。如果仅给定一个文件名,PHP 将试图从当前系统扩展库的默认路径(在 Linux 系统下,该路径通常由 /etc/ld.so.conf 指定)加载该扩展库。如果用一个绝对路径指定文件名,则不会使用系统的扩展库默认路径。如果用相对路径指定的文件名,则 PHP 仅试图在当前目录的相对目录加载扩展库。 PHP 的命令行模式能使得 PHP 脚本能完全独立于 web 服务器单独运行。如果使用 Unix 系统,需要在 PHP 脚本的最前面加上一行特殊的代码,使得它能够被执行,这样系统就能知道用哪个程序去运行该脚本。在 Windows 平台下可以将 php.exe 和 .php 文件的双击属性相关联,也可以编写一个批处理文件来用 PHP 执行脚本。为 Unix 系统增加的第一行代码不会影响该脚本在 Windows 下的运行,因此也可以用该方法编写跨平台的脚本程序。以下是一个简单的 PHP 命令行程序的范例。 Example #1 试图以命令行方式运行的 PHP 脚本(script.php) 在以上脚本中,用第一行特殊的代码来指明该文件应该由 PHP 来执行。在这里使用 CLI 的版本,因此不会有 HTTP 头信息输出。在用 PHP 编写命令行应用程序时,可以使用两个参数:$argc 和 $argv。前面一个的值是比参数个数大 1 的整数(运行的脚本本身的名称也被当作一个参数)。第二个是包含有参数的数组,其第一个元素为脚本的名称,下标为数字 0($argv[0])。 以上程序中检查了参数的个数是大于 1 个还是小于 1 个。此外如果参数是 --help ,-help ,-h 或 -? 时,打印出帮助信息,并同时动态输出脚本的名称。如果还收到了其它参数,将其显示出来。 如果希望在 Unix 下运行以上脚本,需要使其属性为可执行文件,然后简单的运行 script.php echothis 或 script.php -h。在 Windows 下,可以为此编写一个批处理文件: Example #2 运行 PHP 命令行脚本的批处理文件(script.bat) 假设将上述程序命名为 script.php,且 CLI 版的 php.exe 文件放置在 c:\php\cli\php.exe,该批处理文件会帮助将附加的参数传给脚本程序:script.bat echothis 或 script.bat -h。# 以下命令将不会运行 PHP 代码,而只显示 PHP 命令行模式的使用说明:
$ php -r 'var_dump($argv);' -h
Usage: php [options] [-f] <file> [args...]
[...]
# 以下命令将会把“-h”参数传送给脚本程序,PHP 不会显示命令行模式的使用说明:
$ php -r 'var_dump($argv);' -- -h
array(2) {
[0]=>
string(1) "-"
[1]=>
string(2) "-h"
}
#!/usr/bin/php
<?php
var_dump($argv);
?>
$ chmod +x test
$ ./test -h -- foo
array(4) {
[0]=>
string(6) "./test"
[1]=>
string(2) "-h"
[2]=>
string(2) "--"
[3]=>
string(3) "foo"
}
$ php -c /custom/directory/ my_script.php
$ php -c /custom/directory/custom-file.ini my_script.php
-d configuration_directive[=value]
# 取值部分被省略,将会把配置选项设为 "1"
$ php -d max_execution_time
-r '$foo = ini_get("max_execution_time"); var_dump($foo);'
string(1) "1"
# 取值部分为空白,将会把配置选项设为 ""
php -d max_execution_time=
-r '$foo = ini_get("max_execution_time"); var_dump($foo);'
string(0) ""
# 配置选项将被设置成为任何 '=' 字符之后的值
$ php -d max_execution_time=20
-r '$foo = ini_get("max_execution_time"); var_dump($foo);'
string(2) "20"
$ php
-d max_execution_time=doesntmakesense
-r '$foo = ini_get("max_execution_time"); var_dump($foo);'
string(15) "doesntmakesense"
$ php -m
[PHP Modules]
xml
tokenizer
standard
session
posix
pcre
overload
mysql
mbstring
ctype
[Zend Modules]
$ php -r "$foo = get_defined_constants();"
Command line code(1) : Parse error - parse error, unexpected '='
$ php -r " = get_defined_constants();"
$ php -r '$foo = get_defined_constants(); var_dump($foo);'
array(370) {
["E_ERROR"]=>
int(1)
["E_WARNING"]=>
int(2)
["E_PARSE"]=>
int(4)
["E_NOTICE"]=>
int(8)
["E_CORE_ERROR"]=>
[...]
$ find my_proj | php -B '$l=0;' -R '$l += count(@file($argn));' -E 'echo "Total Lines: $l\n";'Total Lines: 37328
$ php -v
PHP 4.3.0 (cli), Copyright (c) 1997-2002 The PHP GroupZend Engine v1.3.0, Copyright (c) 1998-2002 Zend Technologies
#!/usr/bin/php
<?php
if ($argc != 2 || in_array($argv[1], array('--help', '-help', '-h', '-?'))) {
?>
This is a command line PHP script with one option.
Usage:
<?php echo $argv[0]; ?> <option>
<option> can be some word you would like
to print out. With the --help, -help, -h,
or -? options, you can get this help.
<?php
} else {
echo $argv[1];
}
?>
@C:\php\php.exe script.php %1 %2 %3 %