Skip to content

Commit 8c5dbfd

Browse files
author
HumanConnection
committed
ver 0.1
0 parents  commit 8c5dbfd

File tree

8 files changed

+363
-0
lines changed

8 files changed

+363
-0
lines changed

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Andrei Buldakov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included
14+
in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
PHP WebSocket Client
2+
==========
3+
4+
5+
## Installation
6+
7+
```
8+
composer require andreibu/php_websocket_client
9+
```
10+
11+
## Laravel 5
12+
13+
### Setup
14+
15+
Add ServiceProvider to the providers array in `config/app.php`.
16+
17+
```
18+
19+
'providers' => [
20+
...
21+
AndreiBu\php_websocket_client\WSServiceProvider::class,
22+
23+
],
24+
25+
'aliases' => [
26+
...
27+
28+
'PHP_WS' => AndreiBu\php_websocket_client\Facades\PHP_WS::class,
29+
],
30+
31+
```
32+
33+
34+
### Configuration
35+
36+
37+
```php
38+
host
39+
port=
40+
path=
41+
42+
```
43+
44+
### Usage
45+
46+
##### send
47+
48+
```php
49+
50+
```
51+
52+
53+
54+
55+
56+
57+
## Contribute
58+
59+
https://github.com/AndreiBu/php_websocket_client/pulls

composer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "andreibu/php_websocket_client",
3+
"type": "package",
4+
"description": "PHP WebSocket Client For Laravel.",
5+
"keywords": ["WebSocket","PHP", "laravel", "laravel5"],
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "AndreiBu",
10+
"email": "[email protected]"
11+
}
12+
],
13+
"require": {
14+
"php": ">=5.3.23"
15+
},
16+
"autoload": {
17+
"psr-4": {
18+
"AndreiBu\\php_websocket_client\\": "src/"
19+
}
20+
}
21+
22+
}

phpunit.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
syntaxCheck="false"
12+
>
13+
</phpunit>

src/Facades/PHP_WS.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace AndreiBu\php_websocket_client\Facades;
4+
5+
use Illuminate\Support\Facades\Facade;
6+
7+
class PHP_WS extends Facade
8+
{
9+
/**
10+
* Get the registered name of the component.
11+
*
12+
* @return string
13+
*/
14+
protected static function getFacadeAccessor()
15+
{
16+
return 'PHP_WS';
17+
}
18+
}

src/PHP_WS.php

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
namespace AndreiBu\php_websocket_client;
4+
5+
6+
class PHP_WS
7+
{
8+
private $params;
9+
private $head;
10+
private $instance;
11+
12+
public function __construct($params)
13+
{
14+
foreach($params as $key => $value)
15+
$this->params[$key] = $value;
16+
$local = "://".$this->params['host'];
17+
if(isset($_SERVER['REMOTE_ADDR']))
18+
$local = "http://".$_SERVER['REMOTE_ADDR'];
19+
$this->head = "GET / HTTP/1.1\r\n" .
20+
"Upgrade: websocket\r\n" .
21+
"Connection: Upgrade\r\n" .
22+
"Host: ".$this->params['host']."\r\n" .
23+
"Origin: ".$local."\r\n" .
24+
"Sec-WebSocket-Key: TyPfhFqWTjuw8eDAxdY8xg==\r\n" .
25+
"Sec-WebSocket-Version: 13\r\n";
26+
}
27+
public function send($method)
28+
{
29+
$this->head .= "Content-Length: ".strlen($method)."\r\n\r\n";
30+
$this->connect();
31+
fwrite($this->instance, $this->hybi10Encode($method));
32+
$wsdata = fread($this->instance, 2000);
33+
return $this->hybi10Decode($wsdata);
34+
}
35+
public function close()
36+
{
37+
if($this->instance)
38+
{
39+
fclose($this->instance);
40+
$this->instance = NULL;
41+
}
42+
}
43+
44+
public function connect()
45+
{
46+
$sock = fsockopen($this->params['host'], $this->params['port'], $errno, $errstr);
47+
stream_set_timeout($sock, 1);
48+
fwrite($sock, $this->head);
49+
$headers = fread($sock, 2000);
50+
$this->instance = $sock;
51+
}
52+
53+
private function hybi10Decode($data)
54+
{
55+
$bytes = $data;
56+
$dataLength = '';
57+
$mask = '';
58+
$coded_data = '';
59+
$decodedData = '';
60+
$secondByte = sprintf('%08b', ord($bytes[1]));
61+
$masked = ($secondByte[0]=='1') ? true : false;
62+
$dataLength = ($masked===true) ? ord($bytes[1]) & 127 : ord($bytes[1]);
63+
if ($masked===true)
64+
{
65+
if ($dataLength===126)
66+
{
67+
$mask = substr($bytes, 4, 4);
68+
$coded_data = substr($bytes, 8);
69+
}
70+
elseif ($dataLength===127)
71+
{
72+
$mask = substr($bytes, 10, 4);
73+
$coded_data = substr($bytes, 14);
74+
}
75+
else
76+
{
77+
$mask = substr($bytes, 2, 4);
78+
$coded_data = substr($bytes, 6);
79+
}
80+
for ($i = 0; $i<strlen($coded_data); $i++)
81+
$decodedData .= $coded_data[$i] ^ $mask[$i % 4];
82+
}
83+
else
84+
{
85+
if ($dataLength===126)
86+
$decodedData = substr($bytes, 4);
87+
elseif ($dataLength===127)
88+
$decodedData = substr($bytes, 10);
89+
else
90+
$decodedData = substr($bytes, 2);
91+
}
92+
return $decodedData;
93+
}
94+
private function hybi10Encode($payload, $type = 'text', $masked = true)
95+
{
96+
$frameHead = array();
97+
$frame = '';
98+
$payloadLength = strlen($payload);
99+
switch ($type)
100+
{
101+
case 'text' :
102+
// first byte indicates FIN, Text-Frame (10000001):
103+
$frameHead[0] = 129;
104+
break;
105+
case 'close' :
106+
// first byte indicates FIN, Close Frame(10001000):
107+
$frameHead[0] = 136;
108+
break;
109+
case 'ping' :
110+
// first byte indicates FIN, Ping frame (10001001):
111+
$frameHead[0] = 137;
112+
break;
113+
case 'pong' :
114+
// first byte indicates FIN, Pong frame (10001010):
115+
$frameHead[0] = 138;
116+
break;
117+
}
118+
// set mask and payload length (using 1, 3 or 9 bytes)
119+
if ($payloadLength>65535)
120+
{
121+
$payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);
122+
$frameHead[1] = ($masked===true) ? 255 : 127;
123+
for ($i = 0; $i<8; $i++)
124+
$frameHead[$i + 2] = bindec($payloadLengthBin[$i]);
125+
// most significant bit MUST be 0 (close connection if frame too big)
126+
if ($frameHead[2]>127)
127+
{
128+
$this->close(1004);
129+
return false;
130+
}
131+
}
132+
elseif ($payloadLength>125)
133+
{
134+
$payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);
135+
$frameHead[1] = ($masked===true) ? 254 : 126;
136+
$frameHead[2] = bindec($payloadLengthBin[0]);
137+
$frameHead[3] = bindec($payloadLengthBin[1]);
138+
}
139+
else
140+
$frameHead[1] = ($masked===true) ? $payloadLength + 128 : $payloadLength;
141+
// convert frame-head to string:
142+
foreach (array_keys($frameHead) as $i)
143+
$frameHead[$i] = chr($frameHead[$i]);
144+
if ($masked===true)
145+
{
146+
// generate a random mask:
147+
$mask = array();
148+
for ($i = 0; $i<4; $i++)
149+
$mask[$i] = chr(rand(0, 255));
150+
$frameHead = array_merge($frameHead, $mask);
151+
}
152+
$frame = implode('', $frameHead);
153+
// append payload to frame:
154+
for ($i = 0; $i<$payloadLength; $i++)
155+
$frame .= ($masked===true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
156+
return $frame;
157+
}
158+
}

src/WSServiceProvider.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace AndreiBu\php_websocket_client;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
7+
class WSServiceProvider extends ServiceProvider
8+
{
9+
/**
10+
* Indicates if loading of the provider is deferred.
11+
*
12+
* @var bool
13+
*/
14+
protected $defer = false;
15+
16+
/**
17+
* Bootstrap the application events.
18+
*/
19+
public function boot()
20+
{
21+
$app = $this->app;
22+
23+
$this->bootConfig();
24+
25+
}
26+
27+
/**
28+
* Booting configure.
29+
*/
30+
protected function bootConfig()
31+
{
32+
$path = __DIR__.'/config/php_ws.php';
33+
34+
$this->mergeConfigFrom($path, 'php_ws');
35+
36+
if (function_exists('config_path')) {
37+
$this->publishes([$path => config_path('php_ws.php')]);
38+
}
39+
}
40+
41+
/**
42+
* Register the service provider.
43+
*/
44+
public function register()
45+
{
46+
$this->app->bind('PHP_WS', function ($app) {
47+
return new PHP_WS($app['config']['php_ws']);
48+
});
49+
}
50+
51+
/**
52+
* Get the services provided by the provider.
53+
*
54+
* @return array
55+
*/
56+
public function provides()
57+
{
58+
return ['PHP_WS'];
59+
}
60+
61+
62+
63+
64+
}

src/config/php_ws.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
return [
4+
'host' => env('CAPTCHA_MIN', 'buldakoff.ru'),
5+
'port' => env('CAPTCHA_MAX', 8080),
6+
'path' => env('CAPTCHA_WIDTH', '_ws_'),
7+
];

0 commit comments

Comments
 (0)