인수는 php exec ()를 bash 스크립트로 제한합니다.

Dec 02 2020

PHP에서 bash 스크립트로 50000 개의 인수를 전달하는 데 얼마나 오래 걸리는지 테스트 한 결과, 내가 할 수없는 한 한 번에 PHP에서 bash 스크립트로 1000 개의 인수도 전달할 수없는 것으로 나타났습니다 .

PHP:
    
$array = fetch_results_from_working_pool_temp_table (); $outputfile = "/var/www/html/outputFile";
$pidfile = "/var/www/html/pidFile"; $id = "";
$array_check=array(); foreach ( $array as $row => $column ) {
    $id .= $column ['id'];
        $id .= " "; } $cmd = "sudo /bin/bash /var/www/html/statistics/pass_all.sh {$id}"; exec( sprintf ( "%s >> %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile ) ); bash: #!/bin/bash for ip in "$@"
do 
    echo "${ip}" 
done

그래서 내 PHPbash에 인수를 전달 하고 bash는 오류와 함께 outputFile에 인쇄 합니다. pidfile 은이 exec로 시작된 프로세스의 pid를 보유합니다. 실행 된 프로세스가 없기 때문에 명령이 실행되지 않습니다. exec에서 전달 된 인수에 대한 제한이 있습니까? 또는 PHP 또는 Linux 쉘에서? 저는 php 5.4와 Linux Redhat 7 을 실행하고 있습니다. GNU 병렬을 사용하여 프로세스를 실행하고 싶지만 PHP가 단일 스레드이기 때문에 (이를 전달할 라이브러리가 있지만 피하는 것이 좋습니다). 어떻게 든 텍스트 파일에 전달하고이 텍스트 파일에서 가져 오는 스크립트에 exec를 전달할 수 있습니까? 도움!

** 업데이트 : 내 컴퓨터 제한 : **
#getconf ARG_MAX
2097152
 
#ulimit -a
코어 파일 크기 (블록, -c) 0
데이터 세그먼트 크기 (KB, -d) 무제한
스케줄링 우선 순위 (-e) 0
파일 크기 (블록, -f) 무제한
보류중인 신호 (-i) 256634
최대 잠긴 메모리 (KB, -l) 64
최대 메모리 크기 (KB, -m) 무제한
열린 파일 (-n) 1024
파이프 크기 (512 바이트, -p) 8
POSIX 메시지 큐 (바이트, -q) 819200
실시간 우선 순위 (-r) 0
스택 크기 (KB, -s) 8192
CPU 시간 (초, -t) 무제한
최대 사용자 프로세스 (-u) 4096
가상 메모리 (KB, -v) 무제한
파일 잠금 (-x) 무제한

답변

2 ilkkachu Dec 02 2020 at 01:28

대부분의 시스템에서 커널은 execve()syscall 에 대한 인수 크기를 제한합니다 (명령 줄 args + 환경 변수). Linux에서 제한은 최대 스택 크기와 관련이 있지만 일반적으로 기본 스택 크기 제한 인 8MB에 대해 총 2MB 이상을 얻습니다. 또한 단일 인수를 128kB로 제한합니다. 예를 들어 bash 파일 이름 확장 (globbing)에 최대 값이 있습니까? 그렇다면 무엇입니까? 및 Linux에서 환경 변수에 대한 128KiB 제한 올리기

sh -c 'command line'호출 할 때 PHP가 실행 되면 exec("command line")인수 -c가 128KB 제한을 초과 할 수 있습니다. 명령 줄이 나중에 쉘에 의해 별개의 단어로 분할된다는 사실은 도움이되지 않습니다.

1 OleTange Dec 02 2020 at 15:41

이렇게 많은 인수가있는 경우 표준 입력 (stdin) 또는 파일을 통해 GNU Parallel에 전달하려고합니다.

나는 다음과 같은 일을 할 것입니다.

$f = popen("parallel","w"); fwrite($f,$commands); close ($f);

이렇게하면 임시 파일을 피할 수 있습니다.

dwt.bar Dec 02 2020 at 23:48

여기에 모든 도움이 필요하면 내 솔루션이 있습니다. PHP :

function scan_targets() {

$targetsFile= "[absolute path to the file]/targets"; $array_with_targets = fetch_from_db (); //function that gets me all the targets
$outputfile = "[absolute path to the file]/outputFile"; //output from parallel script $pidfile = "[absolute path to the file]/pidFile"; //PID of the process
$target = ""; foreach ( $array_with_targets as $row => $column ) {
    $id .= $column ['id'];
        $id .= " "; } file_put_contents($targetsFile, $ip) ; $cmd = "/bin/bash [absolute path to the file]/pass_targets.sh";
exec( sprintf ( "%s >> %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile ) );

세게 때리다:

#!/bin/bash

#appending arguments to the command
targets_array=()
IFS=" "
while read -r field || [ -n "$field" ]; do targets_array+=("$field")
done <[absolute path to the file]/targets
    
parallel bash [absolute path to the file]/check.sh ::: $targets_array

-Dall 옵션을 사용하여 병렬로 실행하여 더 많은 상황을 파악할 수도 있습니다. 저는 7 시간 동안 거의 40.000 개의 호스트를 스캔 할 수있었습니다. 웹 서버는 몇 초 만에 모든 대상을 파일에 추가했으며 내 exec가 시작될 때 사용 된 백그라운드 프로세스가 결과를 기다릴 필요가 없습니다 (파일로 출력 중입니다).

또한 check.sh 스크립트는 특정 대상에 대한 Mariadb 데이터베이스 레코드를 업데이트합니다.