Funzione PHP pfsockopen(): tutto quello che devi sapere
Scopri la funzione pfsockopen() di PHP: sintassi, parametri, esempi pratici e l'alternativa moderna con stream_socket_client().
La funzione pfsockopen() apre una connessione socket persistente su Internet o su dominio Unix. "Persistente" significa che il socket sottostante rimane aperto al termine dello script e viene riutilizzato dalle richieste successive che si connettono allo stesso host e porta, evitando il costo di aprire una nuova connessione (risoluzione DNS, handshake TCP) ogni volta.
Importante:
pfsockopen()è stata deprecata in PHP 8.1 e rimossa in PHP 8.2, quindi non è disponibile nelle versioni moderne di PHP. Questo capitolo documenta il comportamento storico della funzione e mostra cosa usare al suo posto. Se utilizzi PHP 8.2+, vai direttamente a Alternativa moderna.
Questo capitolo illustra cosa faceva pfsockopen(), la sua sintassi e i suoi parametri, un esempio HTTP pratico, la differenza tra socket persistenti e non persistenti, le insidie più comuni e il sostituto consigliato.
Cos'è la funzione pfsockopen()?
pfsockopen() ("persistent fsockopen") è la versione persistente di fsockopen(). Entrambe aprono un socket di basso livello e restituiscono uno stream da cui è possibile leggere e su cui è possibile scrivere con le normali funzioni file. L'unica differenza è che una connessione aperta con fsockopen() viene chiusa al termine della richiesta, mentre una aperta con pfsockopen() viene inserita in un pool dal processo PHP e riutilizzata nelle richieste successive verso la stessa destinazione.
Questo la rendeva utile in ambienti a lunga durata (FPM/mod_php workers) in cui lo stesso script comunicava ripetutamente con lo stesso backend — ad esempio un nodo memcached o un servizio TCP personalizzato — e valeva la pena evitare l'overhead dell'handshake per ogni richiesta.
Come usare la funzione pfsockopen()
Ecco la sintassi della funzione:
Sintassi PHP della funzione pfsockopen()
pfsockopen($hostname, $port, &$errno, &$errstr, $timeout);La funzione accetta cinque parametri:
$hostname: il nome host o l'indirizzo IP del server a cui connettersi.$port: il numero di porta a cui connettersi.$errno: una variabile passata per riferimento che verrà impostata con il numero di errore in caso di errore.$errstr: una variabile passata per riferimento che verrà impostata con il messaggio di errore in caso di errore.$timeout: il periodo di timeout in secondi.
Solo $hostname e $port sono obbligatori; $errno, $errstr e $timeout sono facoltativi, ma vale quasi sempre la pena passarli per poter diagnosticare i problemi.
Valore restituito: restituisce uno stream/risorsa in caso di successo, oppure false in caso di errore.
Ecco un esempio di utilizzo della funzione pfsockopen() per creare una connessione socket persistente, gestire gli errori e scambiare dati:
Come usare la funzione pfsockopen()?
<?php
$hostname = "example.com";
$port = 80;
$errno = 0;
$errstr = "";
$timeout = 30;
$socket = pfsockopen($hostname, $port, $errno, $errstr, $timeout);
if ($socket === false) {
echo "Connection failed: $errno - $errstr";
} else {
fwrite($socket, "GET / HTTP/1.1\r\nHost: $hostname\r\n\r\n");
$response = fread($socket, 2048);
echo $response;
fclose($socket);
}
?>In questo esempio apriamo una connessione a example.com sulla porta 80 con un timeout di 30 secondi. In caso di errore, il numero e il messaggio di errore vengono salvati in $errno/$errstr. Una volta connessi, inviamo una richiesta HTTP grezza con fwrite(), leggiamo la risposta con fread() e chiudiamo l'handle con fclose().
Lo stream restituito si comporta come qualsiasi altro stream PHP, quindi le stesse funzioni I/O che usi con fopen() funzionano anche qui.
Socket persistenti vs. non persistenti
La tabella seguente mostra quando ciascun comportamento è rilevante:
| Aspetto | fsockopen() | pfsockopen() |
|---|---|---|
| Durata della connessione | Chiusa al termine della richiesta | Inserita in pool e riutilizzata tra le richieste |
| Costo della prima richiesta | Handshake completo ogni volta | Handshake completo solo alla prima richiesta |
| Ideale per | Script eseguiti una sola volta o di breve durata | Chiamate ripetute allo stesso backend in worker a lunga durata |
La persistenza è utile solo quando lo stesso processo serve molte richieste verso lo stesso host/porta — tipicamente PHP-FPM o mod_php. Negli script CLI che terminano immediatamente non c'è nulla da riutilizzare, quindi pfsockopen() si comporta come fsockopen().
Insidie comuni
fclose()non chiude davvero il socket. Chiamarefclose()su un socket persistente lo restituisce semplicemente al pool. Questo è lo scopo — ma significa che una connessione parzialmente rotta può essere passata alla richiesta successiva. Valida sempre la connessione (o invia un ping leggero) prima di affidarti ad essa.- Nessun multiplexing. Ogni worker PHP mantiene il proprio pool, quindi il numero di socket persistenti cresce con il numero di worker. Un server trafficato può esaurire il limite di connessioni del backend.
- Fughe di stato. Poiché il socket sopravvive tra le richieste, dati bufferizzati residui o uno stato intermedio del protocollo da una richiesta precedente possono corrompere quella successiva. I socket persistenti si adattano meglio a protocolli semplici, senza stato, di tipo richiesta/risposta.
- Rimossa in PHP 8.2. Il codice che chiama ancora
pfsockopen()genererà un errore fataleCall to undefined functionsu PHP 8.2+.
Alternativa moderna
Su PHP 8.2+, usa stream_socket_client() con il flag STREAM_CLIENT_PERSISTENT. È più flessibile (supporta i trasporti tcp://, tls:// e unix:// e i contesti di stream) ed è l'API attivamente mantenuta:
<?php
$socket = stream_socket_client(
"tcp://example.com:80",
$errno,
$errstr,
30,
STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT
);
if ($socket === false) {
echo "Connection failed: $errno - $errstr";
} else {
fwrite($socket, "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n");
echo fread($socket, 2048);
fclose($socket);
}
?>Per il lavoro HTTP ordinario, un client di livello più alto come cURL o Guzzle è di solito la scelta migliore — usa i socket grezzi solo quando hai bisogno di un protocollo personalizzato.
Conclusione
pfsockopen() creava una connessione socket persistente e riutilizzabile, utile per i worker PHP a lunga durata che contattavano ripetutamente lo stesso backend. La sua caratteristica principale era che fclose() restituiva il socket al pool invece di chiuderlo. Poiché la funzione è stata rimossa in PHP 8.2, il nuovo codice dovrebbe usare stream_socket_client() con STREAM_CLIENT_PERSISTENT. Per approfondire l'I/O su stream correlato, consulta fsockopen(), fwrite() e fread().