อาร์กิวเมนต์ จำกัด php exec () ไว้ที่ bash script

Dec 02 2020

การทดสอบว่าจะใช้เวลานานแค่ไหนในการส่งอาร์กิวเมนต์ 50000 จาก php ไปยัง bash script ปรากฎว่าฉันไม่สามารถส่งอาร์กิวเมนต์จาก php ไปยัง bash script ได้ในคราวเดียวเว้นแต่จะทำได้

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จะเก็บ pid ของกระบวนการที่เปิดตัวด้วย exec นี้ คำสั่งไม่ได้ถูกเรียกใช้งานด้วยซ้ำเพราะฉันไม่เห็นกระบวนการเปิดใช้งาน มีข้อ จำกัด สำหรับข้อโต้แย้งที่ส่งผ่านใน exec หรือไม่? หรือจาก PHP หรือใน Linux shell? ฉันใช้ php 5.4 และ Linux Redhat 7ฉันต้องการเรียกใช้กระบวนการโดยใช้ GNU แบบขนาน แต่เนื่องจาก PHP เป็นเธรดเดียว (มีไลบรารีที่จะส่งผ่านสิ่งนี้ แต่ฉันต้องการหลีกเลี่ยงสิ่งนั้น) บางทีฉันอาจส่งต่อไปยังไฟล์ข้อความและดำเนินการกับสคริปต์ที่ดึงมาจากไฟล์ข้อความนี้ ช่วยด้วย!

** อัปเดต: ขีด จำกัด เครื่องของฉัน: **
#getconf ARG_MAX
2097152
 
#ulimit -a
ขนาดไฟล์หลัก (บล็อก -c) 0
ขนาด seg ข้อมูล (kbytes, -d) ไม่ จำกัด
ลำดับความสำคัญของการจัดกำหนดการ (-e) 0
ขนาดไฟล์ (บล็อก -f) ไม่ จำกัด
สัญญาณที่รอดำเนินการ (-i) 256634
หน่วยความจำล็อคสูงสุด (kbytes, -l) 64
ขนาดหน่วยความจำสูงสุด (kbytes, -m) ไม่ จำกัด
เปิดไฟล์ (-n) 1024
ขนาดท่อ (512 ไบต์, -p) 8
คิวข้อความ POSIX (ไบต์, -q) 819200
ลำดับความสำคัญแบบเรียลไทม์ (-r) 0
ขนาดกองซ้อน (kbytes, -s) 8192
เวลา cpu (วินาที, -t) ไม่ จำกัด
กระบวนการผู้ใช้สูงสุด (-u) 4096
หน่วยความจำเสมือน (kbytes, -v) ไม่ จำกัด
ล็อคไฟล์ (-x) ไม่ จำกัด

คำตอบ

2 ilkkachu Dec 02 2020 at 01:28

ในระบบส่วนใหญ่เคอร์เนลจะ จำกัด ขนาดของอาร์กิวเมนต์ไว้ที่execve()syscall (บรรทัดคำสั่ง args + environment vars) บน Linux ขีด จำกัด จะเกี่ยวข้องกับขนาดสแต็กสูงสุดแม้ว่าโดยปกติคุณจะได้รับผลรวมอย่างน้อย 2 MB สำหรับขีด จำกัด ขนาดสแต็กเริ่มต้นที่ 8 MB นอกจากนี้ยัง จำกัดอาร์กิวเมนต์เดียวไว้ที่ 128 kB ดูเช่นมีการขยายชื่อไฟล์สูงสุด (globbing) หรือไม่และถ้าเป็นเช่นนั้นมันคืออะไร? และเพิ่มขีด จำกัด 128KiB สำหรับตัวแปรสภาพแวดล้อมใน Linux

หาก PHP ทำงานsh -c 'command line'เมื่อคุณเรียกexec("command line")ใช้อาร์กิวเมนต์-cอาจเกินขีด จำกัด 128 kB ความจริงที่ว่าบรรทัดคำสั่งถูกแบ่งออกเป็นคำที่แตกต่างกันในภายหลังโดยเชลล์จะไม่ช่วย

1 OleTange Dec 02 2020 at 15:41

เมื่อคุณมีอาร์กิวเมนต์จำนวนมากนี้คุณต้องการส่งต่อไปยัง GNU Parallel ผ่านอินพุตมาตรฐาน (stdin) หรือผ่านไฟล์

ฉันจะทำบางอย่างเช่น (ยังไม่ทดลอง):

$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 เพื่อให้มีบริบทเพิ่มเติมว่าเกิดอะไรขึ้นฉันสามารถสแกนโฮสต์เกือบ 40.000 แห่งใน 7 ชั่วโมง เว็บเซิร์ฟเวอร์เพิ่มเป้าหมายทั้งหมดลงในไฟล์ในไม่กี่วินาทีและเมื่อ exec ของฉันเปิดใช้กระบวนการพื้นหลังที่ใช้ไม่ต้องรอผลลัพธ์ (เรากำลังส่งออกไปยังไฟล์)

และสคริปต์ check.sh กำลังอัปเดตบันทึกฐานข้อมูล Mariadb สำหรับเป้าหมายเฉพาะในขณะที่ดำเนินการ