2012-02-20 13 views
14

è comunque di leggere da STDIN con PHP che è non bloccante:lì non-blocking su STDIN in PHP CLI

ho provato questo:

stream_set_blocking(STDIN, false); 
echo fread(STDIN, 1); 

e questo:

$stdin = fopen('php://stdin', 'r'); 
stream_set_blocking($stdin, false); 
echo 'Press enter to force run command...' . PHP_EOL; 
echo fread($stdin, 1); 

ma blocca ancora fino al fread ottiene alcuni dati.

Ho notato alcune segnalazioni di bug aperte su questo (7 anni), quindi se non può essere fatto, qualcuno conosce qualche hack rozzo che potrebbe realizzare questo (su Windows e Linux)?

+3

Non sono sicuro di capire quale dovrebbe essere il comportamento non bloccante. Se non c'è niente in attesa di essere inviato a stdin, dovrebbe 'fread()' restituire un FALSE? Come lo distinguerebbe da EOF? Mi sembra che tu abbia bisogno di una sorta di test * altro * di 'fread()' per determinare se ci sono dati in attesa su stdin, poiché non c'è un errore descrittivo. – Graham

+0

@Graham 'fread' non ritorna, sospendo l'esecuzione dello script, fino a quando non viene dato input a' STDIN'. Fondamentalmente quello che voglio, è controllare se c'è qualche input da parte dell'utente a 'STDIN', e se no, continuare, o eseguire altre cose. – Petah

+0

@Graham "Non bloccare" significa che 'fread()' dovrebbe tornare immediatamente, anche se non può leggere la quantità di dati, che dovrebbe leggere (il secondo argomento), ma meno di questo. In questo caso dovrebbe restituire una stringa vuota. @Petah hai provato 'fopen ('php: // stdin)'? Ricordo vagamente che ho avuto problemi con 'STDIN' prima. – KingCrunch

risposta

12

Ecco cosa potrei inventare. Funziona bene su Linux, ma su Windows, non appena premo un tasto, l'input viene memorizzato nel buffer finché non viene premuto Invio. Attualmente sto cercando di trovare un modo per disabilitare il buffering su un flusso, o in particolare su STDIN in PHP.

<?php 

function non_block_read($fd, &$data) { 
    $read = array($fd); 
    $write = array(); 
    $except = array(); 
    $result = stream_select($read, $write, $except, 0); 
    if($result === false) throw new Exception('stream_select failed'); 
    if($result === 0) return false; 
    $data = stream_get_line($fd, 1); 
    return true; 
} 

while(1) { 
    $x = ""; 
    if(non_block_read(STDIN, $x)) { 
     echo "Input: " . $x . "\n"; 
     // handle your input here 
    } else { 
     echo "."; 
     // perform your processing here 
    } 
} 

?> 
+0

Grazie, questo funzionerà per il mio caso. Ma se riesci a renderlo coerente con (la chiave di accesso), allora ancora meglio. Ti assegnerò la taglia se non ci sono risposte migliori. – Petah

+0

L'ho integrato con la mia sceneggiatura, funziona abbastanza bene, tranne per il fatto che deve aspettare per entrare. Ogni volta che alt + tab alla finestra, si ferma e attende per entrare. – Petah

+0

Qui stubmleed su questa domanda e potrebbe funzionare se stai usando stream_set_read_buffer (STDIN, 0); e, come hai già detto, stream_set_blocking (STDIN, false); - Il primo dovrebbe impostare lo stdin per essere unbuffered durante la lettura, il secondo set non è blocking, che è un po 'diverso da unbuffered. –

1

Petah, non posso fare con il lato PHP di questo direttamente, ma si può fare riferimento ad un articolo mi sono imbattuto in un istante fa in cui qualcuno ha emulato i transistor testando all'interno di uno script di shell l'esistenza di dati in sospeso per una pipe denominata. È una lettura affascinante e porta lo script delle shell a un nuovo livello di geek. :-)

L'articolo è qui: http://www.linusakesson.net/programming/pipelogic/

Così ... in risposta alla tua richiesta di "hack greggio", suppongo che si possa smistare la vostra stdio tramite named pipe, quindi exec() lo strumento la cui fonte è incluso all'URL sopra per verificare se qualcosa è in attesa di essere inviato attraverso la pipe. Probabilmente vorresti sviluppare alcune funzioni wrapper per aiutarti con le cose.

Sospetto che la soluzione pipelogic sia solo per Linux, o almeno richiederebbe un sistema operativo unix-like. Non ho idea di come questo possa essere realizzato su Windows.

+1

Scusate, non vedo davvero come questo aiuti con il mio problema. – Petah

+0

@Petah - un fread non bloccante() che legge da una pipe può essere duplicato da una funzione che eseguirà solo un blocco fread() dopo aver controllato se ci sono dati in attesa su una pipe. Lo strumento al link che ho postato ti permette di testare quella condizione. Sono abbastanza sicuro che questo approccio non funzionerebbe in Windows a causa della mancanza di pipe denominate, quindi non funzionerò ulteriormente, poiché la compatibilità di Windows è una condizione della tua domanda. – ghoti

+0

Grazie comunque :) – Petah

0

Basta un avviso, che il lavoro non bloccante STDIN, ora.