引数はphpexec()を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

したがって、私のphpは引数をbashに渡し、bashはエラーとともにoutputFileに出力します。pidfileは、このexecで起動されたプロセスのpidを保持します。プロセスが起動されていないため、コマンドは実行されていません。execで渡される引数に制限はありますか?またはPHPからまたはLinuxシェルで?私はphp5.4とLinuxRedhat 7を実行しています。GNU並列を使用してプロセスを実行したいのですが、PHPはシングルスレッドであるためです(これを渡すライブラリがありますが、避けたいと思います)。たぶん私はそれをどういうわけかテキストファイルに渡し、このテキストファイルからプルするスクリプトに実行することができますか?助けて!

**更新:私のマシンの制限:**
#getconf ARG_MAX
2097152
 
#ulimit -a
コアファイルサイズ(ブロック、-c)0
データセグメントサイズ(キロバイト、-d)無制限
スケジューリング優先度(-e)0
ファイルサイズ(ブロック、-f)無制限
保留中の信号(-i)256634
最大ロックメモリ(キロバイト、-l)64
最大メモリサイズ(キロバイト、-m)無制限
ファイルを開く(-n)1024
パイプサイズ(512バイト、-p)8
POSIXメッセージキュー(バイト、-q)819200
リアルタイム優先度(-r)0
スタックサイズ(キロバイト、-s)8192
CPU時間(秒、-t)無制限
最大ユーザープロセス(-u)4096
仮想メモリ(キロバイト、-v)無制限
ファイルロック(-x)無制限

回答

2 ilkkachu Dec 02 2020 at 01:28

ほとんどのシステムでは、カーネルはexecve()syscallへの引数のサイズを制限します(コマンドライン引数+環境変数)。Linuxでは、制限は最大スタックサイズに関連していますが、通常、デフォルトのスタックサイズ制限である8 MBの場合、合計で少なくとも2MBが得られます。また、単一の引数を128 kBに制限します。たとえば、ファイル名の展開(グロブ)をbashする最大値はありますか?ある場合、それは何ですか?Linuxの環境変数の128KiB制限を引き上げる

sh -c 'command line'呼び出し時にPHPが実行される場合exec("command line")、toの引数-cはその128kBの制限をはるかに超える可能性があります。その後、コマンドラインがシェルによって個別の単語に分割されるという事実は役に立ちません。

1 OleTange Dec 02 2020 at 15:41

これだけ多くの引数がある場合は、標準入力(stdin)またはファイルを介してそれらをGNUParallelに渡します。

私は(未テスト)のようなことをします:

$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 ) );

BASH:

#!/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のホストをスキャンできました。Webサーバーはすべてのターゲットを数秒でファイルに追加しました。私のexecが起動すると、使用されるバックグラウンドプロセスは結果を待つ必要がありません(ファイルに出力しています)。

また、check.shスクリプトは、特定のターゲットのMariadbデータベースレコードも更新しています。