PHP Conference Japan 2024

从命令行使用 PHP

目录

简介

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

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

CLI/CGI 二进制文件的文件名、位置和是否存在将根据 PHP 在系统上的安装方式而有所不同。默认情况下,在执行 make 时,CGI 和 CLI 都将构建并分别放置为 sapi/cgi/php-cgisapi/cli/php,位于 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 复制。

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

注意我有什么 SAPI?

从 shell 中,键入 php -v 将告诉您 php 是 CGI 还是 CLI。另请参阅函数 php_sapi_name() 和常量 PHP_SAPI

注意:

可以通过在 shell 环境中键入 man php 来获得 Unix 的 `man` 手册页。

添加注释

用户贡献的注释 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
7 年前
向 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
10 年前
在不更改 PHP 脚本的情况下(linux shell)解析命令行参数 GET 字符串
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"
放在一个 bash 脚本“php_get”中,以便像这样使用它
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
11 年前
如果您在 Windows 中编辑一个 php 文件,上传并在 Linux 上使用命令行方法运行它。您可能会遇到类似这样的运行问题

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

或者您可能会遇到其他一些奇怪的问题。
注意回车键。在 Windows 环境中,回车键生成两个二进制字符“0D0A”。但在 Linux 中,回车键只生成一个“OA”。


如果您使用 Windows 编写 PHP 代码,并希望将其作为命令行程序在 Linux 上运行,希望这能帮到您。
15
ohcc at 163 dot com
8 年前
在 Windows 上使用 CLI 版本并带 -r 参数时,请使用 " 而不是 '。

php -r "echo 1"
-- 正确

php -r 'echo 1'
PHP Parse error: syntax error, unexpected ''echo' (T_ENCAPSED_AND_WHITESPACE), expecting end of file in Command line code on line 1
18
drewish at katherinehouse dot com
19 年前
当您编写单行 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
13 年前
直接检查,无需调用函数
<?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/*
数组
(
[input] => 数组
(
[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
匿名用户
3 年前
我们可以直接将许多参数传递到 shebang 行。
例如,通过 php 的 -d 参数设置许多 ini。
---
#!/usr/bin/php -d memory_limit=2048M -d post_max_size=0
phpinfo();
exit;
---
./script | grep memory
memory_limit => 2048M => 2048M
---
但我们也可以在第二个脚本中使用此行为,以便它通过 shebang 调用第一个脚本作为解释器
---
#!./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); ?>
---
数组(3) {
[0]=>
字符串(8) "./script"
[1]=>
字符串(15) "arg1 arg2 arg3 "
[2]=>
字符串(14) "./other_script"
}
数组(4) {
[0]=>
字符串(8) "./other_script"
[1]=>
字符串(4) "arg1"
[2]=>
字符串(4) "arg2"
[3]=>
字符串(4) "arg3"
}
---
这将确保在所有情况下都保持相同行为,并允许甚至双击脚本以调用另一个脚本的参数,甚至创建一个完整的解释器语言层。另一个脚本不必是 php。注意路径。
26
ben at slax0rnet dot com
20 年前
对于尝试从命令行使用交互模式的人员,请注意。

交互模式的目的是解析代码片段而不实际退出 php,其工作方式如下

[root@localhost php-4.3.4]# php -a
已启用交互模式

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

我注意到文档中不知何故省略了这一点,希望它能帮到某人!
20
notreallyanaddress at somerandomaddr dot com
15 年前
如果要与用户进行交互并接受用户输入,只需从 stdin 读取即可。

<?php
echo "您确定要执行此操作吗?键入 'yes' 以继续:";
$handle = fopen ("php://stdin","r");
$line = fgets($handle);
if(
trim($line) != 'yes'){
echo
"中止!\n";
exit;
}
echo
"\n";
echo
"谢谢,继续...\n";
?>
15
OverFlow636 at gmail dot com
19 年前
我需要这个,你可能不需要。
将执行参数放入 $_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
-模式。 '-q' 标志实际上什么也没做(在旧的 cgi 版本中,它在脚本运行时抑制了 html 输出),但它导致 php 忽略了注释掉的模式行。

在 5.2 中,'
-q' 显然已被弃用。将其替换为 '--' 以实现 4.3 中使用 emacs 模式行调用的行为:

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

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

如果你仍然收到 "命令未找到。"
只需尝试将其作为 ./myscript.php 运行,使用 "./"
如果它有效 - 则意味着你的当前目录不在可执行文件搜索路径中。

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

\Alon
9
jeff at noSpam[] dot genhex dot net
22 年前
你也可以在 chmod 文件后(例如:chmod 755 file.php)从命令行调用脚本。

在文件的首行输入 "#!/usr/bin/php"(或指向 php 可执行文件的任何位置)。如果你想抑制 PHP 标头,请使用 "#!/usr/bin/php -q" 行作为你的路径。
8
roberto dot dimas at gmail dot com
19 年前
我喜欢 perl 和 vbscript 的其中一点是,我可以命名一个文件,例如 '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
22 年前
要在交互模式下像在 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"
数组
(
[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
17 年前
另一个“另一个变体”

<?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

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

[arg2] => val2
[arg3] => arg3
[arg4] => true
[arg5] => true
[arg5] => false
)
7
docey
19 年前
不知道在 Linux 上是否相同,但在 Windows 上每次
你发送一些东西到控制台屏幕,php 都会等待
控制台返回。因此,如果您发送大量的小
少量文本,控制台开始使用
比 php 更多的 cpu 周期,从而减慢脚本速度。

看看这个方案
cpu-cycle:1 ->php: print("a");
cpu-cycle:2 ->cmd: output("a");
cpu-cycle:3 ->php: print("b");
cpu-cycle:4 ->cmd: output("b");
cpu-cycle:5 ->php: print("c");
cpu-cycle:6 ->cmd: output("c");
cpu-cylce:7 ->php: print("d");
cpu-cycle:8 ->cmd: output("d");
cpu-cylce:9 ->php: print("e");
cpu-cycle:0 ->cmd: output("e");

在屏幕上只显示“abcde”。但是如果你这样编写
你的脚本,它会快得多
cpu-cycle:1 ->php: ob_start();
cpu-cycle:2 ->php: print("abc");
cpu-cycle:3 ->php: print("de");
cpu-cycle:4 ->php: $data = ob_get_contents();
cpu-cycle:5 ->php: ob_end_clean();
cpu-cycle:6 ->php: print($data);
cpu-cycle: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);

// 当我们完成向标准输入写入数据后,关闭管道
CloseHandle(hStdinWr);

// 从标准输出读取数据稍微复杂一点
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
17 年前
我一直在寻找一种从用户那里交互式获取单个字符响应的方法。使用 STDIN 和 fread、fgets 等方法只有在按下回车键后才能工作。所以我改用了这种方法

#!/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