Função PHP socket_set_timeout(): Tudo o Que Você Precisa Saber
Aprenda como usar socket_set_timeout() no PHP para definir um tempo limite em operações de leitura/escrita em streams e evitar bloqueios prolongados.
Quando seu script lê de uma conexão de rede, um servidor lento ou inativo pode deixar o PHP bloqueado indefinidamente, prendendo um worker e frustrando os usuários. A função socket_set_timeout() define um prazo para operações de leitura/escrita, de modo que uma conexão travada falhe rapidamente em vez de ficar suspensa. Este artigo explica exatamente o que ela controla, as armadilhas comuns e como detectar um timeout quando ele ocorre.
O Que a Função socket_set_timeout() Faz
socket_set_timeout() define o timeout para operações de E/S — fread(), fgets(), fwrite(), etc. — em um stream aberto com fsockopen() ou pfsockopen(). Se uma leitura ou escrita não for concluída dentro do prazo, a operação retorna antecipadamente e o stream é marcado como timed out (tempo esgotado).
Duas coisas que ela não faz:
- Ela não afeta o timeout de conexão. Esse é o quinto argumento de
fsockopen($host, $port, $errno, $errstr, $connectTimeout).socket_set_timeout()governa apenas a transferência de dados após a conexão ser aberta. - Ela não faz a chamada falhar de forma explícita. Uma leitura que atinge o timeout retorna os dados recebidos até o momento (frequentemente uma string vazia) e define um flag — você precisa inspecionar esse flag com
stream_get_meta_data().
Armadilha de nomenclatura: Apesar do prefixo
socket_, essa função pertence à família de streams, não à extensão Sockets. Ela funciona em recursos defsockopen(), nunca em um recurso desocket_create(). Desde o PHP 8.0, é um alias depreciado destream_set_timeout()— prefira esse nome em código novo.
Sintaxe
socket_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool| Parâmetro | Descrição |
|---|---|
$stream | Um recurso de stream aberto retornado por fsockopen() ou pfsockopen(). |
$seconds | O timeout em segundos inteiros. |
$microseconds | Tempo adicional em microssegundos (opcional, padrão 0). |
Retorna true em caso de sucesso e false em caso de falha (por exemplo, se $stream não for um recurso de stream válido).
Um Exemplo Funcional
Abra uma conexão, defina um timeout de leitura de 5 segundos e verifique se uma leitura atingiu o timeout:
<?php
// Open a TCP connection to a web server.
$stream = fsockopen("www.example.com", 80, $errno, $errstr, 10);
if (!$stream) {
echo "Connection failed: $errstr ($errno)\n";
exit;
}
// Fail any single read/write that stalls for more than 5 seconds.
socket_set_timeout($stream, 5);
// Send a minimal HTTP request.
fwrite($stream, "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n");
// Read the first line of the response.
$line = fgets($stream, 1024);
// Check whether that read hit the timeout.
$info = stream_get_meta_data($stream);
if ($info['timed_out']) {
echo "Read timed out — the server was too slow.\n";
} else {
echo "First response line: " . trim($line) . "\n";
}
fclose($stream);O ponto-chave é a chamada a stream_get_meta_data(): o elemento timed_out é a única maneira confiável de distinguir um timeout genuíno de uma conexão que simplesmente fechou.
Leitura em Loop
Quando você lê uma resposta completa, verifique timed_out a cada iteração para que uma interrupção no meio da transferência não trunque silenciosamente seus dados:
<?php
$stream = fsockopen("www.example.com", 80, $errno, $errstr, 10);
socket_set_timeout($stream, 5);
fwrite($stream, "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n");
$body = "";
while (!feof($stream)) {
$chunk = fgets($stream, 4096);
$info = stream_get_meta_data($stream);
if ($info['timed_out']) {
echo "Stalled before the response finished.\n";
break;
}
$body .= $chunk;
}
fclose($stream);
echo "Received " . strlen($body) . " bytes.\n";Armadilhas Comuns
- Tipo de recurso errado. Passar um recurso de
socket_create()não tem utilidade — usestream_set_timeout()com sockets desocket_create(), ousocket_set_option()paraSO_RCVTIMEO/SO_SNDTIMEO. - Confundir timeouts de conexão e de leitura. Um timeout longo de conexão no
fsockopen()não vai protegê-lo de uma resposta lenta; você precisa de ambos. - Esquecer de verificar
timed_out. Sem isso, uma leitura com timeout parece exatamente um fim de stream limpo, levando a dados truncados silenciosamente.
Funções Relacionadas
fsockopen()— abre o stream no qual esta função opera.stream_get_meta_data()via socket_get_status() — lê o flagtimed_out.socket_set_blocking()— alterna um stream entre modo bloqueante e não bloqueante.fgets()efwrite()— as chamadas de E/S às quais o timeout se aplica.
Conclusão
socket_set_timeout() evita que leituras e escritas lentas de rede travem seu script PHP. Lembre-se de que ela funciona em streams de fsockopen() (não na extensão Sockets), governa E/S em vez da conexão, e que você deve inspecionar o flag timed_out de stream_get_meta_data() para saber se um timeout realmente ocorreu. Em código novo, utilize seu nome moderno, stream_set_timeout().