複雑な状況での引用規則

複雑な状況での引用規則

コード行を作成するときに、特定の文字をエスケープする必要がある場合があります。

自分で答えられない状況にぶつかりました。

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と渡されたコードshphp'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=-rためのreadシェルパラメータ拡張に関する引用、そして覚えておいてくださいecho任意のデータと一緒に使用することはできません

両方を実行しshbashユーザーにメッセージを表示するのは過度のようです。

答え2

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

これにはいくつかの問題があります。まず、シェルを実行していますexecbash -c ...これは、Bashが最終的に実行するコードが中間シェルでも参照される必要があることを意味します。bashシェルを介さずに別の配列要素(または同様の)の引数を使用して直接実行できる関数を使用すると、これを回避できます。これもできますproc_open()

$preFill次に、Bashに渡すコードにデータ(変数)を含めます。正しい引用文と変数の良い値を使用すると、これは可能ですが、たとえば、引用文$preFill自体を含めることができる場合は痛いです。ユーザーが変数を制御できる場合、この問題はセキュリティホールになります。より良いアプローチは、必要な値をコマンドライン引数または環境変数としてシェルに渡し、シェルプログラムから$1値を参照または取得することです。$val

まあ、シェル(または2つ)を実行するのはreadかなり愚かなようです。 PHPで直接これを行うより良い方法を見つけるのに時間を費やす方が良いかもしれません。

答え3

あなたの質問Yについて、bashの読み取り/読み取り機能を利用するためにPHPを使用してシステムシェルを呼び出すときに文字列を適切にエスケープする方法について、あなたはこれを行う方法について素晴らしい答えを受けました。

この投稿はあなたの質問に答えようとします @roaimaが投稿のコメントで示したように、基本的なPHPソリューションを使用すると、粗雑なマルチレベル文字エスケープの問題を回避できます。

readlineのPHPドキュメント含むユーザーtaneliの例2009年頃は、外部シェル呼び出しに頼らずに必要な操作を実行する方法を示しています。例を少し拡張しましたが、ここでは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.

関連情報