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);
?>
stream_socket_client
(PHP 5)
stream_socket_client — Abrir una conexión de socket de dominio de Internet o Unix
Descripción
Inicia una conexión secuenciada o tipo datagrama al destino especificado por socket_remoto . El tipo de socket creado es determinado por el transporte especificado usando el formato de URL estándar: transporte://destino. Para sockets de dominio de Internet (AF_INET) tales como TCP y UDP, la porción destino del parámetro socket_remoto debe consistir de un nombre de host o dirección IP seguido de un signo de dos puntos y un número de puerto. Para sockets de dominio Unix, la porción destino debe apuntar al archivo de socket en el sistema de archivos. El tiempo_espera opcional puede ser usado para establecer un tiempo de espera máximo en segundos para el llamado de conexión del sistema. banderas es un campo de máscara de bits que puede ser definido como una combinación de banderas de conexión. Actualmente, las banderas de conexión disponibles están limitadas a STREAM_CLIENT_CONNECT (predeterminada), STREAM_CLIENT_ASYNC_CONNECT y STREAM_CLIENT_PERSISTENT.
Note: Si necesita establecer un tiempo de espera para la lectura/escritura de datos sobre el socket, use stream_set_timeout(), ya que el parámetro tiempo_espera de stream_socket_client() sólo se aplica cuando se establece la conexión con el socket.
Note: El parámetro de tiempo de espera solo se aplica si no está intentando realizar una conexión asincrónica.
stream_socket_client() devuelve un recurso de secuencia que puede ser usado junto con las otras funciones de archivos (tales como fgets(), fgetss(), fwrite(), fclose(), y feof()).
Si la llamada falla, devolverá FALSE y si los argumentos opcionales errno y errstr están presentes, éstos serán definidos de modo tal que indiquen el error de nivel de sistema actual que ocurrió en el llamado de nivel de sistema connect(). Si el valor devuelto en errno es 0 y la función devolvió FALSE, es un indicio de que el error ocurrió antes del llamado a connect(). Esto es por lo general debido a un problema con la inicialización del socket. Note que los argumentos errno y errstr serán siempre pasados por referencia.
Dependiendo del entorno, el dominio Unix o el tiempo de espera de conexión opcional pueden no estar disponibles. Una lista de transportes disponibles puede ser recuperada usando stream_get_transports(). Vea Lista de Transportes de Sockets Soportados para consultar una lista de transportes incorporados.
La secuencia será abierta de forma predeterminada en modo de bloqueo. Puede modificarla a modo de no-bloqueo usando stream_set_blocking().
Example #1 Ejemplo de stream_socket_client()
<?php
$da = stream_socket_client("tcp://www.example.com:80", $errno, $errstr, 30);
if (!$da) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($da, "GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n");
while (!feof($da)) {
echo fgets($da, 1024);
}
fclose($da);
}
?>
Example #2 Uso de una conexión UDP
<?php
$da = stream_socket_client("udp://127.0.0.1:13", $errno, $errstr);
if (!$da) {
echo "ERROR: $errno - $errstr<br />\n";
} else {
fwrite($da, "\n");
echo fread($da, 26);
fclose($da);
}
?>
Los sockets UDP parecerán haber sido abiertos sin error en ocasiones, incluso si el host remoto no ha podido ser contactado. El error solo se hará aparente cuando lea o escriba datos desde/hacia el socket. La razón de esto es que UDP es un protocolo "sin conexión", lo que quiere decir que el sistema operativo no intenta establecer un enlace para el socket hasta que realmente necesita enviar o recibir datos.
Note: Cuando se especifique una dirección numérica IPv6 (p.ej. fe80::1) se debe incluir la IP entre corchetes. Por ejemplo tcp://[fe80::1]:80.
Vea también stream_socket_server(), stream_set_blocking(), stream_set_timeout(), stream_select(), fgets(), fgetss(), fwrite(), fclose(), feof(), y la extensión Curl.
stream_socket_client
29-Oct-2008 01:08
26-Aug-2008 11:19
the httpPost() function was almost too long for a user-comment.. I've cut some newlines but to be complete the code snippet misses:
<?php
function randomNonce($len=0) {
$chars = "ABCDEFGHIJKMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz023456789";
$i=0; $rv='';
if ($len < 1) $len= (6+rand()%10);
while ($i++ < $len) {
$rv.=$chars[rand() % strlen($chars)];
}
return $rv;
}
?>
26-Aug-2008 10:34
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;
}
?>
31-Aug-2007 09:06
# 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";
}
?>
