从命令行使用 PHP

目录

简介

CLI SAPI 的主要目标是使用 PHP 开发 shell 应用程序。 CLI SAPI 与其他 SAPI 之间存在一些差异,本章将对此进行解释。值得一提的是,CLICGI 是不同的 SAPI,尽管它们确实共享许多相同的行为。

默认情况下,使用 --enable-cli 启用 CLI SAPI,但可以在运行 ./configure 时使用 --disable-cli 选项禁用它。

CLI/CGI 二进制文件的名 称、位置和是否存在将根据 PHP 在系统上的安装方式而异。默认情况下,在执行 make 时,CGICLI 都会被构建并分别放置在 PHP 源目录中的 sapi/cgi/php-cgisapi/cli/php 中。你会注意到两者都被命名为 php。在 make install 期间发生的事情取决于你的配置行。如果在配置期间选择了模块 SAPI,例如 apxs,或者使用了 --disable-cgi 选项,那么 CLI 将在 make install 期间复制到 {PREFIX}/bin/php,否则 CGI 将被放置在那里。例如,如果你的配置行中包含 --with-apxs ,那么 CLI 将在 make install 期间复制到 {PREFIX}/bin/php 。如果你想覆盖 CGI 二进制文件的安装,请在 make install 后使用 make install-cli。或者,你可以在配置行中指定 --disable-cgi

注意:

因为 --enable-cli--enable-cgi 默认情况下都已启用,所以仅仅在配置行中包含 --enable-cli 并不一定意味着 CLI 将在 make install 期间被复制为 {PREFIX}/bin/php

在 Windows 上,CLI 二进制文件作为 php.exe 分发在主文件夹中。 CGI 版本作为 php-cgi.exe 分发。此外,如果 PHP 使用 --enable-cli-win32 进行配置,则会分发 php-win.exe。它与 CLI 版本执行相同的操作,只是它不会输出任何内容,因此不提供控制台。

注意: 我拥有哪个 SAPI?

从 shell 中,键入 php -v 将告诉你 phpCGI 还是 CLI。还可以参考函数 php_sapi_name() 和常量 PHP_SAPI

注意:

通过在 shell 环境中键入 man php,可以使用 Unix manual 页面。

添加注释

用户贡献的注释 33 个注释

109
sep16 at psu dot edu
12 年前
你可以很容易地使用 parse_str() 函数将命令行参数解析为 $_GET 变量。

<?php

parse_str
(implode('&', array_slice($argv, 1)), $_GET);

?>

它的行为与 cgi-php 中的预期完全相同。

$ php -f somefile.php a=1 b[]=2 b[]=3

这将把 $_GET['a'] 设置为 '1',将 $_GET['b'] 设置为数组('2', '3')。

更好的是,与其在每个文件中都添加这一行,不如利用 PHP 的 auto_prepend_file 指令。将这一行放在它自己的文件中,并在你的 cli 特定 php.ini 中设置 auto_prepend_file 指令,如下所示

auto_prepend_file = "/etc/php/cli-php5.3/local.prepend.php"

它将自动预置到从命令行运行的任何 PHP 文件中。
22
apmuthu at usa dot net
6 年前
在 PHP 中添加一个 pause() 函数,等待任何用户输入并将其返回

<?php
function pause() {
$handle = fopen ("php://stdin","r");
do {
$line = fgets($handle); } while ($line == '');
fclose($handle);
return
$line;
}
?>
23
frankNospamwanted at. toppoint dot. de
9 年前
在不更改 PHP 脚本的情况下解析命令行参数 GET 字符串(Linux shell)
URL:index.php?a=1&b=2
结果:output.html

echo "" | php -R 'include("index.php");' -B 'parse_str($argv[1], $_GET);' 'a=1&b=2' >output.html

(无需更改 php.ini)

你可以将此
echo "" | php -R 'include("'$1'");' -B 'parse_str($argv[1], $_GET);' "$2"
放在名为 "php_get" 的 bash 脚本中,以便像这样使用它
php_get index.php 'a=1&b=2' >output.html
或者定向到文本浏览器...
php_get index.php 'a=1&b=2' |w3m -T text/html
16
PSIKYO at mail dot dlut dot edu dot cn
10 年前
如果你在 Windows 中编辑了一个 php 文件,上传并使用命令行方法在 Linux 上运行它,你可能会遇到运行问题,可能类似于

[root@ItsCloud02 wsdl]# ./lnxcli.php
扩展 './lnxcli.php' 不存在。

或者你可能会遇到其他奇怪的问题。
注意回车键。在 Windows 环境中,回车键生成两个二进制字符 '0D0A'。但在 Linux 中,回车键只生成一个 'OA'。
如果你使用 Windows 编写 php 代码并在 Linux 上将其作为命令行程序运行,我希望这能帮到一些人。
15
ohcc at 163 dot com
7 年前
在 Windows 上使用 -r 与 cli 版本一起使用时,使用 " 而不是 '

php -r "echo 1"
-- 正确

php -r 'echo 1'
PHP 解析错误:语法错误,意外的 ''echo' (T_ENCAPSED_AND_WHITESPACE),期望在命令行代码的第 1 行中找到文件结尾
18
drewish at katherinehouse dot com
18 年前
当你编写单行 php 脚本时,请记住 'php://stdin' 是你的朋友。以下是我用于格式化要包含在我的博客中的 PHP 代码的简单程序

UNIX
cat test.php | php -r "print htmlentities(file_get_contents('php://stdin'));"

DOS/Windows
type test.php | php -r "print htmlentities(file_get_contents('php://stdin'));"
21
Kodeart
12 年前
直接检查,无需调用函数
<?php
if (PHP_SAPI === 'cli')
{
// ...
}
?>

你可以定义一个常量,以便在其他地方使用它
<?php
define
('ISCLI', PHP_SAPI === 'cli');
?>
16
monte at ispi dot net
21 年前
我遇到了 $argv 值包含加号 (+) 时被分割的问题。确保使用 CLI 版本,而不是 CGI 来解决这个问题。

Monte
14
lucas dot vasconcelos at gmail dot com
17 年前
这只是之前脚本的另一种变体,它将不以“-”或“--”开头的参数分组。

<?php
function arguments($argv) {
$_ARG = array();
foreach (
$argv as $arg) {
if (
ereg('--([^=]+)=(.*)',$arg,$reg)) {
$_ARG[$reg[1]] = $reg[2];
} elseif(
ereg('^-([a-zA-Z0-9])',$arg,$reg)) {
$_ARG[$reg[1]] = 'true';
} else {
$_ARG['input'][]=$arg;
}
}
return
$_ARG;
}

print_r(arguments($argv));
?>

$ php myscript.php --user=nobody /etc/apache2/*
Array
(
[input] => Array
(
[0] => myscript.php
[1] => /etc/apache2/apache2.conf
[2] => /etc/apache2/conf.d
[3] => /etc/apache2/envvars
[4] => /etc/apache2/httpd.conf
[5] => /etc/apache2/mods-available
[6] => /etc/apache2/mods-enabled
[7] => /etc/apache2/ports.conf
[8] => /etc/apache2/sites-available
[9] => /etc/apache2/sites-enabled
)

[user] => nobody
)
15
Anonymous
3 年前
我们可以直接将许多参数传递到哈希邦行。
例如,通过 php 的 -d 参数设置许多 ini 设置。
---
#!/usr/bin/php -d memory_limit=2048M -d post_max_size=0
phpinfo();
exit;
---
./script | grep memory
memory_limit => 2048M => 2048M
---
但我们也可以将这种行为应用于第二个脚本,以便它通过哈希邦调用第一个脚本作为解释器。
---
#!./script arg1 arg2 arg3
---
但是,参数以不同的方式分配到 $argv 中。

所有参数都在 $argv[1] 中,$argv[0] 是解释器脚本名称,$argv[1] 是调用者脚本名称。

要将参数恢复到 $argv 中,我们可以简单地测试 $argv[1] 是否包含空格,然后像往常一样再次分配。

#!/usr/bin/php -d memory_limit=2048M -d post_max_size=0
<?php
var_dump
($argv);
if (
strpos($argv[1], ' ') !== false){
$argw = explode(" ", $argv[1]);
array_unshift($argw, $argv[2]);
$argv = $argw;
}
var_dump($argv); ?>
---
array(3) {
[0]=>
string(8) "./script"
[1]=>
string(15) "arg1 arg2 arg3 "
[2]=>
string(14) "./other_script"
}
array(4) {
[0]=>
string(8) "./other_script"
[1]=>
string(4) "arg1"
[2]=>
string(4) "arg2"
[3]=>
string(4) "arg3"
}
---
这将保持所有情况下的相同行为,并允许甚至双击一个脚本来调用另一个脚本的两个参数,甚至创建一个完整的解释器语言层。另一个脚本不必是 php。注意路径。
26
ben at slax0rnet dot com
20 年前
注意那些尝试从命令行使用交互模式的人。

交互模式的目的是解析代码片段,而不会实际离开 php,它的工作方式如下

[root@localhost php-4.3.4]# php -a
Interactive mode enabled

<?php echo "hi!"; ?>
<注意,这里我们会按下 CTRL-D 来解析我们输入的所有内容>
hi!
<?php exit(); ?>
<ctrl-d 在这里再次按下>
[root@localhost php-4.3.4]#

我注意到这在文档中被省略了,希望它对某人有所帮助!
20
notreallyanaddress at somerandomaddr dot com
14 年前
如果你想与用户进行交互并接受用户输入,你只需要从 stdin 读取。

<?php
echo "你确定要这样做吗?输入 'yes' 继续:" ;
$handle = fopen ("php://stdin","r");
$line = fgets($handle);
if(
trim($line) != 'yes'){
echo
"ABORTING!\n";
exit;
}
echo
"\n";
echo
"谢谢,继续...\n";
?>
15
OverFlow636 at gmail dot com
18 年前
我需要这个,你可能不需要。
将执行参数放入 $_GET 中。
<?php
if ($argv) {
foreach (
$argv as $k=>$v)
{
if (
$k==0) continue;
$it = explode("=",$argv[$i]);
if (isset(
$it[1])) $_GET[$it[0]] = $it[1];
}
}
?>
16
thomas dot harding at laposte dot net
16 年前
解析命令行:优化是邪恶的!

本页所有贡献者都忘记的一件事是,你可以用单引号或双引号包围 argv。因此,join 与 preg_match_all 结合在一起始终会破坏它 :)

以下是一个提议

#!/usr/bin/php
<?php
print_r
(arguments($argv));

function
arguments ( $args )
{
array_shift( $args );
$endofoptions = false;

$ret = array
(
'commands' => array(),
'options' => array(),
'flags' => array(),
'arguments' => array(),
);

while (
$arg = array_shift($args) )
{

// 如果我们已经到达了选项的末尾,
//我们将所有剩余的 argv 转换为参数
if ($endofoptions)
{
$ret['arguments'][] = $arg;
continue;
}

// 它是一个命令吗?(以 -- 为前缀)
if ( substr( $arg, 0, 2 ) === '--' )
{

// 它是否是选项结束标志?
if (!isset ($arg[3]))
{
$endofoptions = true;; // 选项结束;
continue;
}

$value = "";
$com = substr( $arg, 2 );

// 它是否是 '--option=argument' 的语法?
if (strpos($com,'='))
list(
$com,$value) = split("=",$com,2);

// 选项后面没有其他选项,而是参数
elseif (strpos($args[0],'-') !== 0)
{
while (
strpos($args[0],'-') !== 0)
$value .= array_shift($args).' ';
$value = rtrim($value,' ');
}

$ret['options'][$com] = !empty($value) ? $value : true;
continue;

}

// 它是一个标志或一系列标志吗?(以 - 为前缀)
if ( substr( $arg, 0, 1 ) === '-' )
{
for (
$i = 1; isset($arg[$i]) ; $i++)
$ret['flags'][] = $arg[$i];
continue;
}

// 最后,它既不是选项,也不是标志,也不是参数
$ret['commands'][] = $arg;
continue;
}

if (!
count($ret['options']) && !count($ret['flags']))
{
$ret['arguments'] = array_merge($ret['commands'], $ret['arguments']);
$ret['commands'] = array();
}
return
$ret;
}

exit (
0)

/* vim: set expandtab tabstop=2 shiftwidth=2: */
?>
11
rob
17 年前
我使用 emacs 的 c 模式进行编辑。在 4.3 中,像这样启动一个 cli 脚本

#!/usr/bin/php -q /* -*- c -*- */
<?php

告诉 emacs 在我加载文件进行编辑时自动进入 c
-模式。 the '-q' 标志实际上没有任何作用(在旧的 cgi 版本中,它会在脚本运行时抑制 html 输出),但它会导致 php 忽略注释掉的模式行。

在 5.2 中,'
-q' 显然已被弃用。用 '--' 替换它以实现 4.3 呼叫 - 带有 emacs 模式行的行为:

#!/usr/bin/php -- /* -*- c -*- */
<?php

不要返回到你的 4.3 系统
替换'-q' with '--'; 它似乎会导致 php 挂起并等待 STDIN...
11
goalain eat gmail dont com
17 年前
如果你的 php 脚本没有用 shebang (#!/usr/bin/php) 运行,
并且它发出漂亮且信息丰富的错误消息
"Command not found." 只需 dos2unix yourscript.php
et voila。

如果你仍然收到 "Command not found."
只需尝试运行它,如 ./myscript.php,带 "./"
如果它有效 - 这意味着你的当前目录不在可执行文件搜索路径中。

如果你的 php 脚本没有用 shebang (#/usr/bin/php) 运行,
并且它发出漂亮且信息丰富的消息
"Invalid null command." 它可能是因为 shebang 行中缺少 "!"(如上所示)或该区域中的其他内容。

\Alon
9
jeff at noSpam[] dot genhex dot net
21 年前
你也可以在使用 chmod 对文件进行更改后(即:chmod 755 file.php)从命令行调用脚本。

在文件的首行输入 "#!/usr/bin/php"(或指向你 php 可执行文件的位置)。如果你想抑制 PHP 头部,请在你的路径中使用 "#!/usr/bin/php -q" 行。
8
roberto dot dimas at gmail dot com
19 年前
我喜欢 perl 和 vbscripts 的一件事是,我可以将一个文件命名为例如 'test.pl',只需在 Windows 命令行中输入 'test',而无需使用 .pl 扩展名,命令处理器就知道它是一个 perl 文件并使用 perl 命令解释器执行它。

我对文件扩展名 .php3 做了同样的事情(我将专门使用 php3 来执行命令行 php 脚本,我这样做是因为我的文本编辑器 VIM 6.3 已经为 .php3 文件提供了正确的语法高亮显示)。

我在 Windows XP 中修改了 PATHEXT 环境变量,从 "系统控制面板小程序 -> 高级选项卡 -> 环境变量按钮 -> 系统变量文本区域"。

然后从控制面板 "文件夹选项" 小程序 -> 文件类型选项卡中,我使用 "新建" 按钮添加了一个新的文件扩展名(php3),并在弹出的窗口中输入 php3。

然后在 "php3 扩展名的详细信息" 区域中,我使用 "更改" 按钮查找 Php.exe 可执行文件,以便 php3 文件扩展名与 php 可执行文件相关联。

你还需要修改 "PATH" 环境变量,使其指向 php 可执行文件所在的文件夹。

希望这对某些人有用。
7
phpnotes at ssilk dot de
21 年前
为了像在 HTTP 模式中那样在交互模式中传递 GET 变量(例如,你的 URI 是 myprog.html?hugo=bla&bla=hugo),你需要调用

php myprog.html '&hugo=bla&bla=hugo'

(两个 & 而不是 ? 和 &!)

$ARGC、$ARGV 值之间只有一点细微差别,但我认为在这些情况下并不重要。
8
Anonymous
14 年前
使用 CLI(至少在 WIN 上),某些 INI 路径相对于当前工作目录。例如,如果你的 error_log = "php_errors.log",那么 php_errors.log 将在你的当前目录中创建(如果已存在则追加),前提是你具有写入权限。为了避免因为这种行为而导致在各种位置出现随机错误日志,你可能希望将 error_log 设置为完整路径,也许指向 php.exe 目录。
9
linn at backendmedia dot com
20 年前
对于那些希望使用旧的 CGI 行为(更改为脚本的实际目录)的用户,请使用
chdir(dirname($_SERVER['argv'][0]));

在你的脚本开头。
9
eric dot brison at anakeen dot com
17 年前
只是对先前脚本的变体,以便也接受带 "=" 的参数
<?php
function arguments($argv) {
$_ARG = array();
foreach (
$argv as $arg) {
if (
ereg('--([^=]+)=(.*)',$arg,$reg)) {
$_ARG[$reg[1]] = $reg[2];
} elseif(
ereg('-([a-zA-Z0-9])',$arg,$reg)) {
$_ARG[$reg[1]] = 'true';
}

}
return
$_ARG;
}
?>
$ php myscript.php --user=nobody --password=secret -p --access="host=127.0.0.1 port=456"
Array
(
[user] => nobody
[password] => secret
[p] => true
[access] => host=127.0.0.1 port=456
)
4
sam marshall
5 年前
使用 -R 标志时,包含当前行内容(不包括 LF)的变量名称为 $argn。

例如,你可以执行以下代码

cat file.txt | php -R 'echo $argn . "\n";'

这将直接输出输入文件中的每一行,不做任何处理。
6
losbrutos at free dot fr
16 年前
另一个“另一个变体”

<?php
function arguments($argv)
{
$_ARG = array();
foreach (
$argv as $arg)
{
if (
preg_match('#^-{1,2}([a-zA-Z0-9]*)=?(.*)$#', $arg, $matches))
{
$key = $matches[1];
switch (
$matches[2])
{
case
'':
case
'true':
$arg = true;
break;
case
'false':
$arg = false;
break;
default:
$arg = $matches[2];
}
$_ARG[$key] = $arg;
}
else
{
$_ARG['input'][] = $arg;
}
}
return
$_ARG;
}
?>

$php myscript.php arg1 -arg2=val2 --arg3=arg3 -arg4 --arg5 -arg6=false

Array
(
[input] => Array
(
[0] => myscript.php
[1] => arg1
)

[arg2] => val2
[arg3] => arg3
[arg4] => true
[arg5] => true
[arg5] => false
)
7
docey
19 年前
不知道这在 Linux 上是否一样,但在 Windows 上,每次
你发送一些东西到 PHP 正在等待的控制台屏幕上
控制台要返回。因此,如果你发送大量的短文本,
控制台将开始使用
比 PHP 更多的 CPU 周期,从而降低脚本速度。

看看这个模式
CPU 周期:1 -> PHP:print("a");
CPU 周期:2 -> cmd:output("a");
CPU 周期:3 -> PHP:print("b");
CPU 周期:4 -> cmd:output("b");
CPU 周期:5 -> PHP:print("c");
CPU 周期:6 -> cmd:output("c");
CPU 周期:7 -> PHP:print("d");
CPU 周期:8 -> cmd:output("d");
CPU 周期:9 -> PHP:print("e");
CPU 周期:0 -> cmd:output("e");

屏幕上只显示“abcde”。但如果你这样写
你的脚本,它会快得多
CPU 周期:1 -> PHP:ob_start();
CPU 周期:2 -> PHP:print("abc");
CPU 周期:3 -> PHP:print("de");
CPU 周期:4 -> PHP:$data = ob_get_contents();
CPU 周期:5 -> PHP:ob_end_clean();
CPU 周期:6 -> PHP:print($data);
CPU 周期:7 -> cmd:output("abcde");

这只是一个简单的例子,但如果你正在编写一个
向控制台输出大量内容的应用程序,例如文本
基于屏幕并频繁更新,那么最好
首先缓存所有输出,并将输出作为一大块
文本输出,而不是一次输出一个字符。

输出缓冲非常适合这种情况。在我的脚本中,我输出
近 4000 个字符的信息,仅仅通过先缓存它,
速度提高了近 400%,并降低了 CPU 使用率。

因为显示的内容并不重要,无论是 2
个字符还是 40,000 个字符,仅仅是输出调用就需要
大量的時間。记住这一点。

也许有人可以测试一下这在基于 Unix 的系统上是否一样。
似乎 STDOUT 流只是等待
控制台报告就绪,然后继续执行。
8
Adam, php(at)getwebspace.com
21 年前
好的,我在 PHP > 4.3.x 上花了很多时间,不知道该使用 CLI 还是 CGI。4.3.2 的 CGI 版本将在(浏览器中)返回
---
未指定输入文件。
---

而 CLI 版本将返回
---
500 内部服务器错误
---

看来在 CGI 模式下,PHP 查看环境变量 PATH_TRANSLATED 来确定要执行的脚本,并忽略命令行。这就是为什么在缺少此环境变量的情况下,你会得到“未指定输入文件”。但是,在 CLI 模式下,不会打印 HTTP 头。我相信这两种情况都是预期的行为,但当你的 CGI 包装器发送环境变量,但将实际的脚本名称传递给命令行时,就会产生问题。

通过修改我的 CGI 包装器来创建此 PATH_TRANSLATED 环境变量,解决了我的问题,我能够运行 4.3.2 的 CGI 版本。
5
obfuscated at emailaddress dot com
19 年前
这个帖子不是 PHP 特有的问题,但希望可以帮助其他人节省几个小时的麻烦。我在 MacOS 上运行(虽然这可能发生在任何 *nix 上),我无法让脚本执行,除非从命令行明确调用 php

[macg4:valencia/jobs] tim% test.php
./test.php:找不到命令。

但是,当从命令行调用 php 时,它运行得很好

[macg4:valencia/jobs] tim% php test.php
好吧,我们到了这里... 现在怎么办?

文件访问模式是否设置为可执行?是的。

[macg4:valencia/jobs] tim% ls -l
总计 16
-rwxr-xr-x 1 tim staff 242 2 月 24 日 17:23 test.php

当然,你还记得在你的脚本第一行添加 php 命令,对吧?当然。

#!/usr/bin/php
<?php print "Well, here we are... Now what?\n"; ?>

那么为什么它不起作用呢?嗯,正如我所说... 在 Mac 上... 但我偶尔也会在我的 Windows 便携式设备上编辑文件(例如,当我旅行没有我的 Mac 时)... 使用,比如,Windows 上的 WordPad... 和 Mac 上的 BBEdit...

啊哈... 在 BBEdit 中检查文件是如何保存的!Mac?Unix?还是 Dos?Bingo。它被保存为 Dos 格式。将其更改为 Unix

[macg4:valencia/jobs] tim% ./test.php
好吧,我们到了这里... 现在怎么办?
[macg4:valencia/jobs] tim%

注意:如果你在多个平台(例如 Windows 和 Linux)上编辑 PHP 文件,请确保仔细检查文件是否以 Unix 格式保存... 那些 \r 和 \n 会咬你!
4
bluej100@gmail
17 年前
在 5.1.2(以及其他版本,我假设)中,-f 形式会静默地从 $_SERVER['argv'] 中删除脚本名称后面的第一个参数。我建议避免使用它,除非你确实需要它用于特殊情况。
4
Popeye at P-t-B dot com
21 年前
在 *nix 系统中,使用 WHICH 命令显示 PHP 二进制可执行文件的路径。这将是你的 PHP shell 脚本文件中使用的路径。(#!/path/to/php -q)并使用 -v 选项从命令行执行 PHP 以查看你正在运行的版本。

例如

# which php
/usr/local/bin/php
# php -v
PHP 4.3.1 (cli) (built: Mar 27 2003 14:41:51)
Copyright (c) 1997-2002 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2002 Zend Technologies

在上面的例子中,你将使用:#!/usr/local/bin/php

另外注意,如果你在你的 PATH 中没有当前/默认目录 (.),你将不得不使用 ./scriptfilename 从命令行执行你的脚本文件(否则你会收到“找不到命令”的错误)。使用 ENV 命令显示你的 PATH 环境变量的值。
4
Alexander Plakidin
21 年前
如何使用 PHP 4.3.0 从命令行运行 PHP 脚本时将 PHP 脚本的当前目录更改为脚本的目录?
(你可能需要在使用 PHP 4.3.0 运行旧脚本时将此添加到旧脚本中以确保向后兼容性)

这是我正在使用的
chdir(preg_replace('/\\/[^\\/]+$/',"",$PHP_SELF));

注意:文档指出“PHP_SELF”在命令行 PHP 脚本中不可用。尽管它确实可用。可能这会在将来的版本中发生改变,所以不要依赖于此行代码...

如果你有 register_globals=Off,请使用 $_SERVER['PHP_SELF'] 而不是 $PHP_SELF。
4
stromdotcom at hotmail dot com
18 年前
在 Windows 应用程序中使用 php-win.exe 作为子进程来处理脚本有一些怪癖(全部与 Windows 应用程序和控制台应用程序之间的管道有关)。

要在 C++ 中执行此操作

// 我们将在创建后运行 php.exe 作为子进程
// 两个管道并将它们附加到 stdin 和 stdout
// 子进程
// 定义 sa 结构体,以便子进程继承我们的句柄

SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;

// 为我们的两个管道创建句柄(每个管道两个句柄,每个句柄一端)
// 我们将有一个用于 stdin 的管道,一个用于 stdout 的管道,每个管道都有一个 READ 和 WRITE 端
HANDLE hStdoutRd, hStdoutWr, hStdinRd, hStdinWr;

// 现在创建管道,并使它们可继承
CreatePipe (&hStdoutRd, &hStdoutWr, &sa, 0))
SetHandleInformation(hStdoutRd, HANDLE_FLAG_INHERIT, 0);
CreatePipe (&hStdinRd, &hStdinWr, &sa, 0)
SetHandleInformation(hStdinWr, HANDLE_FLAG_INHERIT, 0);

// 现在我们有了两个管道,我们可以创建进程
// 首先,填写使用结构体
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hStdoutWr;
si.hStdInput = hStdinRd;

// 最后,创建进程
CreateProcess (NULL, "c:\\php\\php-win.exe", NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);

// 关闭我们不使用的句柄
CloseHandle(hStdoutWr);
CloseHandle(hStdinRd);

// 现在我们已经运行了进程,我们可以开始向它推送 PHP
WriteFile(hStdinWr, "<?php echo 'test'; ?>", 9, &dwWritten, NULL);

// 当我们完成写入 stdin 时,我们将关闭该管道
CloseHandle(hStdinWr);

// 从 stdout 读取稍微复杂一点
int i;

std::string processed("");
char buf[128];

while ( (ReadFile(hStdoutRd, buf, 128, &dwRead, NULL) && (dwRead != 0)) ) {
for (i = 0; i < dwRead; i++)
processed += buf[i];
}

// 完成读取,因此也关闭此句柄
CloseHandle(hStdoutRd);

完整的实现(作为 C++ 类实现)可以在 http://www.stromcode.com 上找到
3
pyxl at jerrell dot com
22 年前
假设 --prefix=/usr/local/php,最好从 /usr/bin/php 或 /usr/local/bin/php 创建一个指向 /usr/local/php/bin/php 的符号链接,这样它既在你的路径中,又会在每次重建时自动修正。如果你忘记在重建后复制二进制文件,当你遇到问题时,你可能会进行各种无谓的搜索。
2
james_s2010 at NOSPAM dot hotmail dot com
16 年前
我一直在寻找一种方法来从用户那里交互式地获取单个字符的响应。使用 STDIN 与 fread、fgets 等方法只有在按下 Enter 键后才会起作用。所以我找到了以下方法:

#!/usr/bin/php -q
<?php
function inKey($vals) {
$inKey = "";
While(!
in_array($inKey,$vals)) {
$inKey = trim(`read -s -n1 valu;echo \$valu`);
}
return
$inKey;
}
function
echoAT($Row,$Col,$prompt="") {
// 在特定的屏幕坐标显示提示
echo "\033[".$Row.";".$Col."H".$prompt;
}
// 在位置 10,10 显示提示
echoAT(10,10,"Opt : ");

// 定义可接受的响应
$options = array("1","2","3","4","X");

// 获取用户响应
$key = inKey($options);

// 显示用户响应并退出
echoAT(12,10,"Pressed : $key\n");
?>

希望对大家有所帮助。
To Top