Shell çıkış tam PHP ile alındığını değil!

9 Cevap php

Ben bir kabuk komut yürüten bir PHP komut dosyası var:

$handle = popen('python last', 'r');
$read = fread($handle, 4096);
print_r($read);
pclose($handle);

Kabuk çıkışının çıkış yankı. Ben komut bu çalıştırdığınızda böyle bir şey olsun:

[root@localhost tester]# python last
[last] ZVZX-W3vo9I: Downloading video webpage
[last] ZVZX-W3vo9I: Extracting video information
[last] ZVZX-W3vo9I: URL: x
[download] Destination: here.flv
[download]   0.0% of 10.09M at     ---b/s ETA --:--
[download]   0.0% of 10.09M at   22.24k/s ETA 07:44
[download]   0.0% of 10.09M at   66.52k/s ETA 02:35
[download]   0.1% of 10.09M at  154.49k/s ETA 01:06
[download]   0.1% of 10.09M at  162.45k/s ETA 01:03

Ben PHP aynı komutu çalıştırdığınızda Ancak, ben bu çıktıyı alıyorum:

[last] ZVZX-W3vo9I: Downloading video webpage
[last] ZVZX-W3vo9I: Extracting video information
[last] ZVZX-W3vo9I: URL: x
[download] Destination: here.flv

Eğer alt bit hangi eksik gördüğünüz gibi biraz ihtiyacım! Sorun önce yüzdeler aynı hat üzerinde güncellenmektedir ediliyordu ancak yeni bir çizgi oluşturur ki şimdi benim Python komut değişti oldu. Ama bu fark yaptı! (

Bu soru ilişkili to this one.

Herhangi bir yardım için teşekkür ederiz.

Update

Çıkışı "2> & 1" yönlendirmek gerekiyordu. Ben Pax ait tek gerçek cevap almak için süre cevapsız çünkü P: Axeldota şanslı var!

9 Cevap

Sen borudan ilk 4.096 bayt sadece okunur, bir döngü içinde fread / print _R yerleştirmek ve {[kullanarak sonu dosyası için kontrol etmek gerekir (2)]} function.

$handle = popen('python last', 'r');

while(!feof($handle))
{
    print_r(fread($handle, 4096));
} 

pclose($handle);

İlk adım çıkış nereye gittiğini görmek için. Ben yapacağını ilk şey, her test için yedi dakika bekliyor değiliz ki biraz daha küçük bir dosya seçmektir.

Şeyler kabuk yazıldığı nerede 1 / See Adım. Komut çalıştır python last >/tmp/stdout 2>/tmp/stderr o iki dosyalarına bakmak. İdeal olarak, her şeyi stdout yazılı olacaktır ama bu durum olmayabilir. Bu size senaryonun temel davranışını verir.

Adım 2 / kullanarak PHP çalıştırdığınızda aynı şeyi yapın $handle = popen('python last >/tmp/stdout 2>/tmp/stderr', 'r');. Sizin PHP komut muhtemelen bu durumda döndü ama dosyalar hala doldurulması gereken bir şey almazsınız. Terminal olmayan bir ortamda çalışırken bu Değiştirilen herhangi bir davranış çekecektir.

Çıkışın bir stderr'e giderse, daha sonra çözelti $handle = popen('python last 2>&1', 'r'); kadar basit olmalıdır

Ayrıca, PHP devletler için doco (benim kalınlaştırma):

Returns a file pointer identical to that returned by fopen(), except that it is unidirectional (may only be used for reading or writing) and must be closed with pclose(). This pointer may be used with fgets(), fgetss(), and fwrite().

Bu örneklerden biri de gösterilene rağmen Yani, hatta fread() kullanarak olmalıdır emin değilim. Yine de, hat-tabanlı giriş ulaşmak için çalışıyoruz ne daha eşler düşünüyorum.

Ne olursa olsun tüm bu, onu daha fazla 4K, bir şey gibi zaman çıktı alabilirsiniz sağlamak için bir döngü çıktı okumalısınız:

$handle = popen ('python last 2>&1', 'r');
if ($handle) {
    while(! feof ($handle)) {
        $read = fgets ($handle);
        echo $read;
    } 
    pclose ($handle);
}

Bu sunucu tarafı bağlantı kayboldu düşünüyor yana çıktı iseniz, dışarı bakmak için başka bir şey, bir tarayıcıya gidiyor ve çok uzun sürüyor, tarayıcı kendisi zaman aşımına uğrayabilir. Eğer küçük bir dosya çalışma bulmak ve 10M/1minute dosyası, çalışma değilse, bu durumda olabilir. Sen flush() deneyebilirsiniz ancak tüm tarayıcılar bu onur olacaktır.

Bunu yapmak çok daha kolaydır:

$output = `python last`;
var_dump($output);

'Keneler' (`) hattını yürütmek ve çıkış yakalayacaktır. Burada, bir test örneği aşağıda verilmektedir:

Dnm.php Dosya:

<?php
echo "PHP Output Test 1\n";
echo "PHP Output Test 2\n";
echo "PHP Output Test 3\n";
echo "PHP Output Test 4\n";
echo "PHP Output Test 5\n";
?>

Capture.php Dosya:

<?php
$output = `php test.php`;
var_dump($output);
?>

Çıktı php capture.php:

string(80) "Test PHP Script
Test PHP Script
Test PHP Script
Test PHP Script
Test PHP Script
"

Daha sonra satır sonları dayalı bir diziye çıktı bölebilirsiniz:

$outputArray = explode('\n', $output);

OR size stdin, stdout ve stderr ele istediğiniz yeri belirtebilirsiniz gibi popen daha fazla kontrol verir, proc_open() kullanın.

OR Eğer STDIN fopen veya php://stdin ve php sonra boru:

? python last | php script.php

Ben seçeneği 1 ve backticks kullanarak, en kolay yolu ile gitmek istiyorum.

Ben çıkış uçbirimlerden gitmiyor zaman ilerleme raporu ihmal olduğunu bulmak için sürpriz olmaz. Yani, PHP gönderilen şeyi yakalama, ancak ilerleme raporu gönderilmemektedir.

Eski güzel ls komutu ile başlayan komutları - çıkışı nereye bağlı olarak farklı davranmak için yeterli emsal var.

Eğer çalıştırdığınız Python senaryosunu yazdı Tabii ki, bu çok daha az sorun neden olması muhtemeldir.

Nasıl bu hipotez geçerli olup olmadığını kontrol edebilirsiniz? Peki, standart çıktı bir dosya gidiyor ve standart hata başka bir gidiş ile komut satırında komut dosyasını çalıştırarak başlayabilirsiniz. Eğer bu dosyaların birinde ilerleme bilgileri görürseniz, ne olup bittiğini hakkında daha bir sürü biliyorum. Eğer hala ekranda ilerleme bilgileri görürseniz, o komut muhtemelen /dev/tty için ilerleme bilgileri yankılanan, ama PHP çalıştırır, hiçbir /dev/tty süreci için vardır. Eğer (ekranda veya bir dosyada) hiç ilerleme bilgileri göremiyorsanız, o zaman benim özgün hipotez muhtemelen doğrulandı.

$ Kolundaki stream_get_contents () çalıştırmayı deneyin. Bu size almaya çalışıyoruz ne tam boyutunu bilmiyorum kaynakları ile çalışmak için daha iyi bir yolu var.

Yerine fread kullanarak bir süre döngü read () olabilir mi?

while( !feof($handle) )
    echo fgets($handle);

Ayrıca () temizlemek zorunda kalabiliriz.

Sen ne görüyorsun

python last | less

?

Belki istediğiniz çıkış STDERR üzerine yayılır. Sonra bu şekilde başlatmak gerekiyor:

$handle = popen('python last 2>&1', 'r');

2>&1 Eğer popen ile yakalarken STDOUT, içine STDERR yönlendirir.

Sadece bir terminal penceresinden içeride python komut ilerlemesini göstermek için çalışıyorsanız, o zaman ben onun yerine şunları tavsiye ederim:

<?php
system("python last > `tty`");

Daha sonra çıkış yakalamak gerekiyor ve kullanıcı bile Ctrl + PHP komut iptal olmadan C indir. Olmaz

Bir floş çağrı eksik. (Python app, ve muhtemelen php app lutfen)

Eğer (cmdline itibaren) etkileşimli standart akışı stdin / stdout kullandığınızda onlar (her yeni satırda kısa sistem basması) bir çizgi-tamponlu modunda, ancak program akışları içinde çağırdığınızda tamamen tamponlu vardır olmasıdır modu (sistem tampon kadar çıktı tam değil).

Bu konuda daha fazla bilgi burada buffering in standard streams