PHP 8.3.4 Released!

stream_socket_client

(PHP 5, PHP 7, PHP 8)

stream_socket_clientAbre conexão de socket de domínio Internet ou Unix

Descrição

stream_socket_client(
    string $address,
    int &$error_code = null,
    string &$error_message = null,
    ?float $timeout = null,
    int $flags = STREAM_CLIENT_CONNECT,
    ?resource $context = null
): resource|false

Inicia uma conexão de fluxo ou datagrada ao destino especificado pelo parâmetro address. O tipo de socket criado é determinado pelo transporte especificado usando-se formatação de URL padrão: transporte://alvo. Para sockets de domínio Internet (AF_INET) tais como TCP e UDP, a porção alvo do parâmetro address deve consistir de um nome de servidor ou endereço IP seguido por dois-pontos e um número de porta. Para sockets de domínio Unix, a porção alvo seve apontar ao arquivo de socket no sistema de arquivos.

Nota:

O fluxo por padrão será aberto em modo de bloqueio. Pode-se trocar para modo de não-bloqueio usando stream_set_blocking().

Parâmetros

address

Endereço ao qual o socket deve se conectar.

error_code

Será definido para o número de erro no nível do sistema se a conexão falhar.

error_message

Será definido para a mensagem de erro no nível do sistema se a conexão falhar.

timeout

Número máximo de segundos que a chamada de sistema connect() deve esperar. Por padrão, default_socket_timeout é usado.

Nota: Este parâmetro aplica-se somente quando não há tentativas de se fazer conexões assíncronas.

Nota:

Para definir um limite de tempo para leitura/escrita de dados no socket, use a função stream_set_timeout(), já que timeout se aplica somente enquanto está sendo feita a conexão ao socket.

flags

Um campo de máscara de bits que pode ser configurada para qualquer combinação de opções de conexão. Atualmente a seleção de opções de conecão está limitada a STREAM_CLIENT_CONNECT (padrão), STREAM_CLIENT_ASYNC_CONNECT e STREAM_CLIENT_PERSISTENT.

context

Um recurso válido de contexto criado com stream_context_create().

Valor Retornado

Em caso de sucesso, um recurso de fluxo é retornado, e pode ser usado com outras funções de arquivos (como fgets(), fgetss(), fwrite(), fclose() e feof()), false em caso de falha.

Erros/Exceções

Em caso de falha, os argumentos error_code e error_message serão preenchidos com o erro real no que ocorreu na chamada no nível de sistema a connect(). Se o valor retornado em error_code for 0 e a função retornar false, é uma indicação que o erro ocorreu antes da chamada a connect(). Isto é mais provavelmente devido a um problema na inicialização do socket. Note que os argumentos error_code e error_message serão sempre passados por referência.

Registro de Alterações

Versão Descrição
8.0.0 timeout e context agora podem ser nulos.

Exemplos

Exemplo #1 Exemplo de stream_socket_client()

<?php
$fp
= stream_socket_client("tcp://www.example.com:80", $errno, $errstr, 30);
if (!
$fp) {
echo
"$errstr ($errno)<br />\n";
} else {
fwrite($fp, "GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n");
while (!
feof($fp)) {
echo
fgets($fp, 1024);
}
fclose($fp);
}
?>

Exemplo #2 Usando conexão UDP

Obtendo dia e horário do serviço UDP "daytime" (porta 13) no servidor local.

<?php
$fp
= stream_socket_client("udp://127.0.0.1:13", $errno, $errstr);
if (!
$fp) {
echo
"ERRO: $errno - $errstr<br />\n";
} else {
fwrite($fp, "\n");
echo
fread($fp, 26);
fclose($fp);
}
?>

Notas

Aviso

Sockets UDP algumas vezes irão aparentar ter sido abertos sem erro, mesmo se o servidor remoto não puder ser contactado. O erro só ficará aparente quando for realizada leitura/escrita no socket. A razão para isto é porque o UDP é um protocolo "sem conexão", o que significa que o sistema operacional não tenta estabelecer uma ligação ao socket até que realmente precise enviar ou receber dados.

Nota: Ao especificar um endereço IPv6 numérico (por exemplo, fe80::1), o IP deve ser colocado entre colchetes — por exemplo, tcp://[fe80::1]:80.

Nota:

Dependendo do ambiente, o domínio Unix ou o limite opcional de tempo de conexão podem não estar disponíveis. Uma lista de transportes disponíveis pode sem obtida usando-se stream_get_transports(). Consulte Lista de Transportes via Socket Suportados para uma lista de transportes incluídos.

Veja Também

  • stream_socket_server() - Cria socket de servidor de domínio Internet ou Unix
  • stream_set_blocking() - Definir modo de bloqueio/não-bloqueio em um fluxo
  • stream_set_timeout() - Define o limite de tempo em um fluxo
  • stream_select() - Executa o equivalente à chamada de sistema select() nos arrays de fluxos informados com um limite de tempo especificado por segundos e microssegundos
  • fgets() - Lê uma linha de um ponteiro de arquivo
  • fgetss() - Ler uma linha de um ponteiro de arquivo e retira as tags HTML
  • fwrite() - Escrita binary-safe em arquivos
  • fclose() - Fecha um ponteiro de arquivo aberto
  • feof() - Testa pelo fim-de-arquivo em um ponteiro de arquivo
  • Funções cURL

add a note

User Contributed Notes 6 notes

up
23
nicholas at nicholaswilliams dot net
15 years ago
For those wanting to use stream_socket_client() to connect to a local UNIX socket who can't find documentation on how to do it, here's a (rough) example:

<?php

$sock
= stream_socket_client('unix:///full/path/to/my/socket.sock', $errno, $errstr);

fwrite($sock, 'SOME COMMAND'."\r\n");

echo
fread($sock, 4096)."\n";

fclose($sock);

?>
up
11
Vasil Rangelov a.k.a. boen_robot
12 years ago
The remote_socket argument, in its end (well... after the port), can also contain a "/" followed by a unique identifier. This is especially useful if you want to create multiple persistent connections to the same transport://host:port combo.

Example:
<?php
$socket
= stream_socket_client('tcp://mysql.example.com:3306/root', $errorno, $errorstr, $timeout, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT);
?>

Note that while (p)fsockopen() follows a similar scheme, it doesn't have this particular feature.
up
6
wbeaver at afilias dot info
16 years ago
# Some may find it useful to know that your caCert
# must be in pem format, and that PHP seems to like
# your key, cert, and cacert pem's to be concatenated
# in a single file (I suffered various "unknown chain"
# errors, otherwise)
#
# So, (linux users), concat your components as follows:
# (where current working dir is dir where
# cert components are stored)
#
# cat key.pem >certchain.pem
# cat cert.pem >>certchain.pem
# cat cacert.pem >>certchain.pem
#
# Then, the php....
##################################

<?php

$host
= 'host.domain.tld';
$port = 1234;
$timeout = 10;

$cert = '/path/to/your/certchain/certchain.pem';
$context = stream_context_create(array('ssl'=>array('local_cert'=> $cert,
)));

if (
$fp = stream_socket_client('ssl://'.$host.':'.$port, $errno, $errstr, 30,
STREAM_CLIENT_CONNECT, $context)) {
fwrite($fp, "\n");
echo
fread($fp,8192);
fclose($fp);
} else {
echo
"ERROR: $errno - $errstr<br />\n";
}

?>
up
2
Daniel
9 years ago
If you only need to check a stream for data, you can use stream_get_content and strtr function. stream_get_content
reads the remainder of a stream into a string.
<?php

$addr
= gethostbyname('www.example.com');

$client = stream_socket_client("tcp://$addr:80", $errno, $errorMessage);

if(
$client === false){
throw new
UnexpectedValueException("Failed to connect: $errorMessage");
}

fwrite($client, "GET / HTTP/1.0\r\nhost: 'www.example.com'\r\nAccept: */*\r\n\r\n");

$variable = stream_get_content($client);

if(
strstr($variable,'data your looking for'))
echo
"The data you are looking for is here";
else
echo
"data not found";

fclose($client);
?>
up
1
robin at gareus dot org
15 years ago
I came here since fsockopen() does not support any SSL certificate checking in PHP5.

while curl is nice, I use stream_socket_client() to make XML-RPC POST requests via HTTPS and since I have not found any PHP code around that does this, I'll attach an example that also includes HTTP-Digest Auth (eg. trac's WikiRPCInterface2):

<?php
#################################################
# $host: hostname ; eg 'example.org'
# $path: request' eg '/index.php?id=123'
# $data_to_send : data to POST after the HTTP header.
#
# if $opts is an empty array() a standard HTTP to port 80 request is performed.
#
# set auth['type']='basic' to use plain-text auth,
# digest-auth will be handled automatically if $auth['username'] is set and a 401
# status is encountered. - use auth['type']='nodigest' to override.
#
##
function httpPost($host, $path, $data_to_send,
$opts=array('cert'=>"", 'headers'=>0, 'transport' =>'ssl', 'port'=>443),
$auth=array('username'=>"", 'password'=>"", 'type'=>"")
) {
$transport=''; $port=80;
if (!empty(
$opts['transport'])) $transport=$opts['transport'];
if (!empty(
$opts['port'])) $port=$opts['port'];
$remote=$transport.'://'.$host.':'.$port;

$context = stream_context_create();
$result = stream_context_set_option($context, 'ssl', 'verify_host', true);
if (!empty(
$opts['cert'])) {
$result = stream_context_set_option($context, 'ssl', 'cafile', $opts['cert']);
$result = stream_context_set_option($context, 'ssl', 'verify_peer', true);
} else {
$result = stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
}
$fp = stream_socket_client($remote, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $context);

if (!
$fp) {
trigger_error('httpPost error: '.$errstr);
return
NULL;
}

$req='';
$req.="POST $path HTTP/1.1\r\n";
$req.="Host: $host\r\n";
if (
$auth['type']=='basic' && !empty($auth['username'])) {
$req.="Authorization: Basic ";
$req.=base64_encode($auth['username'].':'.$auth['password'])."\r\n";
}
elseif (
$auth['type']=='digest' && !empty($auth['username'])) {
$req.='Authorization: Digest ';
foreach (
$auth as $k => $v) {
if (empty(
$k) || empty($v)) continue;
if (
$k=='password') continue;
$req.=$k.'="'.$v.'", ';
}
$req.="\r\n";
}
$req.="Content-type: text/xml\r\n";
$req.='Content-length: '. strlen($data_to_send) ."\r\n";
$req.="Connection: close\r\n\r\n";

fputs($fp, $req);
fputs($fp, $data_to_send);

while(!
feof($fp)) { $res .= fgets($fp, 128); }
fclose($fp);

if (
$auth['type']!='nodigest'
&& !empty($auth['username'])
&&
$auth['type']!='digest' # prev. digest AUTH failed.
&& preg_match("/^HTTP\/[0-9\.]* 401 /", $res)) {
if (
1 == preg_match("/WWW-Authenticate: Digest ([^\n\r]*)\r\n/Us", $res, $matches)) {
foreach (
split(",", $matches[1]) as $i) {
$ii=split("=",trim($i),2);
if (!empty(
$ii[1]) && !empty($ii[0])) {
$auth[$ii[0]]=preg_replace("/^\"/",'', preg_replace("/\"$/",'', $ii[1]));
}
}
$auth['type']='digest';
$auth['uri']='https://'.$host.$path;
$auth['cnonce']=randomNonce();
$auth['nc']=1;
$a1=md5($auth['username'].':'.$auth['realm'].':'.$auth['password']);
$a2=md5('POST'.':'.$auth['uri']);
$auth['response']=md5($a1.':'
.$auth['nonce'].':'.$auth['nc'].':'
.$auth['cnonce'].':'.$auth['qop'].':'.$a2);
return
httpPost($host, $path, $data_to_send, $opts, $auth);
}
}

if (
1 != preg_match("/^HTTP\/[0-9\.]* ([0-9]{3}) ([^\r\n]*)/", $res, $matches)) {
trigger_error('httpPost: invalid HTTP reply.');
return
NULL;
}

if (
$matches[1] != '200') {
trigger_error('httpPost: HTTP error: '.$matches[1].' '.$matches[2]);
return
NULL;
}

if (!
$opts['headers']) {
$res=preg_replace("/^.*\r\n\r\n/Us",'',$res);
}
return
$res;
}
?>
up
-11
bisho at onirica dot com
13 years ago
stream_socket_client is much easier and faster to use to direct sockets, because you can use directly fwrite / fget / fclose functions, but I find hard to find how to connect to a UNIX domain socket. The URL to use is "udg:///path/to/socket".

For example, to log to the log socket (like syslog), you can use:

<?php
$socket
= stream_socket_client('udg:///dev/log',
$errorno,
$errorstr,
$timeout);
fwrite($socket, ...);
?>
To Top