코드 줄을 작성할 때 때때로 특정 문자를 이스케이프 처리해야 하는 경우가 있습니다.
스스로 대답할 수 없는 상황에 부딪혔어요
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=
그리고 -r
를 위한read
, 그리고쉘 매개변수 확장에 대한 인용문, 그리고 기억하세요echo
임의의 데이터와 함께 사용할 수 없습니다.
둘 다 실행 sh
하고 bash
사용자에게 메시지를 표시하는 것은 과도한 것처럼 보입니다.
답변2
exec('/bin/bash -c \'read -e -p "... " -i "'.$preFill.'" input; echo $input\'');
여기에는 몇 가지 문제가 있습니다. 먼저 셸을 실행하고 있습니다 exec
. bash -c ...
이는 Bash가 최종적으로 실행하는 코드가 중간 셸에서도 참조되어야 함을 의미합니다. bash
셸을 개입시키지 않고 별도의 배열 요소(또는 이와 유사한)의 인수를 사용하여 직접 실행할 수 있는 함수를 사용하면 이를 방지할 수 있습니다 . 이럴 수도 있지proc_open()
.
$preFill
둘째, Bash에 전달하는 코드에 데이터(변수)를 포함시킵니다 . 올바른 인용문과 변수에 대한 좋은 값을 사용하면 이것이 가능하지만 $preFill
예를 들어 인용문 자체가 포함될 수 있다면 고통스럽습니다. 사용자가 변수를 제어할 수 있다면 이러한 어려움은 보안 허점이 됩니다. 더 나은 접근 방식은 원하는 값을 명령줄 인수나 환경 변수로 셸에 전달한 다음 셸 프로그램에서 $1
값을 참조하거나 가져오는 것입니다 .$val
글쎄, 쉘(또는 두 개)을 실행하는 것은 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.