This article mainly introduces examples of using websocket in PHP. Friends who need it can refer to it
Below I drew a picture to demonstrate the handshake part when establishing a websocket connection between client and server. This part can be completed very easily in node, because the net module provided by node has already encapsulated the socket. Developers use At this time, you only need to consider the interaction of data without dealing with the establishment of the connection. However, PHP does not. From socket connection, establishment, binding, monitoring, etc., we need to operate these by ourselves, so it is necessary to take it out and talk about it.

① and ② are actually an HTTP request and response, but what we get during the processing is an unparsed string. like:
The code is as follows:
GET /chat HTTP/1.1
Host: server.example.com
Origin: http://www.jb51.com
The requests we usually see look like this. When this thing reaches the server, we can get this information directly through some code libraries.
1. Processing websocket in php
WebSocket connections are actively initiated by the client, so everything must start from the client. The first step is to parse the Sec-WebSocket-Key string sent by the client.
The code is as follows:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://www.jb51.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
client request format
First, php establishes a socket connection and listens for port information.
1. Establishment of socket connection
Regarding the establishment of sockets, I believe many people who have studied computer network in college know this. The following is a process of establishing a connection:

The code is as follows:
// Create a socket socket
$master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($master, $address, $port);
socket_listen($master);
Compared with node, the processing of this place is really troublesome. The above lines of code do not establish a connection, but these codes are what must be written to establish a socket. Since the processing process is slightly complicated, I wrote various processes into a class to facilitate management and calling.
The code is as follows:
//demo.php
Class WS {
var $master; // client connecting to server
var $sockets = array(); // Socket management in different states
var $handshake = false; // Determine whether to shake hands
function __construct($address, $port){
//Create a socket socket
$this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
or die("socket_create() failed");
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1)
or die("socket_option() failed");
socket_bind($this->master, $address, $port)
or die("socket_bind() failed");
socket_listen($this->master, 2)
or die("socket_listen() failed");
$this->sockets[] = $this->master;
// debug
echo("Master socket : ".$this->master."n");
while(true) {
//Automatically select the socket for incoming messages. If it is a handshake, automatically select the host.
$write = NULL;
$except = NULL;
socket_select($this->sockets, $write, $except, NULL);
foreach ($this->sockets as $socket) {
//Client that connects to the host
if ($socket == $this->master){
$client = socket_accept($this->master);
if ($client sockets, $client);
echo "connect clientn";
} else {
$bytes = @socket_recv($socket,$buffer,2048,0);
if (!$this->handshake) {
// If you do n’t shook hands, shook hands to respond first
//doHandShake($socket, $buffer);
echo "shakeHandsn";
} else {
to
$buffer = decode($buffer);
//process($socket, $buffer);
echo "send filen";
}
}
} }
}
}
The above code has been debugged by me, and there is no big problem. If you want to test it, you can type php /path/to/demo.php in the cmd command line; of course, the above is just a class, if you want to test it , you have to create a new instance.
The code is as follows:
$ws = new WS('localhost', 4000);
The client code can be slightly simpler:
The code is as follows:
var ws = new WebSocket("ws://localhost:4000");
ws.onopen = function(){
console.log("Handshake successful");
};
ws.onerror = function(){
console.log("error");
};
Running the server code, when the client connects, we can see:

2. Extract Sec-WebSocket-Key information
The code is as follows:
function getKey($req) {
$key = null;
if (preg_match("/Sec-WebSocket-Key: (.*)rn/", $req, $match)) {
$key = $match[1];
}
Return $key;
}
It’s relatively simple here. Direct regular matching. The websocket information header must contain Sec-WebSocket-Key, so we can match it quickly~
3. Encryption Sec-WebSocket-Key
The code is as follows:
function encry($req){
$key = $this->getKey($req);
$mask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
Return base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
}
The SHA-1 encrypted string is then base64 encrypted. If the encryption algorithm is wrong, the client will directly report an error when checking:

4. Reply Sec-WebSocket-Accept
The code is as follows:
function dohandshake($socket, $req){
// Get encryption key
$acceptKey = $this->encry($req);
$upgrade = "HTTP/1.1 101 Switching Protocolsrn" .
"Upgrade: websocketrn" .
"Connection: Upgradern" .
"Sec-WebSocket-Accept: " . $acceptKey . "rn" .
"rn";
//Write to socket
socket_write(socket,$upgrade.chr(0), strlen($upgrade.chr(0)));
// Mark that the handshake has been successful, and the next time the data is accepted, it will be in data frame format.
$this->handshake = true;
}
You must pay attention here. Every request and corresponding format has a blank line at the end, which is rn. I lost this thing when I started testing, and I struggled for a long time.

When the client successfully checks the key, the onopen function will be triggered:

5. Data frame processing
The code is as follows:
// Parse the data frame
function decode($buffer) {
$len = $masks = $data = $decoded = null;
$len = ord($buffer[1]) & 127;
if ($len === 126) {
$masks = substr($buffer, 4, 4);
$data = substr($buffer, 8);
} else if ($len === 127) {
$masks = substr($buffer, 10, 4);
$data = substr($buffer, 14);
} else {
$masks = substr($buffer, 2, 4);
$data = substr($buffer, 6);
}
for ($index = 0; $index frame($msg);
socket_write($client, $msg, strlen($msg));
}
Client code:
The code is as follows:
var ws = new WebSocket("ws://localhost:4000");
ws.onopen = function(){
console.log("Handshake successful");
};
ws.onmessage = function(e){
console.log("message:" + e.data);
};
ws.onerror = function(){
console.log("error");
};
ws.send("Li Jing");
After sending data after connection, the server returns as it is:

2. Pay attention to problems
1. websocket version problem
The client's request during the handshake contains Sec-WebSocket-Version: 13, which is a version identifier. This is an upgraded version, and all current browsers use this version. The previous version was more troublesome in the data encryption part. It would send two keys:
The code is as follows:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Origin: http://www.jb51.net
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Key1: xxxx
Sec-WebSocket-Key2: xxxx
If it is this version (older and no longer in use), you need to obtain it through the following method
The code is as follows:
function encry($key1,$key2,$l8b){ //Get the numbers preg_match_all('/([d]+)/', $key1, $key1_num); preg_match_all('/([d]+)/' , $key2, $key2_num);
$key1_num = implode($key1_num[0]);
$key2_num = implode($key2_num[0]);
//Count spaces
preg_match_all('/([ ]+)/', $key1, $key1_spc);
preg_match_all('/([ ]+)/', $key2, $key2_spc);
if($key1_spc==0|$key2_spc==0){ $this->log("Invalid key");return; }
//Some math
$key1_sec = pack("N",$key1_num / $key1_spc);
$key2_sec = pack("N",$key2_num / $key2_spc);
return md5($key1_sec.$key2_sec.$l8b,1);
}
I can only complain endlessly about this verification method! Compared to nodeJs’s websocket operation mode:
The code is as follows:
//server program
var crypto = require('crypto');
var WS = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
require('net').createServer(function(o){
var key;
o.on('data',function(e){
if(!key){
//shake hands
key = e.toString().match(/Sec-WebSocket-Key: (.+)/)[1];
key = crypto.createHash('sha1').update(key + WS).digest('base64');
o.write('HTTP/1.1 101 Switching Protocolsrn');
o.write('Upgrade: websocketrn');
o.write('Connection: Upgradern');
o.write('Sec-WebSocket-Accept: ' + key + 'rn');
o.write('rn');
}else{
console.log(e);
};
});
}).listen(8000);
2. Data frame parsing code
This article does not provide data frame parsing code such as decodeFrame. The format of the data frame is given in the previous article. Parsing is purely physical work.
http://www.bkjia.com/PHPjc/740820.htmlwww.bkjia.comtruehttp: //www.bkjia.com/PHPjc/740820.htmlTechArticleThis article mainly introduces examples of using websocket in PHP. Friends who need it can refer to the picture below. The handshake part when establishing a websocket connection between client and server, this...