PHP CLI를 사용해서 Shell Script를 생성하다보면 사용자에게 어떤 데이터를 입력 받아야 상황이 발생할 수 있다. 이런 경우에 사용할 수 있는 몇가지 방법에 대해 설명하고자 한다.
우선 PHP 메뉴얼 중 Input/output streams에 있는 예시에 약간의 코드를 더해서 설명하겠다.
<?php
$stdin = fopen('php://stdin', 'r');
$fileContents = fread($stdin, 1024);
fclose($stdin);
echo $fileContents;
우선 위 방법은 fopen을 사용해서 사용자에게 입력 받는 방법이다. 이 방법은 사용자의 입력이 완료될 때(Enter 입력시)까지 대기하게 하거나 pipe(|)를 이용해 입력이 가능하다. 위 내용을 fopenTest.php
로 저장했다면 아래와 같이 실행해 볼 수 있다. 그리고 1024는 입력의 최대 길이로 그 이상의 입력이 들어오면 무시된다.
$ php fopenTest.php
test # 입력 후 Enter
test
$ echo "test" | php fopenTest.php
test
이와 동일한 역할로 다음과 같이 사용할 수도 있다.
<?php
echo trim(fgets(STDIN)); // reads one line from STDIN
처음 코드와 동일하게 동작한다. 그리고 특정 형식으로 데이터를 입력받고 싶다면 아래와 같이 사용할 수도 있다.
<?php
fscanf(STDIN, "%d\n", $number); // reads number from STDIN
echo $number;
위 코드는 실행 결과는 약간 다른점이 있으니 아래의 실행 예시를 참고하자.
$ php fopenTest.php
test # 입력 후 Enter
# 입력값이 무시되어 아무값도 출력되지 않음
$ php fopenTest.php
2test3 # 입력 후 Enter
2 # 2 이후의 입력값이 무시됨
$ php fopenTest.php
123 # 입력 후 Enter
123 # 유효한 입력으로 123이 출력됨
$ echo "123" | php fopenTest.php
123 # 유효한 입력으로 123이 출력됨
PHP에서는 다른 방법으로 readline을 사용하는 것이 가능하다. 예를들면 아래와 같이 확인해 볼 수 있다.
<?php
//get 3 commands from user
for ($i=0; $i < 3; $i++) {
$line = readline("Command: ");
readline_add_history($line);
}
//dump history
print_r(readline_list_history());
//dump variables
print_r(readline_info());
그런데 이 함수는 제약조건이 있다. 메뉴얼에 따르면 readline_list_history는 libreadline
과 함께 컴파일되어야만 사용할 수 있다고 되어 있다. 그래서 위 예시는 제대로 테스트 해보지 못했다.
그렇다면 사용자에게 한글자의 입력만 받고 싶다면 어떻게하면 될까? 아래의 예시를 보자.
<?php
echo '변경 후에는 복구할 수 없습니다. 변경하시겠습니까? (y/n) ';
$input = fgetc(STDIN);
위 코드를 실행하면 한글자만 입력을 받게 되지만 한글자를 입력하고 Enter를 눌러야 한다. 그럼 그냥 한글자를 입력하면 바로 입력을 완료하고자 한다면 어떻게 할까? 아래에 그 답이 있다.
<?php
echo '변경 후에는 복구할 수 없습니다. 변경하시겠습니까? (y/n) ';
readline_callback_handler_install('', function () {
});
while (true) {
$r = [STDIN];
$w = null;
$e = null;
$n = stream_select($r, $w, $e, 0);
if ($n && in_array(STDIN, $r)) {
$c = stream_get_contents(STDIN, 1);
if (strcasecmp($c, 'y') != 0) {
echo "\n작업을 취소함\n";
exit;
}
break;
}
}
echo "변경 완료\n";
나의 경우엔 위 스크립트를 사용해야하는 상황이 가장 많은 것 같다. 위험한 동작을 실행하기전 다시 한번 확인하는 것이 정신 건강에 이롭다.