2012-04-24 42 views
6

PHP的proc_open手冊指出:proc_open:擴展文件描述符數,使「狀態」從Perl腳本反饋

的文件描述符數不限於0,1和2 - 你可以指定任何有效的文件描述符號碼,它將被傳遞給子進程。這允許您的腳本與作爲「協同處理」運行的其他腳本進行交互操作。特別是,這對於以更安全的方式將密碼傳遞給PGP,GPG和openssl等程序很有用。這對於讀取這些程序在輔助文件描述符中提供的狀態信息也很有用。

會發生什麼:我所說的Perl腳本在基於PHP的Web應用程序,並調用傳遞參數。我沒有將來需要將數據發送到腳本。通過stdout [1],我從我的PHP應用程序中使用的Perl腳本json_encoded數據中獲得。

我想補充的內容: Perl腳本正在通過網站收集信息,這取決於它在初始調用中傳遞的參數。我想回發給PHP應用程序一個文本字符串,我可以用它作爲一種進度條顯示。

我該怎麼想我應該這樣做:我期望輪詢(每1-2秒)一次爲該「進程」更新設置的頻道。我會使用Javascript/jQuery寫入HTML div容器供用戶查看。我認爲我不應該將「progress」通道與更關鍵的「json_encode(data)」通道混合,因爲那時我需要解密stdout流。 (這是合乎邏輯的思維,務實?)

我的主要問題:「文件描述符」你怎麼使用附加我將圖像附加信道的設置是直接的,如3 => ...在下面:

$tunnels = array( 
    0 => array('pipe', 'r'),  
    1 => array('pipe', 'w'),  
    2 => array('pipe', 'w'),  
    3 => array('pipe', 'w')   
); 

$io = array(); 
$resource = proc_open("perl file/tomy/perl/code.pl $param1 $param2 $param3", $tunnels, $io); 

if(!is_resource($resource)) { 
    $error = "No Resource"; 
} 

fclose($io[0]); 

$perlOutput = stream_get_contents($io[1]); 
$output = json_decode($perlOutput); 

$errors = stream_get_contents($io[2]); 
print "$errors<p>"; 

fclose($io[1]); 
fclose($io[2]); 

$result = proc_close($resource); 

if($result != 0) { 
    echo "you returned a $result result on proc_close"; 
} 

但是,在Perl腳本我簡單地寫入到標準輸出,如:

my $json_terms = encode_json(\@terms); 
print $json_terms; 

如果我對設置額外通道的理解是正確的(上面,3 => ...),那麼我如何在Perl腳本中寫入它?

感謝

回答

2

假設您想要監視hello-world程序的進度,其中每個步驟都是寫入指定文件描述符的點。

#! /usr/bin/env perl 

use warnings; 
use strict; 

die "Usage: $0 progress-fd\n" unless @ARGV == 1; 

my $fd = shift; 
open my $progress, ">&=", $fd or die "$0: dup $fd: $!"; 

# disable buffering on both handles 
for ($progress, *STDOUT) { 
    select $_; 
    $| = 1; 
} 

my $output = "Hello, world!\n"; 

while ($output =~ s/^(.)(.*)\z/$2/s) { 
    my $next = $1; 
    print $next; 
    print $progress "."; 
    sleep 1; 
} 

使用bash語法來打開/tmp/progress FD 3,並將其連接到程序

$ (exec 3>/tmp/progress; ./hello-world 3) 
Hello, world! 

$ cat /tmp/progress 
..............

(它’ S比有趣收看直播。)

要見點在你的終端出現時,你可以打開你的進度描述符,並有效地dup2到標準錯誤—再次使用bash語法和實時更有趣。

$ (exec 17>/dev/null; exec 17>&2; ./hello-world 17) 
H.e.l.l.o.,. .w.o.r.l.d.!. 
.

你當然可以略過

$ (exec 17>&2; ./hello-world 17)

額外的步驟,以達到同樣的效果。

如果你的Perl程序有錯誤,如

$ ./hello-world 333 
./hello-world: dup 333: Bad file descriptor at ./hello-world line 9.

然後在PHP端的管道寫端可能有它的特寫on-exec標誌設置死亡。

+0

聰明。我不確定'$(exec 17>&2; ./hello-world 17)'是做什麼的。但是現在我已經獲得了php和perl腳本之間的通道,我意識到我被困在一個調用perl腳本的php腳本的異步ajax調用中。我想我需要一個WebSocket(?)。我會盡快標記你的或者@mob的迴應。我感謝你們的幫助。謝謝! – Ricalsin 2012-04-25 23:38:12

+0

第一部分使得fd 17與fd 2相同(這是終端的標準錯誤),然後我們告訴hello-world將進度指標寫入fd 17。由於我們如何設置管道,點出現在終端也是如此。暴民是膨脹的;給暴徒勾號。 – 2012-04-26 02:22:39

2

你打開一個新的文件句柄和DUP它文件描述符3:

open STD3, '>&3'; 
print STDERR "foo\n"; 
print STD3 "bar\n"; 

$ perl script.pl 2> file2 3> file3 
$ cat file2 
foo 
$ cat file3 
bar 

編輯:每格雷格·培根的評論,open STD3, '>&=', 3open STD3, '>&=3'直接打開的文件描述符,像C的fdopen呼叫,避免dup調用並保存您的文件描述符。

+0

更直接的是'open my $ fh,「>&=」,3'。 – 2012-04-24 20:23:10

+0

暴徒,與你和@Greg_Bacon幫助我已經得到了perl通信繼續進行的PHP <->。謝謝。但即使我讓管道很熱,我仍然無法寫入我的網頁中的div,直到ajax post(調用perc腳本的proc_opens腳本)完成。我試圖給出perl腳本如何做的狀態更新。是長期投票還是webSocket我的兩個最佳選擇?謝謝你的幫助! – Ricalsin 2012-04-26 03:28:40