PHP pfsockopen() Function: Everything You Need to Know
As a PHP developer, you may need to establish a persistent socket connection for communication between your PHP script and a remote server. The pfsockopen()
The pfsockopen() function opens a persistent Internet or Unix domain socket connection. "Persistent" means the underlying socket is kept open after the script finishes and is reused by later requests that connect to the same host and port — saving the cost of opening a new connection (DNS lookup, TCP handshake) every time.
Important:
pfsockopen()was deprecated in PHP 8.1 and removed in PHP 8.2, so it is unavailable in modern PHP. This chapter documents its historical behavior and shows what to use instead. If you are on PHP 8.2+, jump to Modern alternative.
This chapter covers what pfsockopen() did, its syntax and parameters, a worked HTTP example, the difference between persistent and non-persistent sockets, common gotchas, and the recommended replacement.
What is the pfsockopen() Function?
pfsockopen() ("persistent fsockopen") is the persistent twin of fsockopen(). Both open a low-level socket and return a stream you can read from and write to with the usual file functions. The only difference: a connection opened with fsockopen() is closed at the end of the request, while one opened with pfsockopen() is pooled by the PHP process and reused on subsequent requests to the same destination.
This made it useful in long-lived setups (FPM/mod_php workers) where the same script repeatedly talked to the same backend — for example a memcached node or a custom TCP service — and the handshake overhead per request was worth avoiding.
How to Use the pfsockopen() Function
Here is the syntax of the function:
The PHP syntax of pfsockopen() Function
pfsockopen($hostname, $port, &$errno, &$errstr, $timeout);The function takes five parameters:
$hostname: The hostname or IP address of the server to connect to.$port: The port number to connect to.$errno: A variable passed by reference that will be set to the error number if an error occurs.$errstr: A variable passed by reference that will be set to the error message if an error occurs.$timeout: The timeout period in seconds.
Only $hostname and $port are required; $errno, $errstr, and $timeout are optional but almost always worth passing so you can diagnose failures.
Return value: Returns a stream/resource on success, or false on failure.
Here is an example of how to use the pfsockopen() function to create a persistent socket connection, handle errors, and exchange data:
How to Use the pfsockopen() Function?
<?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);
}
?>Here we open a connection to example.com on port 80 with a 30-second timeout. On failure the error number and message land in $errno/$errstr. Once connected we send a raw HTTP request with fwrite(), read the response with fread(), and close the handle with fclose().
A returned stream behaves like any other PHP stream, so the same I/O functions you use with fopen() work here too.
Persistent vs. non-persistent sockets
The table below shows when each behavior matters:
| Aspect | fsockopen() | pfsockopen() |
|---|---|---|
| Connection lifetime | Closed at end of request | Pooled and reused across requests |
| First-request cost | Full handshake every time | Full handshake only on the first request |
| Best for | One-off or short scripts | Repeated calls to the same backend in long-lived workers |
Persistence only helps when the same process serves many requests to the same host/port — typically PHP-FPM or mod_php. In CLI scripts that exit immediately, there is nothing to reuse, so pfsockopen() behaves like fsockopen().
Common gotchas
fclose()does not really close it. Callingfclose()on a persistent socket only returns it to the pool. That is the point — but it means a half-broken connection can be handed to the next request. Always validate the connection (or send a lightweight ping) before relying on it.- No multiplexing. Each PHP worker keeps its own pool, so the number of persistent sockets grows with your worker count. A busy server can exhaust the backend's connection limit.
- State leaks. Because the socket survives between requests, leftover buffered data or a mid-protocol state from a previous request can corrupt the next one. Persistent sockets suit simple, stateless request/response protocols best.
- Removed in PHP 8.2. Code that still calls
pfsockopen()will throw a fatalCall to undefined functionerror on PHP 8.2+.
Modern alternative
On PHP 8.2+, use stream_socket_client() with the STREAM_CLIENT_PERSISTENT flag. It is more flexible (supports tcp://, tls://, and unix:// transports and stream contexts) and is the actively maintained API:
<?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);
}
?>For everyday HTTP work, a higher-level client such as cURL or Guzzle is usually the better choice — reach for raw sockets only when you need a custom protocol.
Conclusion
pfsockopen() created a persistent, reusable socket connection — handy for long-lived PHP workers that repeatedly contacted the same backend. Its key trait was that fclose() returned the socket to a pool instead of closing it. Since the function was removed in PHP 8.2, new code should use stream_socket_client() with STREAM_CLIENT_PERSISTENT. To explore related stream I/O, see fsockopen(), fwrite(), and fread().