2012-04-24 3 views
6

PHP proc_open Handbuch heißt es:proc_open: Zahlen Dateideskriptors Erweiterung „Status“ Feedback von einem Perl-Skript aktivieren

Die Dateideskriptors Nummern werden nicht auf 0 beschränkt, 1 und 2 - Sie eine gültige Datei angeben Deskriptornummer und es wird an den Kindprozess übergeben. Dadurch kann Ihr Skript mit anderen Skripten zusammenarbeiten, die als "Co-Prozesse" ausgeführt werden. Dies ist insbesondere nützlich, um Passphrasen sicherer an Programme wie PGP, GPG und openssl weiterzuleiten. Es ist auch nützlich, um Statusinformationen zu lesen, die von diesen Programmen auf Zusatzdateideskriptoren bereitgestellt werden.

Was geschieht: ich in einer PHP-basierte ein Perl-Skript aufrufen Web-Anwendung und übergeben Sie Parameter in dem Aufruf. Ich habe keine Zukunft mehr, um Daten an das Skript zu senden. Durch stdout [1] erhalte ich vom Perl-Skript json_encoded Daten, die ich in meiner PHP-Anwendung verwende.

Was ich hinzufügen möchte: Das Perl-Skript wird durch eine Website Fortschritte sammeln Informationen abhängig von den Parametern in seinem ersten Aufruf übergeben. Ich möchte gerne eine Textzeichenfolge an die PHP-Anwendung zurücksenden, die ich als eine Art Fortschrittsbalken verwenden könnte.

Wie ich denke, ich sollte es tun: Ich würde erwarten, (alle 1-2 Sekunden) den Kanal, der für diese "Progression" Update eingerichtet wurde. Ich würde Javascript/jQuery verwenden, um in einen HTML-div-Container zu schreiben, den der Benutzer anzeigen kann. Ich denke nicht, dass ich den "Fortschritt" -Kanal mit dem kritischeren "json_encode (data)" - Kanal mischen sollte, da ich dann den stdout-Stream entschlüsseln müsste. (Ist das dachte logisch, praktisch?)

Meine Hauptfrage: „Datei-Deskriptoren“ Wie Sie zusätzliche verwenden Ich würde Bild der Setup zusätzlicher Kanäle zu einfach, wie die 3 => ... in der unten:

$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"; 
} 

Aber in dem Perl-Skript, das ich einfach an die stdout schreiben wie:

Wenn ich das Einrichten eines zusätzlichen Kanals richtig verstanden habe (oben, die 3 => ...), wie würde ich dann in das Perl-Skript schreiben?

Dank

Antwort

2

Angenommen, Sie möchten den Fortschritt eines Hallo-Welt-Programms überwachen, wobei jeder Schritt ein Punkt ist, der in den angegebenen Dateideskriptor geschrieben wird.

#! /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-Syntax fd 3 auf /tmp/progress zu öffnen und sie an das Programm angeschlossen ist

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

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

(Es ’ s amüsante Live zu sehen.)

auch die Punkte zu sehen, auf Ihrem Terminal, wenn sie auftauchen, können Sie Ihren Fortschrittsdeskriptor und effektiv dup2 es auf den Standardfehler — wieder mit Bash-Syntax und mehr Spaß in Echtzeit öffnen.

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

Sie könnte natürlich den zusätzlichen Schritt mit

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

überspringen den gleichen Effekt zu erzielen.

Wenn Ihr Perl-Programm stirbt mit einem Fehler wie

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

dann dem Schreib Ende des Rohres auf der PHP-Seite wahrscheinlich seine close-on-exec-Flag gesetzt hat.

+0

Clever. Ich bin mir nicht sicher, was das $ (exec 17> & 2; ./hello-world 17) tut. Aber jetzt, da ich die Kanäle zwischen dem php- und perl-Skript piped habe, merke ich, dass ich in einem asynchronen Ajax-Aufruf an das PHP-Skript festhalte, das das Perl-Skript aufgerufen hat. Ich denke ich brauche einen WebSocket (?). Ich markiere entweder Ihre oder @mob Antwort bald. Ich schätze die Hilfe von Ihnen beiden. Vielen Dank! – Ricalsin

+0

Der erste Teil macht fd 17 das gleiche wie fd 2 (was der Standardfehler des Terminals ist), und dann sagen wir hallo-world, Fortschrittsindikatoren auf fd 17 zu schreiben. Wegen der Art und Weise, wie wir die Rohrleitungen einrichten, tauchen die Punkte auf das Terminal auch. Mob ist Schwell; gib Mob das Häkchen. –

2

Sie öffnen ein neues Dateihandle und dup es Descriptor Datei 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 

Edit: pro Greg Bacons Kommentar, open STD3, '>&=', 3 oder open STD3, '>&=3' den Dateideskriptor direkt, wie Cs öffnet fdopen Rufen Sie an, vermeiden Sie einen dup Aufruf und speichern Sie einen Dateideskriptor.

+0

Direktere ist 'öffnen Sie meine $ fh,>> & =", 3 ". –

+0

Mob, mit Ihren und @Greg_Bacon Hilfe Ich habe die PHP <-> Perl Kommunikation los. Vielen Dank. Aber selbst wenn ich die Pipes heiß mache, kann ich immer noch nicht in ein div auf meiner Webseite schreiben, bis der Ajax-Post - der den php aufruft, welcher proc_ das Perl-Skript öffnet - fertig ist. Ich versuche, Status-Updates zu geben, wie das Perl-Skript funktioniert. Ist Long-Polling oder ein webSocket meine zwei besten Möglichkeiten? Danke für Ihre Hilfe! – Ricalsin

Verwandte Themen