复杂情况下的引用规则

复杂情况下的引用规则

在编写代码行时,我们有时需要考虑转义某些字符。

我遇到了一个我无法独自回答的情况

在 PHP 中,exec 命令需要一个用引号 (') 括起来的字符串。我们想要调用命令 /bin/bash -c ,它还需要一个用引号 (') 括起来的字符串

该问题的解决方法如下:

$line = exec('/bin/bash -c \'read -e -p "Check to confirm string: " -i "'.$preFill.'" input; echo $input\'');

只要您不想在向用户建议的文本中插入字符 ('),就没有问题。我们可以看到一些使用 php -a 进行交互模式的示例:

php > $preFill = 'I m reach';
php > $line = exec('/bin/bash -c \'read -e -p "Check to confirm string: " -i "'.$preFill.'" input; echo $input\'');
Check to confirm string: I m reach
php >

问题是:我必须考虑哪些转义规则才能以正确的方式将“我已到达”放入 $preFill 中?

答案1

您需要对传递到的代码bash和传递到的代码sh(由php's开始exec())进行一些引用:

$preFill = 'I m reach';
$prompt = 'Check to confirm string: ';
$bash_code = 'IFS= read -re -p ' .
              escapeshellarg($prompt) .
              ' -i ' .
              escapeshellarg($preFill) .
              ' input; printf "%s\n" "$input"';
$sh_code = 'exec /bin/bash -c ' . escapeshellarg($bash_code);
$output = exec($sh_code);
echo $output;

你也忘记了IFS=-rread, 和关于 shell 参数扩展的一些引用,并记住echo不能用于任意数据

启动两者shbash提示用户似乎有点矫枉过正。

答案2

exec('/bin/bash -c \'read -e -p "... " -i "'.$preFill.'" input; echo $input\'');

这里有一些问题。首先,您正在运行一个 shell(通过exec)来运行bash -c ...,这意味着 Bash 最终运行的代码也必须为中间 shell 引用。您可以通过使用允许直接运行的函数来避免这种情况bash,参数位于单独的数组元素(或类似元素)中,而不涉及中间 shell。可能是这样的proc_open()

其次,您将数据(该$preFill变量)嵌入到传递给 Bash 的代码中。通过正确的引用和变量的良好值,这可以工作,但如果$preFill可以例如包含引号本身,它就会变得痛苦。如果变量可以由用户控制,那么这种痛苦就会变成安全漏洞。更好的方法是将所需的值作为命令行参数传递给 shell,或者作为环境变量,然后在 shell 程序中引用$1或来获取该值。$val

好吧,运行一个(或两个)shell 似乎read非常愚蠢。花一些时间寻找直接从 PHP 执行此操作的更好方法可能会更好。

答案3

鉴于您的问题 Y,当使用 PHP 调用系统 shell 来利用 bash 的读取/读取行功能时,如何正确转义字符串,您已经收到了一些关于如何执行此操作的出色答案。

这篇文章试图解决您的问题 X——您最初的问题——我认为这是,如何在 PHP 中捕获用户输入,同时提供预先填充的默认值?通过使用本机 PHP 解决方案,可以避免粗糙的多级字符转义的整个问题,正如 @roaima 在您的帖子的评论中暗示的那样。

readline 的 PHP 文档包括用户 taneli 的示例大约 2009 年,它展示了如何执行您正在寻求的操作,而不必求助于外部 shell 调用。我稍微扩展了这个例子,但我在这里重复 taneli 的工作:

$ cat test.php
<?php

function readline_callback($ret)
  {
    global $prompt_answer, $prompt_finished;
    $prompt_answer = $ret;
    $prompt_finished = TRUE;
    readline_callback_handler_remove();
  }

$prompt_string = 'Check to confirm string: ';

readline_callback_handler_install($prompt_string,
                                  'readline_callback');

$preFill = 'foobar';
for ($i = 0; $i < strlen($preFill); $i++)
{
  readline_info('pending_input', substr($preFill, $i, 1));
  readline_callback_read_char();
}

$prompt_finished = FALSE;
$prompt_answer   = FALSE;

while (!$prompt_finished)
  readline_callback_read_char();

echo 'You wrote: ' . $prompt_answer . "\n"; 

$prompt_string = 'Check to confirm another string: ';
readline_callback_handler_install($prompt_string,
                                  'readline_callback');

$preFill = $prompt_answer;
for ($i = 0; $i < strlen($preFill); $i++)
{
  readline_info('pending_input', substr($preFill, $i, 1));
  readline_callback_read_char();
}

$prompt_finished = FALSE;
$prompt_answer   = FALSE;

while (!$prompt_finished)
  readline_callback_read_char();

echo 'You wrote: ' . $prompt_answer . "\n"; 

?>

输出:

$ php test.php 
Check to confirm string: foobar

我将附加“ is the default”并按Enter

You wrote: foobar is the default
Check to confirm another string: foobar is the default

我将按下Home并放在Now "字符串的开头。然后我将按下End并放在" is it's own default.字符串的末尾,然后按下Enter

You wrote: Now "foobar is the default" is it's own default.

相关内容