Fonction PHP socket_set_timeout() : Tout ce que vous devez savoir
Découvrez la fonction socket_set_timeout() en PHP pour définir un délai d'expiration sur les flux réseau et éviter les blocages indéfinis.
Lorsque votre script lit depuis une connexion réseau, un serveur lent ou mort peut laisser PHP bloquer indéfiniment, monopolisant un processus de travail et frustrant les utilisateurs. La fonction socket_set_timeout() définit une limite de temps sur les opérations de lecture/écriture, de sorte qu'une connexion bloquée échoue rapidement au lieu de rester suspendue. Cet article explique précisément ce qu'elle contrôle, les pièges courants et comment détecter un délai d'expiration lorsqu'il se produit.
Ce que fait la fonction socket_set_timeout()
socket_set_timeout() définit le délai d'expiration pour les opérations d'E/S — fread(), fgets(), fwrite(), etc. — sur un flux ouvert avec fsockopen() ou pfsockopen(). Si une lecture ou une écriture ne se termine pas dans le délai imparti, l'opération se termine prématurément et le flux est marqué comme ayant expiré.
Deux choses qu'elle ne fait pas :
- Elle n'affecte pas le délai d'expiration de la connexion. C'est le cinquième argument de
fsockopen($host, $port, $errno, $errstr, $connectTimeout).socket_set_timeout()régit uniquement le transfert de données une fois la connexion établie. - Elle ne fait pas échouer l'appel de manière bruyante. Une lecture dont le délai expire renvoie les données reçues jusqu'à présent (souvent une chaîne vide) et définit un indicateur — vous devez inspecter cet indicateur vous-même avec
stream_get_meta_data().
Piège de nommage : Malgré le préfixe
socket_, cette fonction appartient à la famille des flux, et non à l'extension Sockets. Elle fonctionne sur les ressources issues defsockopen(), jamais sur une ressource issue desocket_create(). Depuis PHP 8.0, il s'agit d'un alias déprécié destream_set_timeout()— préférez ce nom dans le nouveau code.
Syntaxe
socket_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool| Paramètre | Description |
|---|---|
$stream | Une ressource de flux ouverte retournée par fsockopen() ou pfsockopen(). |
$seconds | Le délai d'expiration en secondes entières. |
$microseconds | Temps supplémentaire en microsecondes (optionnel, par défaut 0). |
Elle retourne true en cas de succès et false en cas d'échec (par exemple, si $stream n'est pas une ressource de flux valide).
Un exemple fonctionnel
Ouvrez une connexion, définissez un délai d'expiration de lecture de 5 secondes, puis vérifiez si une lecture a expiré :
<?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);L'élément clé est l'appel à stream_get_meta_data() : son élément timed_out est le seul moyen fiable de distinguer un véritable délai d'expiration d'une connexion qui s'est simplement fermée.
Lecture en boucle
Lorsque vous lisez une réponse entière, vérifiez timed_out à chaque itération pour qu'un blocage en cours de transfert ne tronque pas silencieusement vos données :
<?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";Pièges courants
- Mauvais type de ressource. Passer une ressource
socket_create()ne sert à rien — utilisezstream_set_timeout()avec les socketssocket_create(), ousocket_set_option()pourSO_RCVTIMEO/SO_SNDTIMEO. - Confusion entre délai de connexion et délai de lecture. Un long délai de connexion
fsockopen()ne vous protégera pas d'une réponse lente ; vous avez besoin des deux. - Oublier de vérifier
timed_out. Sans cela, une lecture expirée ressemble exactement à une fin de flux normale, entraînant une troncature silencieuse des données.
Fonctions associées
fsockopen()— ouvre le flux sur lequel cette fonction opère.stream_get_meta_data()via socket_get_status() — lit l'indicateurtimed_out.socket_set_blocking()— bascule un flux entre le mode bloquant et non bloquant.fgets()etfwrite()— les appels d'E/S auxquels le délai s'applique.
Conclusion
socket_set_timeout() empêche les lectures et écritures réseau lentes de bloquer votre script PHP. N'oubliez pas qu'elle fonctionne sur les flux fsockopen() (pas l'extension Sockets), régit les E/S plutôt que la connexion, et que vous devez inspecter l'indicateur timed_out de stream_get_meta_data() pour savoir si un délai d'expiration s'est réellement produit. Dans le nouveau code, préférez son nom moderne, stream_set_timeout().