I'm writing an MSN client in PHP. This is my code for so far:
$socket = fsockopen("messenger.hotmail.com", 1863);
echo '<b>Connected to 1st server.</b><br />';
//Send MSNP version
fputs($socket, "VER 0 MSNP10 CVR0\r\n");
echo fread($socket, 5000) . '<br />';
//Send user-agent
fputs($socket, "CVR 1 0x0409 php ".phpversion()." i386 MSNMSGR 7.0.0000 MSMSGS ".$_POST["username"]."\r\n");
echo fread($socket, 5000) . '<br />';
//Send username
fputs($socket, "USR 2 TWN I ".$_POST["username"]."\r\n");
//Read XFR
$xfr = fread($socket, 5000);
echo $xfr . '<br />';
$xfr = explode(" ", $xfr);
//Connect to second server
$server2 = explode(":", $xfr[3]);
$socket = fsockopen($server2[0], (int)$server2[1]);
echo '<b>Connected to 2nd server.</b><br />';
//Send MSNP version
fputs($socket, "VER 0 MSNP10 CVR0\r\n");
echo fread($socket, 5000) . '<br />';
//Send user-agent
fputs($socket, "CVR 1 0x0409 php ".phpversion()." i386 MSNMSGR 7.0.0000 MSMSGS ".$_POST["username"]."\r\n");
echo fread($socket, 5000) . '<br />';
//Send username
fputs($socket, "USR 2 TWN I ".$_POST["username"]."\r\n");
//Read USR
$usr = fread($socket, 5000);
echo $usr . '<br />';
$usr = explode(" ", $usr);
//Connect to Nexus
$nexus = fsockopen("nexus.passport.com", 443);
$request_nexus = "GET /rdr/pprdr.asp HTTP/1.1\r\n";
$request_nexus .= "Host:nexus.passport.com\r\n";
$request_nexus .= "User-Agent:MSNphp/1.0 (PHP; U; PHP 5; en-US)\r\n";
$request_nexus .= "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
$request_nexus .= "Accept-Language:en-us,en;q=0.5\r\n";
$request_nexus .= "Keep-Alive:300\r\n";
$request_nexus .= "Connection:keep-alive\r\n";
$request_nexus .= "Cache-Control:max-age=0\r\n\r\n";
fputs($nexus, $request_nexus);
echo fread($nexus, 5000);//This is line 54, which causes the error
My result is this:
Connected to 1st server.
VER 0 MSNP10
CVR 1 1.0.0000 1.0.0000 1.0.0000 http://msgr.dlservice.microsoft.com http://download.live.com/?sku=messenger
XFR 2 NS 207.46.124.241:1863 0 65.54.239.21:1863
Connected to 2nd server.
VER 0 MSNP10
CVR 1 1.0.0000 1.0.0000 1.0.0000 http://msgr.dlservice.microsoft.com http://download.live.com/?sku=messenger
USR 2 TWN S ct=1249043921,rver=5.5.4177.0,wp=FS_40SEC_0_COMPACT,lc=1033,id=507,ru=http:%2F%2Fmessenger.msn.com,tw=0,kpp=1,kv=4,ver=2.1.6000.1,rn=1lgjBfIL,tpf=b0735e3a873dfb5e75054465196398e0
Fatal error: Maximum execution time of 30 seconds exceeded in C:\wamp\apps\msnphp\chat.php on line 54
I get a timeout error when I connect to Nexus. But when I make a request to https://nexus.passport.com/rdr/pprdr.asp in Firefox, I get the result I want (checked with HttpFox). Why does Nexus take so much to to respond to my script? In Firefox it takes 2 seconds.
Does anyone know what I am doing wrong?
Whilst you are connecting to the SSL port (443) on nexus.passport.com , you aren't actually sending the information encrypted: therefore Nexus is just waiting for the encrypted data to arrive and eventually timing out (your PHP script is timing out before hand).
You'll probably be best using Curl to send the information to nexus as it's able to handle the SSL connection for you (why reinvent the wheel?).
Your script is running to long. PHP has a mechanism where it kills a script if it runs longer then specified in settings. You can change this value (it's called max_execution_time) in your php.ini or you can use set_time_limit() function to alter it in your script.
Related
I have the following code, this was previously working and now all of a sudden I am getting an error;
The error I am getting is;
Failed to connect to server Server responed with: Server did not accept to upgrade connection to websocket.HTTP/1.1 200 OK Date: Sun, 22 Aug 2021 01:07:27 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: keep-alive Last-Modified: Fri, 05 Mar 2021 07:33:32 GMT X-By: #XRPLF X-Upgrade: WebSocket X-Conn: upgrade CF-Cache-Status: DYNAMIC Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=ahbUvdpOxo1wZb%2B54qo5pEWE0KGc%2BTpWu2vgw47WhbCgjbfPwdQOGLCAZlivJyijhHs4PTt4nYVIW3ak%2BwAtlz6qhz36saYBmLZ3%2FyKJc8ZB6OJA0%2FNVp14%3D"}],"group":"cf-nel","max_age":604800} NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800} Server: cloudflare CF-RAY: 682834517edc2ce3-LHR alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, h3=":443"; ma=86400 6980
I am not too sure what is causing it below is the code;
<?php
include('/websocket_client.php');
$server = 'xrpl.ws';
$command = json_encode(array(
'id' => 2,
'command' => "server_info"
));
if( $sp = websocket_open($server, 443,'',$errstr, 10, true) ) {
websocket_write($sp,$command);
$result = websocket_read($sp,$errstr);
}else {
echo "Failed to connect to server\n";
echo "Server responed with: $errstr\n";
}
$result_data = json_decode($result, true);
echo '<pre>';
echo $result_data;
echo '</pre>';
?>
Below is the Websocket_Client.php page I am sorry for the length ; But I thought it might be important to include it all.
<?php
/*----------------------------------------------------------------------------*\
Websocket client - https://github.com/paragi/PHP-websocket-client
By Paragi 2013, Simon Riget MIT license.
This is a demonstration of a websocket clinet.
If you find flaws in it, please let me know at simon.riget (at) gmail
Websockets use hybi10 frame encoding:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/63) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
See: https://tools.ietf.org/rfc/rfc6455.txt
or: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10#section-4.2
\*----------------------------------------------------------------------------*/
/*============================================================================*\
Open websocket connection
resource websocket_open(string $host [,int $port [,$additional_headers [,string &error_string ,[, int $timeout]]]]
host
A host URL. It can be a domain name like www.example.com or an IP address,
with port number. Local host example: 127.0.0.1:8080
port
headers (optional)
additional HTTP headers to attach to the request.
For example to parse a session cookie: "Cookie: SID=" . session_id()
error_string (optional)
A referenced variable to store error messages, i any
timeout (optional)
The maximum time in seconds, a read operation will wait for an answer from
the server. Default value is 10 seconds.
ssl (optional)
persistant (optional)
path (optional)
Context (optional)
Open a websocket connection by initiating a HTTP GET, with an upgrade request
to websocket.
If the server accepts, it sends a 101 response header, containing
"Sec-WebSocket-Accept"
\*============================================================================*/
function websocket_open($host='',$port=80,$headers='',&$error_string='',$timeout=10,$ssl=false, $persistant = false, $path = '/', $context = null){
// Generate a key (to convince server that the update is not random)
// The key is for the server to prove it i websocket aware. (We know it is)
$key=base64_encode(openssl_random_pseudo_bytes(16));
$header = "GET " . $path . " HTTP/1.1\r\n"
."Host: $host\r\n"
."pragma: no-cache\r\n"
."Upgrade: WebSocket\r\n"
."Connection: Upgrade\r\n"
."Sec-WebSocket-Key: $key\r\n"
."Sec-WebSocket-Version: 13\r\n";
// Add extra headers
if(!empty($headers)) foreach($headers as $h) $header.=$h."\r\n";
// Add end of header marker
$header.="\r\n";
// Connect to server
$host = $host ? $host : "127.0.0.1";
$port = $port <1 ? ( $ssl ? 443 : 80 ): $port;
$address = ($ssl ? 'ssl://' : '') . $host . ':' . $port;
$flags = STREAM_CLIENT_CONNECT | ( $persistant ? STREAM_CLIENT_PERSISTENT : 0 );
$ctx = $context ?? stream_context_create();
$sp = stream_socket_client($address, $errno, $errstr, $timeout, $flags, $ctx);
if(!$sp){
$error_string = "Unable to connect to websocket server: $errstr ($errno)";
return false;
}
// Set timeouts
stream_set_timeout($sp,$timeout);
if (!$persistant or ftell($sp) === 0) {
//Request upgrade to websocket
$rc = fwrite($sp,$header);
if(!$rc){
$error_string
= "Unable to send upgrade header to websocket server: $errstr ($errno)";
return false;
}
// Read response into an assotiative array of headers. Fails if upgrade failes.
$reaponse_header=fread($sp, 1024);
// status code 101 indicates that the WebSocket handshake has completed.
if (stripos($reaponse_header, ' 101 ') === false
|| stripos($reaponse_header, 'Sec-WebSocket-Accept: ') === false) {
$error_string = "Server did not accept to upgrade connection to websocket."
.$reaponse_header. E_USER_ERROR;
return false;
}
// The key we send is returned, concatenate with "258EAFA5-E914-47DA-95CA-
// C5AB0DC85B11" and then base64-encoded. one can verify if one feels the need...
}
return $sp;
}
/*============================================================================*\
Write to websocket
int websocket_write(resource $handle, string $data ,[boolean $final])
Write a chunk of data through the websocket, using hybi10 frame encoding
handle
the resource handle returned by websocket_open, if successful
data
Data to transport to server
final (optional)
indicate if this block is the final data block of this request. Default true
binary (optional)
indicate if this block is sent in binary or text mode. Default true/binary
\*============================================================================*/
function websocket_write($sp,$data,$final=true,$binary=true){
// Assemble header: FINal 0x80 | Mode (0x02 binary, 0x01 text)
if ($binary)
$header=chr(($final?0x80:0) | 0x02); // 0x02 binary mode
else
$header=chr(($final?0x80:0) | 0x01); // 0x01 text mode
// Mask 0x80 | payload length (0-125)
if(strlen($data)<126) $header.=chr(0x80 | strlen($data));
elseif (strlen($data)<0xFFFF) $header.=chr(0x80 | 126) . pack("n",strlen($data));
else $header.=chr(0x80 | 127) . pack("N",0) . pack("N",strlen($data));
// Add mask
$mask=pack("N",rand(1,0x7FFFFFFF));
$header.=$mask;
// Mask application data.
for($i = 0; $i < strlen($data); $i++)
$data[$i]=chr(ord($data[$i]) ^ ord($mask[$i % 4]));
return fwrite($sp,$header.$data);
}
/*============================================================================*\
Read from websocket
string websocket_read(resource $handle [,string &error_string])
read a chunk of data from the server, using hybi10 frame encoding
handle
the resource handle returned by websocket_open, if successful
error_string (optional)
A referenced variable to store error messages, i any
Read
Note:
- This implementation waits for the final chunk of data, before returning.
- Reading data while handling/ignoring other kind of packages
\*============================================================================*/
function websocket_read($sp,&$error_string=NULL){
$data="";
do{
// Read header
$header=fread($sp,2);
if(!$header){
$error_string = "Reading header from websocket failed.";
return false;
}
$opcode = ord($header[0]) & 0x0F;
$final = ord($header[0]) & 0x80;
$masked = ord($header[1]) & 0x80;
$payload_len = ord($header[1]) & 0x7F;
// Get payload length extensions
$ext_len = 0;
if($payload_len >= 0x7E){
$ext_len = 2;
if($payload_len == 0x7F) $ext_len = 8;
$header=fread($sp,$ext_len);
if(!$header){
$error_string = "Reading header extension from websocket failed.";
return false;
}
// Set extented paylod length
$payload_len= 0;
for($i=0;$i<$ext_len;$i++)
$payload_len += ord($header[$i]) << ($ext_len-$i-1)*8;
}
// Get Mask key
if($masked){
$mask=fread($sp,4);
if(!$mask){
$error_string = "Reading header mask from websocket failed.";
return false;
}
}
// Get payload
$frame_data='';
while($payload_len>0){
$frame= fread($sp,$payload_len);
if(!$frame){
$error_string = "Reading from websocket failed.";
return false;
}
$payload_len -= strlen($frame);
$frame_data.=$frame;
}
// Handle ping requests (sort of) send pong and continue to read
if($opcode == 9){
// Assamble header: FINal 0x80 | Opcode 0x0A + Mask on 0x80 with zero payload
fwrite($sp,chr(0x8A) . chr(0x80) . pack("N", rand(1,0x7FFFFFFF)));
continue;
// Close
} elseif($opcode == 8){
fclose($sp);
// 0 = continuation frame, 1 = text frame, 2 = binary frame
}elseif($opcode < 3){
// Unmask data
$data_len=strlen($frame_data);
if($masked)
for ($i = 0; $i < $data_len; $i++)
$data.= $frame_data[$i] ^ $mask[$i % 4];
else
$data.= $frame_data;
}else
continue;
}while(!$final);
return $data;
}
?>
I thought initially I had been blacklisted or something for the amount of requests I was making and the fact that it in the message I saw something about CloudFlare but I used a VPN to navigate to xrpl.ws via the IP of the host and I was able to access this without problems. I have not made any changes to the PHP ini file either so I really am stuck to what is causing this. Thanks for any help and sorry for the length of the examples. Thanks again.
I did see this previous answer which mentioned about the way the key is generated but I looked into it and I believe its using a good generation method. So I really am at a loss.
The error message is pretty clear:
Server did not accept to upgrade connection to websocket.
You'd need Ratchet, because there likely is no web-socket support available on this server.
Or it may send out unexpected HTTP headers.
I'm trying to connect a PHP-based client to a websocket server.
Here's the code I have been using which has been widely published on different forums. But for some reason I just cannot get it to work.
Any help would be appreciated.
$host = 'host'; //where is the websocket server
$port = 443; //ssl
$local = "http://www.example.com/"; //url where this script run
$data = '{"id": 2,"command": "server_info"}'; //data to be send
$head = "GET / HTTP/1.1"."\r\n".
"Upgrade: WebSocket"."\r\n".
"Connection: Upgrade"."\r\n".
"Origin: $local"."\r\n".
"Host: $host"."\r\n".
"Content-Length: ".strlen($data)."\r\n"."\r\n";
////WebSocket handshake
$sock = fsockopen($host, $port, $errno, $errstr, 2);
fwrite($sock, $head ) or die('error:'.$errno.':'.$errstr);
$headers = fread($sock, 2000);
fwrite($sock, "\x00$data\xff" ) or die('error:'.$errno.':'.$errstr);
$wsdata = fread($sock, 2000); //receives the data included in the websocket package "\x00DATA\xff"
$retdata = trim($wsdata,"\x00\xff"); //extracts data
////WebSocket handshake
fclose($sock);
echo $retdata;
I would probably prefer to use an existing websocket client library (maybe https://github.com/gabrielbull/php-websocket-client or https://github.com/Devristo/phpws/tree/master/src/Devristo/Phpws/Client ?) rather than roll your own, but I got it to at least connect by using:
$head = "GET / HTTP/1.1"."\r\n".
"Host: $host"."\r\n".
"Upgrade: websocket"."\r\n".
"Connection: Upgrade"."\r\n".
"Sec-WebSocket-Key: asdasdaas76da7sd6asd6as7d"."\r\n".
"Sec-WebSocket-Version: 13"."\r\n".
"Content-Length: ".strlen($data)."\r\n"."\r\n";
My server is using TLS/SSL, so I also needed:
$sock = fsockopen('tls://'.$host, $port, $errno, $errstr, 2);
The full protocol spec is: https://tools.ietf.org/rfc/rfc6455.txt
UPDATE 2019: many servers requires the key to be more unique that the original example, resulting in failure to establish upgrade connection. The key generation is now changed accordingly.
Your header must contain:
Sec-WebSocket-Key: (some value)
Sec-WebSocket-Version: 13
to connect successfully.
When you have made the connection, you also need to use the hybi10 frame encoding.
See: https://tools.ietf.org/rfc/rfc6455.txt - Its a bit dry though.
I have made this working example:
<?php
$sp=websocket_open('127.0.0.1/ws_request.php?param=php_test',$errstr);
websocket_write($sp,"Websocket request message");
echo websocket_read($sp,true);
$sp=websocket_open('127.0.0.1:8080/ws_request.php?param=php_test',$errstr);
websocket_write($sp,"Websocket request message");
echo websocket_read($sp,true);
function websocket_open($url){
$key=base64_encode(openssl_random_pseudo_bytes(16));
$query=parse_url($url);
$header="GET / HTTP/1.1\r\n"
."pragma: no-cache\r\n"
."cache-control: no-cache\r\n"
."Upgrade: WebSocket\r\n"
."Connection: Upgrade\r\n"
."Sec-WebSocket-Key: $key\r\n"
."Sec-WebSocket-Version: 13\r\n"
."\r\n";
$sp=fsockopen($query['host'],$query['port'], $errno, $errstr,1);
if(!$sp) die("Unable to connect to server ".$url);
// Ask for connection upgrade to websocket
fwrite($sp,$header);
stream_set_timeout($sp,5);
$reaponse_header=fread($sp, 1024);
if(!strpos($reaponse_header," 101 ")
|| !strpos($reaponse_header,'Sec-WebSocket-Accept: ')){
die("Server did not accept to upgrade connection to websocket"
.$reaponse_header);
}
return $sp;
}
function websocket_write($sp, $data,$final=true){
// Assamble header: FINal 0x80 | Opcode 0x02
$header=chr(($final?0x80:0) | 0x02); // 0x02 binary
// Mask 0x80 | payload length (0-125)
if(strlen($data)<126) $header.=chr(0x80 | strlen($data));
elseif (strlen($data)<0xFFFF) $header.=chr(0x80 | 126) . pack("n",strlen($data));
elseif(PHP_INT_SIZE>4) // 64 bit
$header.=chr(0x80 | 127) . pack("Q",strlen($data));
else // 32 bit (pack Q dosen't work)
$header.=chr(0x80 | 127) . pack("N",0) . pack("N",strlen($data));
// Add mask
$mask=pack("N",rand(1,0x7FFFFFFF));
$header.=$mask;
// Mask application data.
for($i = 0; $i < strlen($data); $i++)
$data[$i]=chr(ord($data[$i]) ^ ord($mask[$i % 4]));
return fwrite($sp,$header.$data);
}
function websocket_read($sp,$wait_for_end=true,&$err=''){
$out_buffer="";
do{
// Read header
$header=fread($sp,2);
if(!$header) die("Reading header from websocket failed");
$opcode = ord($header[0]) & 0x0F;
$final = ord($header[0]) & 0x80;
$masked = ord($header[1]) & 0x80;
$payload_len = ord($header[1]) & 0x7F;
// Get payload length extensions
$ext_len = 0;
if($payload_len >= 0x7E){
$ext_len = 2;
if($payload_len == 0x7F) $ext_len = 8;
$ext=fread($sp,$ext_len);
if(!$ext) die("Reading header extension from websocket failed");
// Set extented paylod length
$payload_len= 0;
for($i=0;$i<$ext_len;$i++)
$payload_len += ord($header[$i]) << ($ext_len-$i-1)*8;
}
// Get Mask key
if($masked){
$mask=fread($sp,4);
if(!$mask) die("Reading header mask from websocket failed");
}
// Get payload
$frame_data='';
do{
$frame= fread($sp,$payload_len);
if(!$frame) die("Reading from websocket failed.");
$payload_len -= strlen($frame);
$frame_data.=$frame;
}while($payload_len>0);
// if opcode ping, reuse headers to send a pong and continue to read
if($opcode==9){
// Assamble header: FINal 0x80 | Opcode 0x02
$header[0]=chr(($final?0x80:0) | 0x0A); // 0x0A Pong
fwrite($sp,$header.$ext.$mask.$frame_data);
// Recieve and unmask data
}elseif($opcode<3){
$data="";
if($masked)
for ($i = 0; $i < $data_len; $i++)
$data.= $frame_data[$i] ^ $mask[$i % 4];
else
$data.= $frame_data;
$out_buffer.=$data;
}
// wait for Final
}while($wait_for_end && !$final);
return $out_buffer;
}
You can get the full version here: https://github.com/paragi/PHP-websocket-client
Connecting to a WSS stream with purely php:
Example with the public binance wss api.
<?php
$sock = stream_socket_client("tls://stream.binance.com:9443",$error,$errnum,30,STREAM_CLIENT_CONNECT,stream_context_create(null));
if (!$sock) {
echo "[$errnum] $error" . PHP_EOL;
} else {
echo "Connected - Do NOT get rekt!" . PHP_EOL;
fwrite($sock, "GET /stream?streams=btcusdt#kline_1m HTTP/1.1\r\nHost: stream.binance.com:9443\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: ".rand(0,999)."\r\n\r\n");
while (!feof($sock)) {
var_dump(explode(",",fgets($sock, 512)));
}
}
More details: WebSockets - send json data via php
https://github.com/ratchetphp/Pawl
I tried around 10 different solutions from various stackoverflow threads but nothing worked, after spending about 6 hours trying different solution this worked for me.
scenario:
Ratchet as server
I was able to connect via reactjs
I wasn't able to connect via php,
Expected Result: To send message from php-client to all connected react clients. the git repo i provided was a lucky break i was looking for.
I tried the solution presented here and it works fine for me.
here are the details:
step1: Install the library from here with non-root user as follows:
php8.0 composer require textalk/websocket
then use the code below for sending some message to a socket which is located on localhost and has port number 8080:
<?php
require('vendor/autoload.php');
use WebSocket\Client;
$client = new Client("ws://127.0.0.1:8080");
$client->send($argv[1]);
?>
Since I had php7.1 webserver and the socket was installed with php8.0, I put the above code in a PHP file (testphp.php) and call it using shell_exec('php8.0 testphp.php hello');
The 400 error is because you're missing Host and Origin in the header.
$key=base64_encode(openssl_random_pseudo_bytes(16));
$query=parse_url($url);
$local = "http://".$query['host'];
if (isset($_SERVER['REMOTE_ADDR'])) $local = "http://".$_SERVER['REMOTE_ADDR'];
$header="GET / HTTP/1.1\r\n"
."Host: ".$query['host']."\r\n"
."Origin: ".$local."\r\n"
."Pragma: no-cache\r\n"
."Cache-Control: no-cache\r\n"
."Upgrade: websocket\r\n"
."Connection: Upgrade\r\n"
."Sec-WebSocket-Key: $key\r\n"
."Sec-WebSocket-Version: 13\r\n"
."\r\n";
I'm trying to send a huge amount of data using SSL/TLS connection in PHP. It works pretty well if the data chunk isn't very big or if I don't use TLS, but what I need (near 2MiB), the fwrite function shows the warning:
Warning: fwrite(): SSL operation failed with code 1. OpenSSL Error messages: error: 1409F07F: SSL routines: SSL3_WRITE_PENDING: bad write retry
The relevant code I'm using to connect clients:
$cntxt = stream_context_create(array('ssl' => array('local_cert' => 'certificate.pem')));
$server = stream_socket_server('tls://127.0.0.1:8080', $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $cntxt);
// Wait for client connection //
$client = stream_socket_accept($server);
// Use non-blocking socket to allow answering many clients at a time
stream_set_blocking($client, 0);
$clients[] = $client;
When sending data, it's append to a buffer and, from time to time, this function is called for each client and linked buffer:
function trySend($client, &$buffer) {
if (strlen($buffer)) {
$len = fwrite($client, $buffer);
$buffer = substr($buffer, $len);
}
}
As I said, my code works for small ammount of data or for normal (non-TLS) connections. I've searched for this error and found http://www.openssl.org/docs/ssl/SSL_write.html:
SSL_write() will only return with success, when the complete contents of buf of length num has been written. This default behaviour can be changed with the SSL_MODE_ENABLE_PARTIAL_WRITE option of SSL_CTX_set_mode(3). When this flag is set, SSL_write() will also return with success, when a partial write has been successfully completed. In this case the SSL_write() operation is considered completed. The bytes are sent and a new SSL_write() operation with a new buffer (with the already sent bytes removed) must be started. A partial write is performed with the size of a message block, which is 16kB for SSLv3/TLSv1.
But how can I do this in PHP?
Any help appreciated :)
I have found I can get around this problem by restricting the length of the string passed to fwrite() to 8192, which prevents fwrite() warning.
So for the code in your example I would try changing the substr() call to:
$buffer = substr($buffer, $len, 8192);
The solution is:
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
try {
$result = fwrite($fp, $msg, strlen($msg));
}
catch (Exception $ex) {
sleep(1); //sleep for 5 seconds
$result = fwrite($fp, $msg, strlen($msg));
}
I am running into a silly problem: I need to get a certain number of bytes, then close the connection. I've found I can extract the "Content Length" from the header, and use the length to determine just how many more bytes I should get before severing the connection. However, it appears I have made a mistake. It is only getting 40 bytes, instead of 2428 (as it should). Perhaps I am not using fgets() correctly?
Here is the code:
private static function Send($URL, $Data) {
$server = parse_url($URL, PHP_URL_HOST);
$port = parse_url($URL, PHP_URL_PORT);
// If the parsing the port information fails, we will assume it's on a default port.
// As such, we'll set the port in the switch below.
if($port == null) {
switch(parse_url($URL, PHP_URL_SCHEME)) {
case "HTTP":
$port = 80;
break;
case "HTTPS":
$port = 443;
break;
}
}
// Check if we are using a proxy (debug configuration typically).
if(\HTTP\HTTPRequests::ProxyEnabled) {
$server = \HTTP\HTTPRequests::ProxyServer;
$port = \HTTP\HTTPRequests::ProxyPort;
}
// Open a connection to the server.
$connection = fsockopen($server, $port, $errno, $errstr);
if (!$connection) {
die("OMG Ponies!");
}
echo "===========================================================<BR>";
echo "Connection Open<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
echo "Sending Request<BR>";
fwrite($connection, $Data);
echo "Request Sent.";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
$responseheader = "";
$responsebody = "";
/*
\HTTP\HTTPRequests::$start = NULL;
\HTTP\HTTPRequests::$timeout = 10;
// #todo: Rewrite this. Should keep checking for '/r/n/r/n', then check for a content length header. If found, keep grabbing bytes, then close. If not, then close immediately.
while(!\HTTP\HTTPRequests::safe_feof($connection, \HTTP\HTTPRequests::$start) && (microtime(true) - \HTTP\HTTPRequests::$start) < \HTTP\HTTPRequests::$timeout)
{
$response .= fgets($connection);
}
*/
echo "Getting Response<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
while(!feof($connection) && !(strlen(strstr($responseheader,"\r\n\r\n"))>0)) {
$responseheader .= fgets($connection);
}
echo "The Header is fully received at " . date("H:i:su", time()) . "<BR>";
echo "Header (raw):" . "<BR>";
echo "/////////////////////////////////////////////<BR>";
echo $responseheader . "<BR>";
echo "/////////////////////////////////////////////<BR>";
if((strlen(strstr($responseheader,"Content-Length:"))>0)) {
$contentlength = ((int)(\Extract\Extract::GetContentLength($responseheader)));
//for($i = 0; $i < $contentlength; $i++) {
$responsebody .= fgets($connection, $contentlength);
//}
echo "The Body is fully received at " . date("H:i:su", time()) . "<BR>";
echo "Body (raw):" . "<BR>";
echo "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}<BR>";
echo $responsebody . "<BR>";
echo "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}<BR>";
echo "<B>!Content length is " . strlen($responsebody) . ". It should be " . $contentlength . "!</B><BR>";
}
echo "Response Received.<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
fclose($connection);
echo "Connection Closed.<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
echo "Exiting Send() method.<BR>";
echo "===========================================================<BR>";
echo "<BR>";
return $responseheader . $responsebody;
}
And here is the output:
===========================================================
Connection Open
The Time is 15:57:29000000
Sending Request
Request Sent.The Time is 15:57:29000000
Getting Response
The Time is 15:57:29000000
The Header is fully received at 15:57:29000000
Header (raw):
/////////////////////////////////////////////
HTTP/1.1 207 Multi-Status Date: Wed, 11 Apr 2012 19:57:18 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.14 with Suhosin-Patch mod_ssl/2.2.8 OpenSSL/0.9.8g mod_wsgi/2.0 Python/2.5.2 mod_perl/2.0.3 Perl/v5.8.8 X-Powered-By: PHP/5.2.4-2ubuntu5.14 DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule Content-Location: /davical/caldav.php/rwr26/home/ ETag: "8378ead7e628deafd91ec99dc180ad74" X-DAViCal-Version: DAViCal/0.9.9; DB/1.2.9 Content-Length: 2428 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/xml; charset="utf-8"
/////////////////////////////////////////////
The Body is fully received at 15:57:29000000
Body (raw):
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
!Content length is 40. It should be 2428!
Response Received.
The Time is 15:57:29000000
Connection Closed.
The Time is 15:57:29000000
Exiting Send() method.
===========================================================
Why am I doing it this way? Apparently, I was running into some sort of a timeout error, which makes each connection stay open for 30 seconds (yes, 30 whole seconds). So I wrote this code to get the exact number of bytes, then close. Any help is greatly appreciated.
I changed the content line "$responsebody .= fgets($connection, $contentlength);" to "$responsebody .= stream_get_line($connection, $contentlength);". Thing is wicked fast now, and works.
I'm new to web sockets.. i made my first web socket and i am having problems on running it now!
here is the code of the socket
// set some variables
$host = "127.0.0.1";
$port = 1234;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
if($socket){
echo "socket created .... $socket\n";
}
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
if($result){
echo "socket binded ... $result\n";
}
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");
if($result){
echo "socket is now listening ... $result";
}
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
if($spawn){
echo $spawn."\n";
}
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
if($input){
echo $input."\n";
}
// clean up input string
$input = trim($input);
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
now how can i run this code?? i wrote on my xampp shell the following code:
php htdocs/socket/server.php -q
it displays:
socket created....Resource id #4
socket binded... 1
socket is now listening...1 Resource is #5
GET socket/server.php HTTP 1.1
upgrade: WebSocket
connection: Upgrade
Host: http://localhost
sec-WebSocket-key1: 14 53 8501 z4 5R'
sec-WebSocket-key2: S 9\ 2s63, *8460!~MO#
now how can i run it.. how can i send input to it and how can i use it with JavaScript??
i made a JavaScript code but it connect for a second and then disconnect...
here is the javascipt code:
$(document).ready(function() {
if(!("WebSocket" in window)){
$('#chatLog, input, button, #examples').fadeOut("fast");
$('<p>Oh no, you need a browser that supports WebSockets. How about Google Chrome?</p>').appendTo('#container');
}else{
//The user has WebSockets
connect();
function connect(){
var socket;
var host = "ws://localhost:1234/websocket_source_files/myown.php";
try{
var socket = new WebSocket(host);
message('<p class="event">Socket Status: '+socket.readyState);
socket.onopen = function(){
message('<p class="event">Socket Status: '+socket.readyState+' (open)');
}
socket.onmessage = function(msg){
message('<p class="message">Received: '+msg.data);
}
socket.onclose = function(){
message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
}
} catch(exception){
message('<p>Error'+exception);
}
function send(){
var text = $('#text').val();
if(text==""){
message('<p class="warning">Please enter a message');
return ;
}
try{
socket.send(text);
message('<p class="event">Sent: '+text)
} catch(exception){
message('<p class="warning">');
}
$('#text').val("");
}
function message(msg){
$('#chatLog').append(msg+'</p>');
}//End message()
$('#text').keypress(function(event) {
if (event.keyCode == '13') {
send();
}
});
$('#disconnect').click(function(){
socket.close();
});
}
}//End connect()
});
</script>
<title>WebSockets Client</title>
</head>
<body>
<div id="wrapper">
<div id="container">
<h1>WebSockets Client</h1>
<div id="chatLog">
</div>
<p id="examples">e.g. try 'hi', 'name', 'age', 'today'</p>
<input id="text" type="text" />
<button id="disconnect">Disconnect</button>
</div>
</div>
</body>
</html>
please help me run this code and learn web sockets.. i really need to use them with my school project.
The socket_accept-function will block (wait) until a client connects to it. That's it's standard behavior.
But the functions you execute after you've connected your socket don't block (unless you tell them to). So you'll want to tell your script to wait until it can read from the Socket.
To do so, the socket_set_block-function is used. Also, you might want to check for any possible errors using the socket_last_error-function.
Although, I think Java or C are way bedder suited for using Sockets.
Write another PHP script which would connect to it.
you are not doing the handshake propertly.
from what you posted, you are dealing with the ietf-00 implementation ( https://datatracker.ietf.org/doc/html/draft-ietf-hybi-thewebsocketprotocol-00 )
this is old and deprecated, the last one seems to be ietf-10 ( https://datatracker.ietf.org/doc/html/draft-ietf-hybi-thewebsocketprotocol-10 ).
a very basic description of the handshake you need can be found here: http://en.wikipedia.org/wiki/WebSockets
(you can find in there the links to the newer and official specifications).
The important part in your case is this:
The Sec-WebSocket-Key1 and Sec-WebSocket-Key2 fields and the 8 bytes
after the fields are random tokens which the server uses to construct
a 16-byte token at the end of its handshake to prove that it has read
the client's handshake.
The handshake is constructed by concatenating the numbers from the
first key, and dividing by the number of spaces. This is then repeated
for the second key. The two resulting numbers are concatenated with
each other, and with the last 8 bytes after the fields.
The final result is an MD5 sum of the concatenated string.[7] The
handshake looks like HTTP but actually isn't. It allows the server to
interpret part of the handshake request as HTTP and then switch to
WebSocket. Once established, WebSocket data frames can be sent back
and forth between the client and the server in full-duplex mode. Text
frames can be sent full-duplex, in either direction at the same time.
The data is minimally framed with just two bytes. Each frame starts
with a 0x00 byte, ends with a 0xFF byte, and contains UTF-8 data in
between. Binary frames are not supported yet in the API. WebSocket
text frames use a terminator, while binary frames use a length prefix.
Now, some code (this will accept one connection, receive a message, and then send a response, just like a very basic and raw example to show how it can be done):
// Just to log to console
function myLog($msg)
{
echo date('m/d/Y H:i:s ', time()) . $msg . "\n";
}
// This will actually read and process the key-1 and key-2 variables, doing the math for them
function getWebSocketKeyHash($key)
{
$digits = '';
$spaces = 0;
// Get digits
preg_match_all('/([0-9])/', $key, $digits);
$digits = implode('', $digits[0]);
// Count spaces
$spaces = preg_match_all("/\\s/ ", $key, $dummySpaces);
$div = (int)$digits / (int)$spaces;
myLog('key |' . $key . '|: ' . $digits . ' / ' . $spaces . ' = ' . $div);
return (int)$div;
}
// This will read one header: value from the request header
function getWebSocketHeader($buffer, &$lines, &$keys)
{
preg_match_all("/([a-zA-Z0-9\\-]*)(\\s)*:(\\s)*(.*)?\r\n/", $buffer, $headers);
$lines = explode("\r\n", $buffer);
$keys = array_combine($headers[1], $headers[4]);
}
// This is where the handshake gets done
function handshake($peer)
{
$buffer = socket_read($peer, 4096, PHP_BINARY_READ);
socket_getpeername($peer, $address, $port);
$peerName = $address . ':' . $port;
myLog('Got from: ' . $peerName . ': ' . $buffer);
getWebSocketHeader($buffer, $lines, $keys);
if (!isset($keys['Sec-WebSocket-Key1']) || !isset($keys['Sec-WebSocket-Key2'])) {
myLog('Invalid websocket handshake for: ' . $peerName);
return;
}
$key1 = getWebSocketKeyHash($keys['Sec-WebSocket-Key1']);
$key2 = getWebSocketKeyHash($keys['Sec-WebSocket-Key2']);
$code = array_pop($lines);
// Process the result from both keys and form the response header
$key = pack('N', $key1) . pack('N', $key2) . $code;
myLog('1:|' . $key1 . '|- 2:|' . $key2 . '|3:|' . $code . '|4: ' . $key);
$response = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n";
$response .= "Upgrade: WebSocket\r\n";
$response .= "Connection: Upgrade\r\n";
$response .= "Sec-WebSocket-Origin: " . trim($keys['Origin']) . "\r\n";
$response .= "Sec-WebSocket-Location: ws://" . trim($keys['Host']) . "/\r\n";
$response .= "\r\n" . md5($key, true); // this is the actual response including the hash of the result of processing both keys
myLog($response);
socket_write($peer, $response);
}
// This is where you can send a frame (delimited by 0x00 and 0xFF)
function send($peer, $message)
{
socket_write($peer, pack('c', (int)0) . utf8_encode($message) . pack('c', (int)255));
}
// This is where you receive a frame (delimited again by 0x00 and 0xFF)
function receive($peer)
{
$buffer = socket_read($peer, 4096, PHP_BINARY_READ);
if (empty($buffer)) {
myLog('Error receiving from peer');
return;
}
return substr($buffer, 1, -1);
}
// Now create a socket
$socket = socket_create_listen(1026);
$peer = socket_accept($socket);
// Do the handshake and wait for an incoming message from the client
handshake($peer);
myLog('Got ' . receive($peer));
// Respond!
send($peer, 'hi there');
socket_close($peer);
socket_close($socket);
EDIT:
this is a very basic html that works in chrome (mine at least):
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function WebSocketTest()
{
if ("WebSocket" in window)
{
// Let us open a web socket
var ws = new WebSocket("ws://host:1026");
ws.onopen = function()
{
// Web Socket is connected, send data using send()
ws.send("Message to send");
console.log('send');
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
console.log(received_msg);
var txt = document.createTextNode(received_msg);
document.getElementById('messages').appendChild(txt);
};
ws.onclose = function()
{
// websocket is closed.
console.log('close');
};
}
else
{
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
</script>
</head>
<body>
<div id="sse">
Run WebSocket
</div>
<div id="messages">
</div>
</body>
</html>