引数はphpexec()をbashスクリプトに制限します
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)無制限
回答
ほとんどのシステムでは、カーネルはexecve()
syscallへの引数のサイズを制限します(コマンドライン引数+環境変数)。Linuxでは、制限は最大スタックサイズに関連していますが、通常、デフォルトのスタックサイズ制限である8 MBの場合、合計で少なくとも2MBが得られます。また、単一の引数を128 kBに制限します。たとえば、ファイル名の展開(グロブ)をbashする最大値はありますか?ある場合、それは何ですか?Linuxの環境変数の128KiB制限を引き上げる
sh -c 'command line'
呼び出し時にPHPが実行される場合exec("command line")
、toの引数-c
はその128kBの制限をはるかに超える可能性があります。その後、コマンドラインがシェルによって個別の単語に分割されるという事実は役に立ちません。
これだけ多くの引数がある場合は、標準入力(stdin)またはファイルを介してそれらをGNUParallelに渡します。
私は(未テスト)のようなことをします:
$f = popen("parallel","w"); fwrite($f,$commands); close ($f);
このようにして、一時ファイルを回避できる場合があります。
だからここにあなたのすべての助けを借りて私の解決策があります: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データベースレコードも更新しています。