This commit is contained in:
以诺书 2022-12-15 18:09:24 +08:00
commit da496c3606
116 changed files with 14092 additions and 0 deletions

View File

View File

@ -0,0 +1,8 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns2://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('udp://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->protocol = 'Dns';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('udp://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->protocol = 'dns';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('udp://0.0.0.0:53');
$worker->protocol = 'Dns';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
echo getRemoteIp();
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
echo $data;
echo $connection->getRemoteIp();
};
Worker::runAll();

View File

@ -0,0 +1,16 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip"
};
Worker::runAll();

View File

@ -0,0 +1,16 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n"
};
Worker::runAll();

View File

@ -0,0 +1,16 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
};
Worker::runAll();

View File

@ -0,0 +1,20 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
#echo "$type\n$name\n$rip\n";
};
Worker::runAll();

View File

@ -0,0 +1,20 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://0.0.0.0:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
#echo "$type\n$name\n$rip\n";
$connection->send('0000000381800001000000000000047a6c69001062026d6c00001c0001');
};
Worker::runAll();

View File

@ -0,0 +1,20 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
#echo "$type\n$name\n$rip\n";
$connection->send('0000000381800001000000000000047a6c69001062026d6c00001c0001');
};
Worker::runAll();

View File

@ -0,0 +1,20 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
#echo "$type\n$name\n$rip\n";
$connection->send('000281800001000200000000047a6c6962026d6c0000010001c00c000100010000003c0004d466323ac00c000100010000001e0004d466323a');
};
Worker::runAll();

View File

@ -0,0 +1,21 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=explode('|||', $data);
$type=$data[0];
$name=$data[1];
$rip=$connection->getRemoteIp();
#echo "$type\n$name\n$rip\n";
$connection->send('000281800001000200000000047a6c6962026d6c0000010001c00c000100010000003c0004d466323ac00c000100010000001e0004d466323a');
};
Worker::runAll();

View File

@ -0,0 +1,21 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data['type'];
$name=$data['realname'];
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$connection->send('000281800001000200000000047a6c6962026d6c0000010001c00c000100010000003c0004d466323ac00c000100010000001e0004d466323a');
};
Worker::runAll();

View File

@ -0,0 +1,21 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$connection->send('000281800001000200000000047a6c6962026d6c0000010001c00c000100010000003c0004d466323ac00c000100010000001e0004d466323a');
};
Worker::runAll();

View File

@ -0,0 +1,22 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$send['type']='A';
$send['detail']='119.29.29.29';
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,23 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$send['type']='A';
$send['detail']='119.29.29.29';
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,25 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$send['type']='A';
$send['detail']='119.29.29.29';
$send['id']=$data->id;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,26 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$send['type']='A';
$send['detail']='119.29.29.29';
$send['id']=$data->id;
$send['query']=$data->query;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,27 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$send['type']='A';
$send['detail']='119.29.29.29';
$send['id']=$data->id;
$send['query']=$data->query;
$send['ttl']=60;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,27 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
// 注意直接udp协议是有效的使用自定义协议无效
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
echo "$type\n$name\n$rip\n";
$send['type']='A';
$send['detail']='119.29.29.29';
$send['id']=$data->id;
$send['query']=$data->query;
$send['ttl']=30;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,41 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
#输出信息
#echo "Type: $type \n Domain: $name\n Client IP: $rip \n";
/** A类记录返回
$send['type']='A';
$send['detail']='119.29.29.29';
$send['ttl']=30;
**/
$send['type']='NS';
$send['detail']='coco.bunny.net';
$send['ttl']=30;
#id和query一般情况下直接返回输出即可
$send['id']=$data->id;
$send['query']=$data->query;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

@ -0,0 +1,42 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
#输出信息
#echo "Type: $type \n Domain: $name\n Client IP: $rip \n";
/** A类记录返回
$send['type']='A';
$send['detail']='119.29.29.29';
$send['ttl']=30;
**/
$send['type']='NS';
$send['detail'][1]='coco.bunny.net';
$send['detail'][2]='kiki.bunny.net';
$send['ttl']=30;
#id和query一般情况下直接返回输出即可
$send['id']=$data->id;
$send['query']=$data->query;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

View File

View File

@ -0,0 +1,21 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
// 创建一个Worker监听2345端口使用http协议通讯
$http_worker = new Worker("http://0.0.0.0:2345");
// 启动4个进程对外提供服务
$http_worker->count = 4;
// 接收到浏览器发送的数据时回复hello world给浏览器
$http_worker->onMessage = function(TcpConnection $connection, Request $request)
{
// 向浏览器发送hello world
$connection->send('hello world');
};
// 运行worker
Worker::runAll();

View File

@ -0,0 +1,22 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
// 创建一个Worker监听2345端口使用http协议通讯
$http_worker = new Worker("udp://0.0.0.0:53");
// 启动4个进程对外提供服务
$http_worker->count = 4;
// 接收到浏览器发送的数据时回复hello world给浏览器
$http_worker->onMessage = function(TcpConnection $connection, Request $request)
{
var_dump($request);
// 向浏览器发送hello world
$connection->send('hello world');
};
// 运行worker
Worker::runAll();

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://127.0.0.1:9090');
$udp_worker->onMessage = function($connection, $data){
var_dump($data);
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
var_dump($data);
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
echo($data);
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,12 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
echo(bin2hex($data));
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
echo(bin2hex($data));
echo "/n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,13 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
echo(bin2hex($data));
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,15 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
echo(substr($data,-8,4));
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,19 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
echo(substr($data,-8,4));
echo "\n";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,34 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
}
echo($type);
echo "\n";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,37 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
}
echo($type);
echo "\n";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,42 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,43 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
echo $name;
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,45 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
#$namede=str_split($name,2);
echo hex2bin($name);
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,45 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
#$namede=str_split($name,2);
echo hex2bin('01');
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,47 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
#$namede=str_split($name,2);
echo hex2bin('01');
if(!hex2bin('01')){
echo "none";
}
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,55 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($str)){
$chat='.';
}
$realname=$realname.$chat;
}
echo hex2bin('01');
if(!hex2bin('01')){
echo "none";
}
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,52 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($str)){
$chat='.';
}
$realname=$realname.$chat;
}
echo "realname";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,52 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($str)){
$chat='.';
}
$realname=$realname.$chat;
}
echo "$realname";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,52 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($chat)){
$chat='.';
}
$realname=$realname.$chat;
}
echo "$realname";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,53 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://0.0.0.0:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($chat)){
$chat='.';
}
$realname=$realname.$chat;
}
$realname=substr($realname,1,-1);
echo "$realname";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,53 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://172.17.120.40:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($chat)){
$chat='.';
}
$realname=$realname.$chat;
}
$realname=substr($realname,1,-1);
echo "$realname";
echo "\n";
$connection->send('get');
};
Worker::runAll();

View File

@ -0,0 +1,125 @@
<?php
namespace Workerman\Protocols;
class Dns
{
/**
* 检查包的完整性
* 如果能够得到包长则返回包的在buffer中的长度否则返回0继续等待数据
* 如果协议有问题则可以返回false当前客户端连接会因此断开
* @param string $buffer
* @return int
*/
public static function input($buffer)
{
return 200;
}
/**
* 打包,当向客户端发送数据的时候会自动调用
* @param string $buffer
* @return string
*/
public static function encode($buffer)
{
$buffer=json_decode($buffer);
$type=$buffer->type;
switch($type){
case 'A':
$type='0001';
$lenth='0004';
$ip=$buffer->detail;
$n=0;
foreach($ip as $i){
$nss=explode('.',$i);
$detail[$n]='';
foreach($nss as $part){
$tpart=dechex($part);
$detail[$n]=$detail[$n].$tpart;
};
$n+1;
};
break;
case 'NS':
$type='0002';
$lenth='0004';
$ns=$buffer->detail;
$n=0;
foreach($ns as $i){
$nss=explode('.',$i);
$detail[$n]='';
foreach($nss as $part){
$len=strlen($part);
$tpart=bin2hex($part);
$detail[$n]=$detail[$n].$len.$tpart;
};
$detail[$n]=$detail[$n].'00';
$n+1;
};
break;
}
$ttl=str_pad(dechex($buffer->ttl),8,"0",STR_PAD_LEFT);
$status='8180';
$questions='0001';
$AnswerRRs='0001';
$AuthorityRRs='0000';
$AdditionalRRs='0000';
$answer='';
foreach($detail as $c){
$answer=$answer.'C00C'.$type.'0001'.$ttl.$lenth.$c;
}
$response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query.$answer;
return hex2bin($response);
}
/**
* 解包当接收到的数据字节数等于input返回的值大于0的值自动调用
* 并传递给onMessage回调函数的$data参数
* @param string $buffer
* @return string
*/
public static function decode($buffer)
{
$data=bin2hex($buffer);
$id=substr($data,0,4);
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
$name=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($chat)){
$chat='.';
}
$realname=$realname.$chat;
}
$realname=substr($realname,1,-1);
$query=substr($data,24);
#$returndata="$type".'|||'."$realname";
$returndata= json_encode(array('type' => "$type", 'name' => "$realname", 'id'=>"$id", 'query'=>"$query"));
return $returndata;
}
}

5
composer.json Normal file
View File

@ -0,0 +1,5 @@
{
"require": {
"workerman/workerman": "^4.1"
}
}

59
composer.lock generated Normal file
View File

@ -0,0 +1,59 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f83c087b46e30125925a7337b17a4aca",
"packages": [
{
"name": "workerman/workerman",
"version": "v4.1.0",
"dist": {
"type": "zip",
"url": "https://mirrors.tencent.com/repository/composer/workerman/workerman/v4.1.0/workerman-workerman-v4.1.0.zip",
"reference": "88ddf517e5c35bee072b2e453c4fcca0c6f1e59a",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"suggest": {
"ext-event": "For better performance. "
},
"type": "library",
"autoload": {
"psr-4": {
"Workerman\\": "./"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.",
"homepage": "http://www.workerman.net",
"keywords": [
"asynchronous",
"event-loop"
],
"time": "2022-08-20T10:16:22+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

53
start.php Normal file
View File

@ -0,0 +1,53 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$udp_worker = new Worker('udp://172.17.120.40:53');
$udp_worker->onMessage = function($connection, $data){
$data=bin2hex($data);
echo($data);
echo "\n";
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
echo($type);
echo "\n";
$name=$type=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($chat)){
$chat='.';
}
$realname=$realname.$chat;
}
$realname=substr($realname,1,-1);
echo "$realname";
echo "\n";
$connection->send('get');
};
Worker::runAll();

42
start2.php Normal file
View File

@ -0,0 +1,42 @@
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('Dns://172.17.120.40:53');
$worker->transport = 'udp';
$worker->onMessage = function($connection, $data){
$data=json_decode($data);
$type=$data->type;
$name=$data->name;
$rip=$connection->getRemoteIp();
#输出信息
#echo "Type: $type \n Domain: $name\n Client IP: $rip \n";
/** A类记录返回
$send['type']='A';
$send['detail']='119.29.29.29';
$send['ttl']=30;
**/
$send['type']='NS';
$send['detail'][1]='coco.bunny.net';
$send['detail'][2]='kiki.bunny.net';
$send['ttl']=30;
#id和query一般情况下直接返回输出即可
$send['id']=$data->id;
$send['query']=$data->query;
$send=json_encode($send);
$connection->send($send);
};
Worker::runAll();

12
vendor/autoload.php vendored Normal file
View File

@ -0,0 +1,12 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit738d15a25cb49a9fe191f4f579c57b01::getLoader();

572
vendor/composer/ClassLoader.php vendored Normal file
View File

@ -0,0 +1,572 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
}

352
vendor/composer/InstalledVersions.php vendored Normal file
View File

@ -0,0 +1,352 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
return $installed;
}
}

21
vendor/composer/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

10
vendor/composer/autoload_classmap.php vendored Normal file
View File

@ -0,0 +1,10 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

10
vendor/composer/autoload_psr4.php vendored Normal file
View File

@ -0,0 +1,10 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Workerman\\' => array($vendorDir . '/workerman/workerman'),
);

38
vendor/composer/autoload_real.php vendored Normal file
View File

@ -0,0 +1,38 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit738d15a25cb49a9fe191f4f579c57b01
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit738d15a25cb49a9fe191f4f579c57b01', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit738d15a25cb49a9fe191f4f579c57b01', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit738d15a25cb49a9fe191f4f579c57b01::getInitializer($loader));
$loader->register(true);
return $loader;
}
}

36
vendor/composer/autoload_static.php vendored Normal file
View File

@ -0,0 +1,36 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit738d15a25cb49a9fe191f4f579c57b01
{
public static $prefixLengthsPsr4 = array (
'W' =>
array (
'Workerman\\' => 10,
),
);
public static $prefixDirsPsr4 = array (
'Workerman\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/workerman',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit738d15a25cb49a9fe191f4f579c57b01::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit738d15a25cb49a9fe191f4f579c57b01::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit738d15a25cb49a9fe191f4f579c57b01::$classMap;
}, null, ClassLoader::class);
}
}

49
vendor/composer/installed.json vendored Normal file
View File

@ -0,0 +1,49 @@
{
"packages": [
{
"name": "workerman/workerman",
"version": "v4.1.0",
"version_normalized": "4.1.0.0",
"dist": {
"type": "zip",
"url": "https://mirrors.tencent.com/repository/composer/workerman/workerman/v4.1.0/workerman-workerman-v4.1.0.zip",
"reference": "88ddf517e5c35bee072b2e453c4fcca0c6f1e59a",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"suggest": {
"ext-event": "For better performance. "
},
"time": "2022-08-20T10:16:22+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Workerman\\": "./"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.",
"homepage": "http://www.workerman.net",
"keywords": [
"asynchronous",
"event-loop"
],
"install-path": "../workerman/workerman"
}
],
"dev": true,
"dev-package-names": []
}

32
vendor/composer/installed.php vendored Normal file
View File

@ -0,0 +1,32 @@
<?php return array(
'root' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'ba47abc8928782cef820e087d584a8244911b7f9',
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'ba47abc8928782cef820e087d584a8244911b7f9',
'dev_requirement' => false,
),
'workerman/workerman' => array(
'pretty_version' => 'v4.1.0',
'version' => '4.1.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../workerman/workerman',
'aliases' => array(),
'reference' => '88ddf517e5c35bee072b2e453c4fcca0c6f1e59a',
'dev_requirement' => false,
),
),
);

26
vendor/composer/platform_check.php vendored Normal file
View File

@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70000)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

View File

@ -0,0 +1 @@
6655

262
vendor/workerman/workerman.log vendored Normal file
View File

@ -0,0 +1,262 @@
2022-09-09 09:50:16 pid:3186 Workerman[start.php] start in DEBUG mode
2022-09-09 09:50:17 pid:3186 Workerman[start.php] stopping ...
2022-09-09 09:50:17 pid:3186 Workerman[start.php] has been stopped
2022-09-09 09:59:23 pid:3842 Workerman[start.php] start in DEBUG mode
2022-09-09 09:59:35 pid:3875 Workerman[start.php] start in DEBUG mode
2022-09-09 09:59:57 pid:3875 Workerman[start.php] stopping ...
2022-09-09 09:59:57 pid:3875 Workerman[start.php] has been stopped
2022-09-09 10:00:00 pid:3973 Workerman[start.php] start in DEBUG mode
2022-09-09 10:00:14 pid:3975 TypeError: {closure}(): Argument #1 ($connection) must be of type Workerman\Connection\TcpConnection, Workerman\Connection\UdpConnection given, called in /home/enoch/dns/vendor/workerman/workerman/Worker.php on line 2579 and defined in /home/enoch/dns/start.php:14
Stack trace:
#0 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2579): {closure}()
#1 [internal function]: Workerman\Worker->acceptUdpConnection()
#2 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#7 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#8 /home/enoch/dns/start.php(22): Workerman\Worker::runAll()
#9 {main}
2022-09-09 10:00:14 pid:3973 worker[none:3975] exit with status 64000
2022-09-09 10:00:16 pid:3976 TypeError: {closure}(): Argument #1 ($connection) must be of type Workerman\Connection\TcpConnection, Workerman\Connection\UdpConnection given, called in /home/enoch/dns/vendor/workerman/workerman/Worker.php on line 2579 and defined in /home/enoch/dns/start.php:14
Stack trace:
#0 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2579): {closure}()
#1 [internal function]: Workerman\Worker->acceptUdpConnection()
#2 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#7 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#8 /home/enoch/dns/start.php(22): Workerman\Worker::runAll()
#9 {main}
2022-09-09 10:00:16 pid:3973 worker[none:3976] exit with status 64000
2022-09-09 10:00:18 pid:4156 TypeError: {closure}(): Argument #1 ($connection) must be of type Workerman\Connection\TcpConnection, Workerman\Connection\UdpConnection given, called in /home/enoch/dns/vendor/workerman/workerman/Worker.php on line 2579 and defined in /home/enoch/dns/start.php:14
Stack trace:
#0 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2579): {closure}()
#1 [internal function]: Workerman\Worker->acceptUdpConnection()
#2 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#7 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1720): Workerman\Worker::forkWorkers()
#8 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1660): Workerman\Worker::monitorWorkersForLinux()
#9 /home/enoch/dns/vendor/workerman/workerman/Worker.php(559): Workerman\Worker::monitorWorkers()
#10 /home/enoch/dns/start.php(22): Workerman\Worker::runAll()
#11 {main}
2022-09-09 10:00:18 pid:3973 worker[none:4156] exit with status 64000
2022-09-09 10:00:34 pid:3973 Workerman[start.php] stopping ...
2022-09-09 10:00:34 pid:3973 Workerman[start.php] has been stopped
2022-09-09 10:00:35 pid:4238 Workerman[start.php] start in DEBUG mode
2022-09-09 10:00:39 pid:4239 TypeError: {closure}(): Argument #1 ($connection) must be of type Workerman\Connection\TcpConnection, Workerman\Connection\UdpConnection given, called in /home/enoch/dns/vendor/workerman/workerman/Worker.php on line 2579 and defined in /home/enoch/dns/start.php:14
Stack trace:
#0 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2579): {closure}()
#1 [internal function]: Workerman\Worker->acceptUdpConnection()
#2 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#7 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#8 /home/enoch/dns/start.php(22): Workerman\Worker::runAll()
#9 {main}
2022-09-09 10:00:39 pid:4238 worker[none:4239] exit with status 64000
2022-09-09 10:02:01 pid:4238 Workerman[start.php] stopping ...
2022-09-09 10:02:01 pid:4238 Workerman[start.php] has been stopped
2022-09-09 10:02:03 pid:4496 Workerman[start.php] start in DEBUG mode
2022-09-09 10:02:12 pid:4496 Workerman[start.php] stopping ...
2022-09-09 10:02:12 pid:4496 Workerman[start.php] has been stopped
2022-09-09 10:02:14 pid:4565 Workerman[start.php] start in DEBUG mode
2022-09-09 10:08:35 pid:4565 Workerman[start.php] stopping ...
2022-09-09 10:08:35 pid:4565 Workerman[start.php] has been stopped
2022-09-09 10:08:36 pid:5010 Workerman[start.php] start in DEBUG mode
2022-09-09 10:12:29 pid:5010 Workerman[start.php] stopping ...
2022-09-09 10:12:29 pid:5010 Workerman[start.php] has been stopped
2022-09-09 10:12:29 pid:5329 Workerman[start.php] start in DEBUG mode
2022-09-09 10:14:21 pid:5329 Workerman[start.php] stopping ...
2022-09-09 10:14:21 pid:5329 Workerman[start.php] has been stopped
2022-09-09 10:14:21 pid:5513 Workerman[start.php] start in DEBUG mode
2022-09-09 10:15:38 pid:5513 Workerman[start.php] stopping ...
2022-09-09 10:15:38 pid:5513 Workerman[start.php] has been stopped
2022-09-09 10:15:38 pid:5578 Workerman[start.php] start in DEBUG mode
2022-09-09 10:15:48 pid:5578 Workerman[start.php] stopping ...
2022-09-09 10:15:48 pid:5578 Workerman[start.php] has been stopped
2022-09-09 10:15:49 pid:5627 Workerman[start.php] start in DEBUG mode
2022-09-09 10:21:23 pid:5627 Workerman[start.php] stopping ...
2022-09-09 10:21:23 pid:5627 Workerman[start.php] has been stopped
2022-09-09 10:21:25 pid:6113 Workerman[start.php] start in DEBUG mode
2022-09-09 10:25:13 pid:6113 Workerman[start.php] stopping ...
2022-09-09 10:25:13 pid:6113 Workerman[start.php] has been stopped
2022-09-09 10:25:13 pid:6435 Workerman[start.php] start in DEBUG mode
2022-09-09 10:25:48 pid:6435 Workerman[start.php] stopping ...
2022-09-09 10:25:48 pid:6435 Workerman[start.php] has been stopped
2022-09-09 10:25:49 pid:6526 Workerman[start.php] start in DEBUG mode
2022-09-09 10:31:22 pid:6526 Workerman[start.php] stopping ...
2022-09-09 10:31:22 pid:6526 Workerman[start.php] has been stopped
2022-09-09 10:31:23 pid:7082 Workerman[start.php] start in DEBUG mode
2022-09-09 10:42:09 pid:7082 Workerman[start.php] stopping ...
2022-09-09 10:42:09 pid:7082 Workerman[start.php] has been stopped
2022-09-09 10:42:10 pid:7911 Workerman[start.php] start in DEBUG mode
2022-09-09 10:43:39 pid:7911 Workerman[start.php] stopping ...
2022-09-09 10:43:39 pid:7911 Workerman[start.php] has been stopped
2022-09-09 10:43:40 pid:7976 Workerman[start.php] start in DEBUG mode
2022-09-09 10:44:38 pid:7976 Workerman[start.php] stopping ...
2022-09-09 10:44:38 pid:7976 Workerman[start.php] has been stopped
2022-09-09 10:44:39 pid:8167 Workerman[start.php] start in DEBUG mode
2022-09-09 10:48:22 pid:8167 Workerman[start.php] stopping ...
2022-09-09 10:48:22 pid:8167 Workerman[start.php] has been stopped
2022-09-09 10:48:23 pid:8476 Workerman[start.php] start in DEBUG mode
2022-09-09 10:48:31 pid:8476 Workerman[start.php] stopping ...
2022-09-09 10:48:31 pid:8476 Workerman[start.php] has been stopped
2022-09-09 10:48:32 pid:8531 Workerman[start.php] start in DEBUG mode
2022-09-09 10:49:11 pid:8531 Workerman[start.php] stopping ...
2022-09-09 10:49:11 pid:8531 Workerman[start.php] has been stopped
2022-09-09 10:49:12 pid:8604 Workerman[start.php] start in DEBUG mode
2022-09-09 11:00:02 pid:8604 Workerman[start.php] stopping ...
2022-09-09 11:00:02 pid:8604 Workerman[start.php] has been stopped
2022-09-09 11:00:05 pid:9525 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:02:12 pid:9712 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:04:22 pid:9893 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:04:44 pid:9929 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:07:43 pid:10140 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:07:50 pid:10141 Error: Class "Dns" not found in /home/enoch/dns/vendor/workerman/workerman/Worker.php:2572
Stack trace:
#0 [internal function]: Workerman\Worker->acceptUdpConnection()
#1 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#2 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#7 /home/enoch/dns/start2.php(13): Workerman\Worker::runAll()
#8 {main}
2022-09-09 11:07:50 pid:10140 worker[none:10141] exit with status 64000
2022-09-09 11:08:03 pid:10140 Workerman[start2.php] stopping ...
2022-09-09 11:08:03 pid:10140 Workerman[start2.php] has been stopped
2022-09-09 11:08:03 pid:10349 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:08:06 pid:10350 Error: Class "dns" not found in /home/enoch/dns/vendor/workerman/workerman/Worker.php:2572
Stack trace:
#0 [internal function]: Workerman\Worker->acceptUdpConnection()
#1 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#2 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#7 /home/enoch/dns/start2.php(13): Workerman\Worker::runAll()
#8 {main}
2022-09-09 11:08:06 pid:10349 worker[none:10350] exit with status 64000
2022-09-09 11:08:09 pid:10349 Workerman[start2.php] stopping ...
2022-09-09 11:08:09 pid:10349 Workerman[start2.php] has been stopped
2022-09-09 11:09:22 pid:10436 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:09:26 pid:10437 Error: Class "Dns" not found in /home/enoch/dns/vendor/workerman/workerman/Worker.php:2572
Stack trace:
#0 [internal function]: Workerman\Worker->acceptUdpConnection()
#1 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#2 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#7 /home/enoch/dns/start2.php(12): Workerman\Worker::runAll()
#8 {main}
2022-09-09 11:09:26 pid:10436 worker[none:10437] exit with status 64000
2022-09-09 11:09:55 pid:10436 Workerman[start2.php] stopping ...
2022-09-09 11:09:55 pid:10436 Workerman[start2.php] has been stopped
2022-09-09 11:09:55 pid:10500 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:10:01 pid:10500 Workerman[start2.php] stopping ...
2022-09-09 11:10:01 pid:10500 Workerman[start2.php] has been stopped
2022-09-09 11:10:43 pid:10698 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:11:08 pid:10698 Workerman[start2.php] stopping ...
2022-09-09 11:11:08 pid:10698 Workerman[start2.php] has been stopped
2022-09-09 11:11:09 pid:10777 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:11:34 pid:10777 Workerman[start2.php] stopping ...
2022-09-09 11:11:34 pid:10777 Workerman[start2.php] has been stopped
2022-09-09 11:11:34 pid:10853 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:12:04 pid:10853 Workerman[start2.php] stopping ...
2022-09-09 11:12:04 pid:10853 Workerman[start2.php] has been stopped
2022-09-09 11:12:05 pid:11026 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:12:48 pid:11026 Workerman[start2.php] stopping ...
2022-09-09 11:12:48 pid:11026 Workerman[start2.php] has been stopped
2022-09-09 11:12:49 pid:11095 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:14:18 pid:11095 Workerman[start2.php] stopping ...
2022-09-09 11:14:18 pid:11095 Workerman[start2.php] has been stopped
2022-09-09 11:14:19 pid:11305 Workerman[start2.php] start in DEBUG mode
2022-09-09 11:17:42 pid:11305 Workerman[start2.php] stopping ...
2022-09-09 11:17:42 pid:11305 Workerman[start2.php] has been stopped
2022-09-09 11:17:49 pid:11522 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:02:17 pid:771 Workerman[start.php] start in DEBUG mode
2022-09-11 03:02:19 pid:771 Workerman[start.php] stopping ...
2022-09-11 03:02:19 pid:771 Workerman[start.php] has been stopped
2022-09-11 03:02:22 pid:806 Workerman[start.php] start in DEBUG mode
2022-09-11 03:03:22 pid:806 Workerman[start.php] stopping ...
2022-09-11 03:03:22 pid:806 Workerman[start.php] has been stopped
2022-09-11 03:03:25 pid:934 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:04:08 pid:934 Workerman[start2.php] stopping ...
2022-09-11 03:04:08 pid:934 Workerman[start2.php] has been stopped
2022-09-11 03:04:11 pid:1125 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:05:54 pid:1125 Workerman[start2.php] stopping ...
2022-09-11 03:05:54 pid:1125 Workerman[start2.php] has been stopped
2022-09-11 03:05:55 pid:1199 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:07:26 pid:1199 Workerman[start2.php] stopping ...
2022-09-11 03:07:26 pid:1199 Workerman[start2.php] has been stopped
2022-09-11 03:07:26 pid:1395 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:18:17 pid:1395 Workerman[start2.php] stopping ...
2022-09-11 03:18:17 pid:1395 Workerman[start2.php] has been stopped
2022-09-11 03:18:18 pid:2201 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:18:21 pid:2202 TypeError: explode(): Argument #2 ($string) must be of type string, array given in /home/enoch/dns/start2.php:10
Stack trace:
#0 /home/enoch/dns/start2.php(10): explode()
#1 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2569): {closure}()
#2 [internal function]: Workerman\Worker->acceptUdpConnection()
#3 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#7 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#8 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#9 /home/enoch/dns/start2.php(21): Workerman\Worker::runAll()
#10 {main}
2022-09-11 03:18:21 pid:2201 worker[none:2202] exit with status 64000
2022-09-11 03:18:37 pid:2201 Workerman[start2.php] stopping ...
2022-09-11 03:18:37 pid:2201 Workerman[start2.php] has been stopped
2022-09-11 03:18:38 pid:2259 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:19:36 pid:2259 Workerman[start2.php] stopping ...
2022-09-11 03:19:36 pid:2259 Workerman[start2.php] has been stopped
2022-09-11 03:19:36 pid:2332 Workerman[start2.php] start in DEBUG mode
2022-09-11 03:19:39 pid:2333 Error: Cannot use object of type stdClass as array in /home/enoch/dns/start2.php:11
Stack trace:
#0 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2569): {closure}()
#1 [internal function]: Workerman\Worker->acceptUdpConnection()
#2 /home/enoch/dns/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#3 /home/enoch/dns/vendor/workerman/workerman/Worker.php(2463): Workerman\Events\Event->loop()
#4 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1574): Workerman\Worker->run()
#5 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1416): Workerman\Worker::forkOneWorkerForLinux()
#6 /home/enoch/dns/vendor/workerman/workerman/Worker.php(1390): Workerman\Worker::forkWorkersForLinux()
#7 /home/enoch/dns/vendor/workerman/workerman/Worker.php(557): Workerman\Worker::forkWorkers()
#8 /home/enoch/dns/start2.php(21): Workerman\Worker::runAll()
#9 {main}
2022-09-11 03:19:39 pid:2332 worker[none:2333] exit with status 64000
2022-09-11 03:20:52 pid:2332 Workerman[start2.php] stopping ...
2022-09-11 03:20:52 pid:2332 Workerman[start2.php] has been stopped
2022-09-11 03:20:53 pid:2523 Workerman[start2.php] start in DEBUG mode
2022-09-11 04:11:46 pid:2523 Workerman[start2.php] stopping ...
2022-09-11 04:11:47 pid:2523 Workerman[start2.php] has been stopped
2022-09-11 04:11:48 pid:5867 Workerman[start2.php] start in DEBUG mode
2022-09-11 04:12:26 pid:5867 Workerman[start2.php] stopping ...
2022-09-11 04:12:26 pid:5867 Workerman[start2.php] has been stopped
2022-09-11 04:12:27 pid:6044 Workerman[start2.php] start in DEBUG mode
2022-09-11 04:14:22 pid:6044 Workerman[start2.php] stopping ...
2022-09-11 04:14:22 pid:6044 Workerman[start2.php] has been stopped
2022-09-11 04:14:23 pid:6275 Workerman[start2.php] start in DEBUG mode
2022-09-11 04:15:25 pid:6275 Workerman[start2.php] stopping ...
2022-09-11 04:15:25 pid:6275 Workerman[start2.php] has been stopped
2022-09-11 04:15:25 pid:6384 Workerman[start2.php] start in DEBUG mode
2022-09-11 04:17:11 pid:6384 Workerman[start2.php] stopping ...
2022-09-11 04:17:11 pid:6384 Workerman[start2.php] has been stopped
2022-09-11 04:17:11 pid:6582 Workerman[start2.php] start in DEBUG mode
2022-09-11 04:17:56 pid:6582 Workerman[start2.php] stopping ...
2022-09-11 04:17:56 pid:6582 Workerman[start2.php] has been stopped
2022-09-11 04:17:56 pid:6655 Workerman[start2.php] start in DEBUG mode

View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
open_collective: workerman
patreon: walkor

6
vendor/workerman/workerman/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
logs
.buildpath
.project
.settings
.idea
.DS_Store

View File

@ -0,0 +1,69 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman;
/**
* Autoload.
*/
class Autoloader
{
/**
* Autoload root path.
*
* @var string
*/
protected static $_autoloadRootPath = '';
/**
* Set autoload root path.
*
* @param string $root_path
* @return void
*/
public static function setRootPath($root_path)
{
self::$_autoloadRootPath = $root_path;
}
/**
* Load files by namespace.
*
* @param string $name
* @return boolean
*/
public static function loadByNamespace($name)
{
$class_path = \str_replace('\\', \DIRECTORY_SEPARATOR, $name);
if (\strpos($name, 'Workerman\\') === 0) {
$class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php';
} else {
if (self::$_autoloadRootPath) {
$class_file = self::$_autoloadRootPath . \DIRECTORY_SEPARATOR . $class_path . '.php';
}
if (empty($class_file) || !\is_file($class_file)) {
$class_file = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . "$class_path.php";
}
}
if (\is_file($class_file)) {
require_once($class_file);
if (\class_exists($name, false)) {
return true;
}
}
return false;
}
}
\spl_autoload_register('\Workerman\Autoloader::loadByNamespace');

View File

@ -0,0 +1,376 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Connection;
use Workerman\Events\EventInterface;
use Workerman\Lib\Timer;
use Workerman\Worker;
use \Exception;
/**
* AsyncTcpConnection.
*/
class AsyncTcpConnection extends TcpConnection
{
/**
* Emitted when socket connection is successfully established.
*
* @var callable|null
*/
public $onConnect = null;
/**
* Transport layer protocol.
*
* @var string
*/
public $transport = 'tcp';
/**
* Status.
*
* @var int
*/
protected $_status = self::STATUS_INITIAL;
/**
* Remote host.
*
* @var string
*/
protected $_remoteHost = '';
/**
* Remote port.
*
* @var int
*/
protected $_remotePort = 80;
/**
* Connect start time.
*
* @var float
*/
protected $_connectStartTime = 0;
/**
* Remote URI.
*
* @var string
*/
protected $_remoteURI = '';
/**
* Context option.
*
* @var array
*/
protected $_contextOption = null;
/**
* Reconnect timer.
*
* @var int
*/
protected $_reconnectTimer = null;
/**
* PHP built-in protocols.
*
* @var array
*/
protected static $_builtinTransports = array(
'tcp' => 'tcp',
'udp' => 'udp',
'unix' => 'unix',
'ssl' => 'ssl',
'sslv2' => 'sslv2',
'sslv3' => 'sslv3',
'tls' => 'tls'
);
/**
* Construct.
*
* @param string $remote_address
* @param array $context_option
* @throws Exception
*/
public function __construct($remote_address, array $context_option = array())
{
$address_info = \parse_url($remote_address);
if (!$address_info) {
list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2);
if('unix' === strtolower($scheme)) {
$this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2);
}
if (!$this->_remoteAddress) {
Worker::safeEcho(new \Exception('bad remote_address'));
}
} else {
if (!isset($address_info['port'])) {
$address_info['port'] = 0;
}
if (!isset($address_info['path'])) {
$address_info['path'] = '/';
}
if (!isset($address_info['query'])) {
$address_info['query'] = '';
} else {
$address_info['query'] = '?' . $address_info['query'];
}
$this->_remoteHost = $address_info['host'];
$this->_remotePort = $address_info['port'];
$this->_remoteURI = "{$address_info['path']}{$address_info['query']}";
$scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp';
$this->_remoteAddress = 'unix' === strtolower($scheme)
? substr($remote_address, strpos($remote_address, '/') + 2)
: $this->_remoteHost . ':' . $this->_remotePort;
}
$this->id = $this->_id = self::$_idRecorder++;
if(\PHP_INT_MAX === self::$_idRecorder){
self::$_idRecorder = 0;
}
// Check application layer protocol class.
if (!isset(self::$_builtinTransports[$scheme])) {
$scheme = \ucfirst($scheme);
$this->protocol = '\\Protocols\\' . $scheme;
if (!\class_exists($this->protocol)) {
$this->protocol = "\\Workerman\\Protocols\\$scheme";
if (!\class_exists($this->protocol)) {
throw new Exception("class \\Protocols\\$scheme not exist");
}
}
} else {
$this->transport = self::$_builtinTransports[$scheme];
}
// For statistics.
++self::$statistics['connection_count'];
$this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
$this->maxPackageSize = self::$defaultMaxPackageSize;
$this->_contextOption = $context_option;
static::$connections[$this->_id] = $this;
}
/**
* Do connect.
*
* @return void
*/
public function connect()
{
if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING &&
$this->_status !== self::STATUS_CLOSED) {
return;
}
$this->_status = self::STATUS_CONNECTING;
$this->_connectStartTime = \microtime(true);
if ($this->transport !== 'unix') {
if (!$this->_remotePort) {
$this->_remotePort = $this->transport === 'ssl' ? 443 : 80;
$this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort;
}
// Open socket connection asynchronously.
if ($this->_contextOption) {
$context = \stream_context_create($this->_contextOption);
$this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",
$errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context);
} else {
$this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",
$errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT);
}
} else {
$this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0,
\STREAM_CLIENT_ASYNC_CONNECT);
}
// If failed attempt to emit onError callback.
if (!$this->_socket || !\is_resource($this->_socket)) {
$this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr);
if ($this->_status === self::STATUS_CLOSING) {
$this->destroy();
}
if ($this->_status === self::STATUS_CLOSED) {
$this->onConnect = null;
}
return;
}
// Add socket to global event loop waiting connection is successfully established or faild.
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection'));
// For windows.
if(\DIRECTORY_SEPARATOR === '\\') {
Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection'));
}
}
/**
* Reconnect.
*
* @param int $after
* @return void
*/
public function reconnect($after = 0)
{
$this->_status = self::STATUS_INITIAL;
static::$connections[$this->_id] = $this;
if ($this->_reconnectTimer) {
Timer::del($this->_reconnectTimer);
}
if ($after > 0) {
$this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false);
return;
}
$this->connect();
}
/**
* CancelReconnect.
*/
public function cancelReconnect()
{
if ($this->_reconnectTimer) {
Timer::del($this->_reconnectTimer);
}
}
/**
* Get remote address.
*
* @return string
*/
public function getRemoteHost()
{
return $this->_remoteHost;
}
/**
* Get remote URI.
*
* @return string
*/
public function getRemoteURI()
{
return $this->_remoteURI;
}
/**
* Try to emit onError callback.
*
* @param int $code
* @param string $msg
* @return void
*/
protected function emitError($code, $msg)
{
$this->_status = self::STATUS_CLOSING;
if ($this->onError) {
try {
\call_user_func($this->onError, $this, $code, $msg);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
}
/**
* Check connection is successfully established or faild.
*
* @param resource $socket
* @return void
*/
public function checkConnection()
{
// Remove EV_EXPECT for windows.
if(\DIRECTORY_SEPARATOR === '\\') {
Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT);
}
// Remove write listener.
Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
if ($this->_status !== self::STATUS_CONNECTING) {
return;
}
// Check socket state.
if ($address = \stream_socket_get_name($this->_socket, true)) {
// Nonblocking.
\stream_set_blocking($this->_socket, false);
// Compatible with hhvm
if (\function_exists('stream_set_read_buffer')) {
\stream_set_read_buffer($this->_socket, 0);
}
// Try to open keepalive for tcp and disable Nagle algorithm.
if (\function_exists('socket_import_stream') && $this->transport === 'tcp') {
$raw_socket = \socket_import_stream($this->_socket);
\socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1);
\socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1);
}
// SSL handshake.
if ($this->transport === 'ssl') {
$this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket);
if ($this->_sslHandshakeCompleted === false) {
return;
}
} else {
// There are some data waiting to send.
if ($this->_sendBuffer) {
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
}
}
// Register a listener waiting read event.
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
$this->_status = self::STATUS_ESTABLISHED;
$this->_remoteAddress = $address;
// Try to emit onConnect callback.
if ($this->onConnect) {
try {
\call_user_func($this->onConnect, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
// Try to emit protocol::onConnect
if ($this->protocol && \method_exists($this->protocol, 'onConnect')) {
try {
\call_user_func(array($this->protocol, 'onConnect'), $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
} else {
// Connection failed.
$this->emitError(\WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds');
if ($this->_status === self::STATUS_CLOSING) {
$this->destroy();
}
if ($this->_status === self::STATUS_CLOSED) {
$this->onConnect = null;
}
}
}
}

View File

@ -0,0 +1,203 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Connection;
use Workerman\Events\EventInterface;
use Workerman\Worker;
use \Exception;
/**
* AsyncUdpConnection.
*/
class AsyncUdpConnection extends UdpConnection
{
/**
* Emitted when socket connection is successfully established.
*
* @var callable
*/
public $onConnect = null;
/**
* Emitted when socket connection closed.
*
* @var callable
*/
public $onClose = null;
/**
* Connected or not.
*
* @var bool
*/
protected $connected = false;
/**
* Context option.
*
* @var array
*/
protected $_contextOption = null;
/**
* Construct.
*
* @param string $remote_address
* @throws Exception
*/
public function __construct($remote_address, $context_option = null)
{
// Get the application layer communication protocol and listening address.
list($scheme, $address) = \explode(':', $remote_address, 2);
// Check application layer protocol class.
if ($scheme !== 'udp') {
$scheme = \ucfirst($scheme);
$this->protocol = '\\Protocols\\' . $scheme;
if (!\class_exists($this->protocol)) {
$this->protocol = "\\Workerman\\Protocols\\$scheme";
if (!\class_exists($this->protocol)) {
throw new Exception("class \\Protocols\\$scheme not exist");
}
}
}
$this->_remoteAddress = \substr($address, 2);
$this->_contextOption = $context_option;
}
/**
* For udp package.
*
* @param resource $socket
* @return bool
*/
public function baseRead($socket)
{
$recv_buffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address);
if (false === $recv_buffer || empty($remote_address)) {
return false;
}
if ($this->onMessage) {
if ($this->protocol) {
$parser = $this->protocol;
$recv_buffer = $parser::decode($recv_buffer, $this);
}
++ConnectionInterface::$statistics['total_request'];
try {
\call_user_func($this->onMessage, $this, $recv_buffer);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
return true;
}
/**
* Sends data on the connection.
*
* @param string $send_buffer
* @param bool $raw
* @return void|boolean
*/
public function send($send_buffer, $raw = false)
{
if (false === $raw && $this->protocol) {
$parser = $this->protocol;
$send_buffer = $parser::encode($send_buffer, $this);
if ($send_buffer === '') {
return;
}
}
if ($this->connected === false) {
$this->connect();
}
return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0);
}
/**
* Close connection.
*
* @param mixed $data
* @param bool $raw
*
* @return bool
*/
public function close($data = null, $raw = false)
{
if ($data !== null) {
$this->send($data, $raw);
}
Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
\fclose($this->_socket);
$this->connected = false;
// Try to emit onClose callback.
if ($this->onClose) {
try {
\call_user_func($this->onClose, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
$this->onConnect = $this->onMessage = $this->onClose = null;
return true;
}
/**
* Connect.
*
* @return void
*/
public function connect()
{
if ($this->connected === true) {
return;
}
if ($this->_contextOption) {
$context = \stream_context_create($this->_contextOption);
$this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg,
30, \STREAM_CLIENT_CONNECT, $context);
} else {
$this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg);
}
if (!$this->_socket) {
Worker::safeEcho(new \Exception($errmsg));
return;
}
\stream_set_blocking($this->_socket, false);
if ($this->onMessage) {
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
}
$this->connected = true;
// Try to emit onConnect callback.
if ($this->onConnect) {
try {
\call_user_func($this->onConnect, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Connection;
/**
* ConnectionInterface.
*/
abstract class ConnectionInterface
{
/**
* Statistics for status command.
*
* @var array
*/
public static $statistics = array(
'connection_count' => 0,
'total_request' => 0,
'throw_exception' => 0,
'send_fail' => 0,
);
/**
* Emitted when data is received.
*
* @var callable
*/
public $onMessage = null;
/**
* Emitted when the other end of the socket sends a FIN packet.
*
* @var callable
*/
public $onClose = null;
/**
* Emitted when an error occurs with connection.
*
* @var callable
*/
public $onError = null;
/**
* Sends data on the connection.
*
* @param mixed $send_buffer
* @return void|boolean
*/
abstract public function send($send_buffer);
/**
* Get remote IP.
*
* @return string
*/
abstract public function getRemoteIp();
/**
* Get remote port.
*
* @return int
*/
abstract public function getRemotePort();
/**
* Get remote address.
*
* @return string
*/
abstract public function getRemoteAddress();
/**
* Get local IP.
*
* @return string
*/
abstract public function getLocalIp();
/**
* Get local port.
*
* @return int
*/
abstract public function getLocalPort();
/**
* Get local address.
*
* @return string
*/
abstract public function getLocalAddress();
/**
* Is ipv4.
*
* @return bool
*/
abstract public function isIPv4();
/**
* Is ipv6.
*
* @return bool
*/
abstract public function isIPv6();
/**
* Close connection.
*
* @param string|null $data
* @return void
*/
abstract public function close($data = null);
}

View File

@ -0,0 +1,974 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Connection;
use Workerman\Events\EventInterface;
use Workerman\Worker;
use \Exception;
/**
* TcpConnection.
*/
class TcpConnection extends ConnectionInterface
{
/**
* Read buffer size.
*
* @var int
*/
const READ_BUFFER_SIZE = 65535;
/**
* Status initial.
*
* @var int
*/
const STATUS_INITIAL = 0;
/**
* Status connecting.
*
* @var int
*/
const STATUS_CONNECTING = 1;
/**
* Status connection established.
*
* @var int
*/
const STATUS_ESTABLISHED = 2;
/**
* Status closing.
*
* @var int
*/
const STATUS_CLOSING = 4;
/**
* Status closed.
*
* @var int
*/
const STATUS_CLOSED = 8;
/**
* Emitted when data is received.
*
* @var callable
*/
public $onMessage = null;
/**
* Emitted when the other end of the socket sends a FIN packet.
*
* @var callable
*/
public $onClose = null;
/**
* Emitted when an error occurs with connection.
*
* @var callable
*/
public $onError = null;
/**
* Emitted when the send buffer becomes full.
*
* @var callable
*/
public $onBufferFull = null;
/**
* Emitted when the send buffer becomes empty.
*
* @var callable
*/
public $onBufferDrain = null;
/**
* Application layer protocol.
* The format is like this Workerman\\Protocols\\Http.
*
* @var \Workerman\Protocols\ProtocolInterface
*/
public $protocol = null;
/**
* Transport (tcp/udp/unix/ssl).
*
* @var string
*/
public $transport = 'tcp';
/**
* Which worker belong to.
*
* @var Worker
*/
public $worker = null;
/**
* Bytes read.
*
* @var int
*/
public $bytesRead = 0;
/**
* Bytes written.
*
* @var int
*/
public $bytesWritten = 0;
/**
* Connection->id.
*
* @var int
*/
public $id = 0;
/**
* A copy of $worker->id which used to clean up the connection in worker->connections
*
* @var int
*/
protected $_id = 0;
/**
* Sets the maximum send buffer size for the current connection.
* OnBufferFull callback will be emited When the send buffer is full.
*
* @var int
*/
public $maxSendBufferSize = 1048576;
/**
* Default send buffer size.
*
* @var int
*/
public static $defaultMaxSendBufferSize = 1048576;
/**
* Sets the maximum acceptable packet size for the current connection.
*
* @var int
*/
public $maxPackageSize = 1048576;
/**
* Default maximum acceptable packet size.
*
* @var int
*/
public static $defaultMaxPackageSize = 10485760;
/**
* Id recorder.
*
* @var int
*/
protected static $_idRecorder = 1;
/**
* Socket
*
* @var resource
*/
protected $_socket = null;
/**
* Send buffer.
*
* @var string
*/
protected $_sendBuffer = '';
/**
* Receive buffer.
*
* @var string
*/
protected $_recvBuffer = '';
/**
* Current package length.
*
* @var int
*/
protected $_currentPackageLength = 0;
/**
* Connection status.
*
* @var int
*/
protected $_status = self::STATUS_ESTABLISHED;
/**
* Remote address.
*
* @var string
*/
protected $_remoteAddress = '';
/**
* Is paused.
*
* @var bool
*/
protected $_isPaused = false;
/**
* SSL handshake completed or not.
*
* @var bool
*/
protected $_sslHandshakeCompleted = false;
/**
* All connection instances.
*
* @var array
*/
public static $connections = array();
/**
* Status to string.
*
* @var array
*/
public static $_statusToString = array(
self::STATUS_INITIAL => 'INITIAL',
self::STATUS_CONNECTING => 'CONNECTING',
self::STATUS_ESTABLISHED => 'ESTABLISHED',
self::STATUS_CLOSING => 'CLOSING',
self::STATUS_CLOSED => 'CLOSED',
);
/**
* Construct.
*
* @param resource $socket
* @param string $remote_address
*/
public function __construct($socket, $remote_address = '')
{
++self::$statistics['connection_count'];
$this->id = $this->_id = self::$_idRecorder++;
if(self::$_idRecorder === \PHP_INT_MAX){
self::$_idRecorder = 0;
}
$this->_socket = $socket;
\stream_set_blocking($this->_socket, 0);
// Compatible with hhvm
if (\function_exists('stream_set_read_buffer')) {
\stream_set_read_buffer($this->_socket, 0);
}
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
$this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
$this->maxPackageSize = self::$defaultMaxPackageSize;
$this->_remoteAddress = $remote_address;
static::$connections[$this->id] = $this;
}
/**
* Get status.
*
* @param bool $raw_output
*
* @return int|string
*/
public function getStatus($raw_output = true)
{
if ($raw_output) {
return $this->_status;
}
return self::$_statusToString[$this->_status];
}
/**
* Sends data on the connection.
*
* @param mixed $send_buffer
* @param bool $raw
* @return bool|null
*/
public function send($send_buffer, $raw = false)
{
if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) {
return false;
}
// Try to call protocol::encode($send_buffer) before sending.
if (false === $raw && $this->protocol !== null) {
$parser = $this->protocol;
$send_buffer = $parser::encode($send_buffer, $this);
if ($send_buffer === '') {
return;
}
}
if ($this->_status !== self::STATUS_ESTABLISHED ||
($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true)
) {
if ($this->_sendBuffer && $this->bufferIsFull()) {
++self::$statistics['send_fail'];
return false;
}
$this->_sendBuffer .= $send_buffer;
$this->checkBufferWillFull();
return;
}
// Attempt to send data directly.
if ($this->_sendBuffer === '') {
if ($this->transport === 'ssl') {
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
$this->_sendBuffer = $send_buffer;
$this->checkBufferWillFull();
return;
}
$len = 0;
try {
$len = @\fwrite($this->_socket, $send_buffer);
} catch (\Exception $e) {
Worker::log($e);
} catch (\Error $e) {
Worker::log($e);
}
// send successful.
if ($len === \strlen($send_buffer)) {
$this->bytesWritten += $len;
return true;
}
// Send only part of the data.
if ($len > 0) {
$this->_sendBuffer = \substr($send_buffer, $len);
$this->bytesWritten += $len;
} else {
// Connection closed?
if (!\is_resource($this->_socket) || \feof($this->_socket)) {
++self::$statistics['send_fail'];
if ($this->onError) {
try {
\call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed');
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
$this->destroy();
return false;
}
$this->_sendBuffer = $send_buffer;
}
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
// Check if the send buffer will be full.
$this->checkBufferWillFull();
return;
}
if ($this->bufferIsFull()) {
++self::$statistics['send_fail'];
return false;
}
$this->_sendBuffer .= $send_buffer;
// Check if the send buffer is full.
$this->checkBufferWillFull();
}
/**
* Get remote IP.
*
* @return string
*/
public function getRemoteIp()
{
$pos = \strrpos($this->_remoteAddress, ':');
if ($pos) {
return (string) \substr($this->_remoteAddress, 0, $pos);
}
return '';
}
/**
* Get remote port.
*
* @return int
*/
public function getRemotePort()
{
if ($this->_remoteAddress) {
return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1);
}
return 0;
}
/**
* Get remote address.
*
* @return string
*/
public function getRemoteAddress()
{
return $this->_remoteAddress;
}
/**
* Get local IP.
*
* @return string
*/
public function getLocalIp()
{
$address = $this->getLocalAddress();
$pos = \strrpos($address, ':');
if (!$pos) {
return '';
}
return \substr($address, 0, $pos);
}
/**
* Get local port.
*
* @return int
*/
public function getLocalPort()
{
$address = $this->getLocalAddress();
$pos = \strrpos($address, ':');
if (!$pos) {
return 0;
}
return (int)\substr(\strrchr($address, ':'), 1);
}
/**
* Get local address.
*
* @return string
*/
public function getLocalAddress()
{
if (!\is_resource($this->_socket)) {
return '';
}
return (string)@\stream_socket_get_name($this->_socket, false);
}
/**
* Get send buffer queue size.
*
* @return integer
*/
public function getSendBufferQueueSize()
{
return \strlen($this->_sendBuffer);
}
/**
* Get recv buffer queue size.
*
* @return integer
*/
public function getRecvBufferQueueSize()
{
return \strlen($this->_recvBuffer);
}
/**
* Is ipv4.
*
* return bool.
*/
public function isIpV4()
{
if ($this->transport === 'unix') {
return false;
}
return \strpos($this->getRemoteIp(), ':') === false;
}
/**
* Is ipv6.
*
* return bool.
*/
public function isIpV6()
{
if ($this->transport === 'unix') {
return false;
}
return \strpos($this->getRemoteIp(), ':') !== false;
}
/**
* Pauses the reading of data. That is onMessage will not be emitted. Useful to throttle back an upload.
*
* @return void
*/
public function pauseRecv()
{
Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
$this->_isPaused = true;
}
/**
* Resumes reading after a call to pauseRecv.
*
* @return void
*/
public function resumeRecv()
{
if ($this->_isPaused === true) {
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
$this->_isPaused = false;
$this->baseRead($this->_socket, false);
}
}
/**
* Base read handler.
*
* @param resource $socket
* @param bool $check_eof
* @return void
*/
public function baseRead($socket, $check_eof = true)
{
// SSL handshake.
if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) {
if ($this->doSslHandshake($socket)) {
$this->_sslHandshakeCompleted = true;
if ($this->_sendBuffer) {
Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
}
} else {
return;
}
}
$buffer = '';
try {
$buffer = @\fread($socket, self::READ_BUFFER_SIZE);
} catch (\Exception $e) {} catch (\Error $e) {}
// Check connection closed.
if ($buffer === '' || $buffer === false) {
if ($check_eof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) {
$this->destroy();
return;
}
} else {
$this->bytesRead += \strlen($buffer);
$this->_recvBuffer .= $buffer;
}
// If the application layer protocol has been set up.
if ($this->protocol !== null) {
$parser = $this->protocol;
while ($this->_recvBuffer !== '' && !$this->_isPaused) {
// The current packet length is known.
if ($this->_currentPackageLength) {
// Data is not enough for a package.
if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) {
break;
}
} else {
// Get current package length.
try {
$this->_currentPackageLength = $parser::input($this->_recvBuffer, $this);
} catch (\Exception $e) {} catch (\Error $e) {}
// The packet length is unknown.
if ($this->_currentPackageLength === 0) {
break;
} elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) {
// Data is not enough for a package.
if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) {
break;
}
} // Wrong package.
else {
Worker::safeEcho('Error package. package_length=' . \var_export($this->_currentPackageLength, true));
$this->destroy();
return;
}
}
// The data is enough for a packet.
++self::$statistics['total_request'];
// The current packet length is equal to the length of the buffer.
if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) {
$one_request_buffer = $this->_recvBuffer;
$this->_recvBuffer = '';
} else {
// Get a full package from the buffer.
$one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength);
// Remove the current package from the receive buffer.
$this->_recvBuffer = \substr($this->_recvBuffer, $this->_currentPackageLength);
}
// Reset the current packet length to 0.
$this->_currentPackageLength = 0;
if (!$this->onMessage) {
continue;
}
try {
// Decode request buffer before Emitting onMessage callback.
\call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this));
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
return;
}
if ($this->_recvBuffer === '' || $this->_isPaused) {
return;
}
// Applications protocol is not set.
++self::$statistics['total_request'];
if (!$this->onMessage) {
$this->_recvBuffer = '';
return;
}
try {
\call_user_func($this->onMessage, $this, $this->_recvBuffer);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
// Clean receive buffer.
$this->_recvBuffer = '';
}
/**
* Base write handler.
*
* @return void|bool
*/
public function baseWrite()
{
\set_error_handler(function(){});
if ($this->transport === 'ssl') {
$len = @\fwrite($this->_socket, $this->_sendBuffer, 8192);
} else {
$len = @\fwrite($this->_socket, $this->_sendBuffer);
}
\restore_error_handler();
if ($len === \strlen($this->_sendBuffer)) {
$this->bytesWritten += $len;
Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
$this->_sendBuffer = '';
// Try to emit onBufferDrain callback when the send buffer becomes empty.
if ($this->onBufferDrain) {
try {
\call_user_func($this->onBufferDrain, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
if ($this->_status === self::STATUS_CLOSING) {
$this->destroy();
}
return true;
}
if ($len > 0) {
$this->bytesWritten += $len;
$this->_sendBuffer = \substr($this->_sendBuffer, $len);
} else {
++self::$statistics['send_fail'];
$this->destroy();
}
}
/**
* SSL handshake.
*
* @param resource $socket
* @return bool
*/
public function doSslHandshake($socket){
if (\feof($socket)) {
$this->destroy();
return false;
}
$async = $this instanceof AsyncTcpConnection;
/**
* We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack.
* You can enable ssl3 by the codes below.
*/
/*if($async){
$type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
}else{
$type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER;
}*/
if($async){
$type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
}else{
$type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER;
}
// Hidden error.
\set_error_handler(function($errno, $errstr, $file){
if (!Worker::$daemonize) {
Worker::safeEcho("SSL handshake error: $errstr \n");
}
});
$ret = \stream_socket_enable_crypto($socket, true, $type);
\restore_error_handler();
// Negotiation has failed.
if (false === $ret) {
$this->destroy();
return false;
} elseif (0 === $ret) {
// There isn't enough data and should try again.
return 0;
}
if (isset($this->onSslHandshake)) {
try {
\call_user_func($this->onSslHandshake, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
return true;
}
/**
* This method pulls all the data out of a readable stream, and writes it to the supplied destination.
*
* @param self $dest
* @return void
*/
public function pipe(self $dest)
{
$source = $this;
$this->onMessage = function ($source, $data) use ($dest) {
$dest->send($data);
};
$this->onClose = function ($source) use ($dest) {
$dest->close();
};
$dest->onBufferFull = function ($dest) use ($source) {
$source->pauseRecv();
};
$dest->onBufferDrain = function ($dest) use ($source) {
$source->resumeRecv();
};
}
/**
* Remove $length of data from receive buffer.
*
* @param int $length
* @return void
*/
public function consumeRecvBuffer($length)
{
$this->_recvBuffer = \substr($this->_recvBuffer, $length);
}
/**
* Close connection.
*
* @param mixed $data
* @param bool $raw
* @return void
*/
public function close($data = null, $raw = false)
{
if($this->_status === self::STATUS_CONNECTING){
$this->destroy();
return;
}
if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) {
return;
}
if ($data !== null) {
$this->send($data, $raw);
}
$this->_status = self::STATUS_CLOSING;
if ($this->_sendBuffer === '') {
$this->destroy();
} else {
$this->pauseRecv();
}
}
/**
* Get the real socket.
*
* @return resource
*/
public function getSocket()
{
return $this->_socket;
}
/**
* Check whether the send buffer will be full.
*
* @return void
*/
protected function checkBufferWillFull()
{
if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) {
if ($this->onBufferFull) {
try {
\call_user_func($this->onBufferFull, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
}
}
/**
* Whether send buffer is full.
*
* @return bool
*/
protected function bufferIsFull()
{
// Buffer has been marked as full but still has data to send then the packet is discarded.
if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) {
if ($this->onError) {
try {
\call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
return true;
}
return false;
}
/**
* Whether send buffer is Empty.
*
* @return bool
*/
public function bufferIsEmpty()
{
return empty($this->_sendBuffer);
}
/**
* Destroy connection.
*
* @return void
*/
public function destroy()
{
// Avoid repeated calls.
if ($this->_status === self::STATUS_CLOSED) {
return;
}
// Remove event listener.
Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
// Close socket.
try {
@\fclose($this->_socket);
} catch (\Exception $e) {} catch (\Error $e) {}
$this->_status = self::STATUS_CLOSED;
// Try to emit onClose callback.
if ($this->onClose) {
try {
\call_user_func($this->onClose, $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
// Try to emit protocol::onClose
if ($this->protocol && \method_exists($this->protocol, 'onClose')) {
try {
\call_user_func(array($this->protocol, 'onClose'), $this);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
$this->_sendBuffer = $this->_recvBuffer = '';
$this->_currentPackageLength = 0;
$this->_isPaused = $this->_sslHandshakeCompleted = false;
if ($this->_status === self::STATUS_CLOSED) {
// Cleaning up the callback to avoid memory leaks.
$this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null;
// Remove from worker->connections.
if ($this->worker) {
unset($this->worker->connections[$this->_id]);
}
unset(static::$connections[$this->_id]);
}
}
/**
* Destruct.
*
* @return void
*/
public function __destruct()
{
static $mod;
self::$statistics['connection_count']--;
if (Worker::getGracefulStop()) {
if (!isset($mod)) {
$mod = \ceil((self::$statistics['connection_count'] + 1) / 3);
}
if (0 === self::$statistics['connection_count'] % $mod) {
Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)');
}
if(0 === self::$statistics['connection_count']) {
Worker::stopAll();
}
}
}
}

View File

@ -0,0 +1,208 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Connection;
/**
* UdpConnection.
*/
class UdpConnection extends ConnectionInterface
{
/**
* Application layer protocol.
* The format is like this Workerman\\Protocols\\Http.
*
* @var \Workerman\Protocols\ProtocolInterface
*/
public $protocol = null;
/**
* Transport layer protocol.
*
* @var string
*/
public $transport = 'udp';
/**
* Udp socket.
*
* @var resource
*/
protected $_socket = null;
/**
* Remote address.
*
* @var string
*/
protected $_remoteAddress = '';
/**
* Construct.
*
* @param resource $socket
* @param string $remote_address
*/
public function __construct($socket, $remote_address)
{
$this->_socket = $socket;
$this->_remoteAddress = $remote_address;
}
/**
* Sends data on the connection.
*
* @param string $send_buffer
* @param bool $raw
* @return void|boolean
*/
public function send($send_buffer, $raw = false)
{
if (false === $raw && $this->protocol) {
$parser = $this->protocol;
$send_buffer = $parser::encode($send_buffer, $this);
if ($send_buffer === '') {
return;
}
}
return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->_remoteAddress);
}
/**
* Get remote IP.
*
* @return string
*/
public function getRemoteIp()
{
$pos = \strrpos($this->_remoteAddress, ':');
if ($pos) {
return \trim(\substr($this->_remoteAddress, 0, $pos), '[]');
}
return '';
}
/**
* Get remote port.
*
* @return int
*/
public function getRemotePort()
{
if ($this->_remoteAddress) {
return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1);
}
return 0;
}
/**
* Get remote address.
*
* @return string
*/
public function getRemoteAddress()
{
return $this->_remoteAddress;
}
/**
* Get local IP.
*
* @return string
*/
public function getLocalIp()
{
$address = $this->getLocalAddress();
$pos = \strrpos($address, ':');
if (!$pos) {
return '';
}
return \substr($address, 0, $pos);
}
/**
* Get local port.
*
* @return int
*/
public function getLocalPort()
{
$address = $this->getLocalAddress();
$pos = \strrpos($address, ':');
if (!$pos) {
return 0;
}
return (int)\substr(\strrchr($address, ':'), 1);
}
/**
* Get local address.
*
* @return string
*/
public function getLocalAddress()
{
return (string)@\stream_socket_get_name($this->_socket, false);
}
/**
* Is ipv4.
*
* @return bool.
*/
public function isIpV4()
{
if ($this->transport === 'unix') {
return false;
}
return \strpos($this->getRemoteIp(), ':') === false;
}
/**
* Is ipv6.
*
* @return bool.
*/
public function isIpV6()
{
if ($this->transport === 'unix') {
return false;
}
return \strpos($this->getRemoteIp(), ':') !== false;
}
/**
* Close connection.
*
* @param mixed $data
* @param bool $raw
* @return bool
*/
public function close($data = null, $raw = false)
{
if ($data !== null) {
$this->send($data, $raw);
}
return true;
}
/**
* Get the real socket.
*
* @return resource
*/
public function getSocket()
{
return $this->_socket;
}
}

191
vendor/workerman/workerman/Events/Ev.php vendored Normal file
View File

@ -0,0 +1,191 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author 有个鬼<42765633@qq.com>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
use Workerman\Worker;
use \EvWatcher;
/**
* ev eventloop
*/
class Ev implements EventInterface
{
/**
* All listeners for read/write event.
*
* @var array
*/
protected $_allEvents = array();
/**
* Event listeners of signal.
*
* @var array
*/
protected $_eventSignal = array();
/**
* All timer event listeners.
* [func, args, event, flag, time_interval]
*
* @var array
*/
protected $_eventTimer = array();
/**
* Timer id.
*
* @var int
*/
protected static $_timerId = 1;
/**
* Add a timer.
* {@inheritdoc}
*/
public function add($fd, $flag, $func, $args = null)
{
$callback = function ($event, $socket) use ($fd, $func) {
try {
\call_user_func($func, $fd);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
};
switch ($flag) {
case self::EV_SIGNAL:
$event = new \EvSignal($fd, $callback);
$this->_eventSignal[$fd] = $event;
return true;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
$repeat = $flag === self::EV_TIMER_ONCE ? 0 : $fd;
$param = array($func, (array)$args, $flag, $fd, self::$_timerId);
$event = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param);
$this->_eventTimer[self::$_timerId] = $event;
return self::$_timerId++;
default :
$fd_key = (int)$fd;
$real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE;
$event = new \EvIo($fd, $real_flag, $callback);
$this->_allEvents[$fd_key][$flag] = $event;
return true;
}
}
/**
* Remove a timer.
* {@inheritdoc}
*/
public function del($fd, $flag)
{
switch ($flag) {
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][$flag])) {
$this->_allEvents[$fd_key][$flag]->stop();
unset($this->_allEvents[$fd_key][$flag]);
}
if (empty($this->_allEvents[$fd_key])) {
unset($this->_allEvents[$fd_key]);
}
break;
case self::EV_SIGNAL:
$fd_key = (int)$fd;
if (isset($this->_eventSignal[$fd_key])) {
$this->_eventSignal[$fd_key]->stop();
unset($this->_eventSignal[$fd_key]);
}
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
if (isset($this->_eventTimer[$fd])) {
$this->_eventTimer[$fd]->stop();
unset($this->_eventTimer[$fd]);
}
break;
}
return true;
}
/**
* Timer callback.
*
* @param EvWatcher $event
*/
public function timerCallback(EvWatcher $event)
{
$param = $event->data;
$timer_id = $param[4];
if ($param[2] === self::EV_TIMER_ONCE) {
$this->_eventTimer[$timer_id]->stop();
unset($this->_eventTimer[$timer_id]);
}
try {
\call_user_func_array($param[0], $param[1]);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
/**
* Remove all timers.
*
* @return void
*/
public function clearAllTimer()
{
foreach ($this->_eventTimer as $event) {
$event->stop();
}
$this->_eventTimer = array();
}
/**
* Main loop.
*
* @see EventInterface::loop()
*/
public function loop()
{
\Ev::run();
}
/**
* Destroy loop.
*
* @return void
*/
public function destroy()
{
foreach ($this->_allEvents as $event) {
$event->stop();
}
}
/**
* Get timer count.
*
* @return integer
*/
public function getTimerCount()
{
return \count($this->_eventTimer);
}
}

View File

@ -0,0 +1,215 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author 有个鬼<42765633@qq.com>
* @copyright 有个鬼<42765633@qq.com>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
use Workerman\Worker;
/**
* libevent eventloop
*/
class Event implements EventInterface
{
/**
* Event base.
* @var object
*/
protected $_eventBase = null;
/**
* All listeners for read/write event.
* @var array
*/
protected $_allEvents = array();
/**
* Event listeners of signal.
* @var array
*/
protected $_eventSignal = array();
/**
* All timer event listeners.
* [func, args, event, flag, time_interval]
* @var array
*/
protected $_eventTimer = array();
/**
* Timer id.
* @var int
*/
protected static $_timerId = 1;
/**
* construct
* @return void
*/
public function __construct()
{
if (\class_exists('\\\\EventBase', false)) {
$class_name = '\\\\EventBase';
} else {
$class_name = '\EventBase';
}
$this->_eventBase = new $class_name();
}
/**
* @see EventInterface::add()
*/
public function add($fd, $flag, $func, $args=array())
{
if (\class_exists('\\\\Event', false)) {
$class_name = '\\\\Event';
} else {
$class_name = '\Event';
}
switch ($flag) {
case self::EV_SIGNAL:
$fd_key = (int)$fd;
$event = $class_name::signal($this->_eventBase, $fd, $func);
if (!$event||!$event->add()) {
return false;
}
$this->_eventSignal[$fd_key] = $event;
return true;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
$param = array($func, (array)$args, $flag, $fd, self::$_timerId);
$event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT|$class_name::PERSIST, array($this, "timerCallback"), $param);
if (!$event||!$event->addTimer($fd)) {
return false;
}
$this->_eventTimer[self::$_timerId] = $event;
return self::$_timerId++;
default :
$fd_key = (int)$fd;
$real_flag = $flag === self::EV_READ ? $class_name::READ | $class_name::PERSIST : $class_name::WRITE | $class_name::PERSIST;
$event = new $class_name($this->_eventBase, $fd, $real_flag, $func, $fd);
if (!$event||!$event->add()) {
return false;
}
$this->_allEvents[$fd_key][$flag] = $event;
return true;
}
}
/**
* @see Events\EventInterface::del()
*/
public function del($fd, $flag)
{
switch ($flag) {
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][$flag])) {
$this->_allEvents[$fd_key][$flag]->del();
unset($this->_allEvents[$fd_key][$flag]);
}
if (empty($this->_allEvents[$fd_key])) {
unset($this->_allEvents[$fd_key]);
}
break;
case self::EV_SIGNAL:
$fd_key = (int)$fd;
if (isset($this->_eventSignal[$fd_key])) {
$this->_eventSignal[$fd_key]->del();
unset($this->_eventSignal[$fd_key]);
}
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
if (isset($this->_eventTimer[$fd])) {
$this->_eventTimer[$fd]->del();
unset($this->_eventTimer[$fd]);
}
break;
}
return true;
}
/**
* Timer callback.
* @param int|null $fd
* @param int $what
* @param int $timer_id
*/
public function timerCallback($fd, $what, $param)
{
$timer_id = $param[4];
if ($param[2] === self::EV_TIMER_ONCE) {
$this->_eventTimer[$timer_id]->del();
unset($this->_eventTimer[$timer_id]);
}
try {
\call_user_func_array($param[0], $param[1]);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
/**
* @see Events\EventInterface::clearAllTimer()
* @return void
*/
public function clearAllTimer()
{
foreach ($this->_eventTimer as $event) {
$event->del();
}
$this->_eventTimer = array();
}
/**
* @see EventInterface::loop()
*/
public function loop()
{
$this->_eventBase->loop();
}
/**
* Destroy loop.
*
* @return void
*/
public function destroy()
{
$this->_eventBase->exit();
}
/**
* Get timer count.
*
* @return integer
*/
public function getTimerCount()
{
return \count($this->_eventTimer);
}
}

View File

@ -0,0 +1,107 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
interface EventInterface
{
/**
* Read event.
*
* @var int
*/
const EV_READ = 1;
/**
* Write event.
*
* @var int
*/
const EV_WRITE = 2;
/**
* Except event
*
* @var int
*/
const EV_EXCEPT = 3;
/**
* Signal event.
*
* @var int
*/
const EV_SIGNAL = 4;
/**
* Timer event.
*
* @var int
*/
const EV_TIMER = 8;
/**
* Timer once event.
*
* @var int
*/
const EV_TIMER_ONCE = 16;
/**
* Add event listener to event loop.
*
* @param mixed $fd
* @param int $flag
* @param callable $func
* @param array $args
* @return bool
*/
public function add($fd, $flag, $func, $args = array());
/**
* Remove event listener from event loop.
*
* @param mixed $fd
* @param int $flag
* @return bool
*/
public function del($fd, $flag);
/**
* Remove all timers.
*
* @return void
*/
public function clearAllTimer();
/**
* Main loop.
*
* @return void
*/
public function loop();
/**
* Destroy loop.
*
* @return mixed
*/
public function destroy();
/**
* Get Timer count.
*
* @return mixed
*/
public function getTimerCount();
}

View File

@ -0,0 +1,225 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
use Workerman\Worker;
/**
* libevent eventloop
*/
class Libevent implements EventInterface
{
/**
* Event base.
*
* @var resource
*/
protected $_eventBase = null;
/**
* All listeners for read/write event.
*
* @var array
*/
protected $_allEvents = array();
/**
* Event listeners of signal.
*
* @var array
*/
protected $_eventSignal = array();
/**
* All timer event listeners.
* [func, args, event, flag, time_interval]
*
* @var array
*/
protected $_eventTimer = array();
/**
* construct
*/
public function __construct()
{
$this->_eventBase = \event_base_new();
}
/**
* {@inheritdoc}
*/
public function add($fd, $flag, $func, $args = array())
{
switch ($flag) {
case self::EV_SIGNAL:
$fd_key = (int)$fd;
$real_flag = \EV_SIGNAL | \EV_PERSIST;
$this->_eventSignal[$fd_key] = \event_new();
if (!\event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) {
return false;
}
if (!\event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) {
return false;
}
if (!\event_add($this->_eventSignal[$fd_key])) {
return false;
}
return true;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
$event = \event_new();
$timer_id = (int)$event;
if (!\event_set($event, 0, \EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) {
return false;
}
if (!\event_base_set($event, $this->_eventBase)) {
return false;
}
$time_interval = $fd * 1000000;
if (!\event_add($event, $time_interval)) {
return false;
}
$this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval);
return $timer_id;
default :
$fd_key = (int)$fd;
$real_flag = $flag === self::EV_READ ? \EV_READ | \EV_PERSIST : \EV_WRITE | \EV_PERSIST;
$event = \event_new();
if (!\event_set($event, $fd, $real_flag, $func, null)) {
return false;
}
if (!\event_base_set($event, $this->_eventBase)) {
return false;
}
if (!\event_add($event)) {
return false;
}
$this->_allEvents[$fd_key][$flag] = $event;
return true;
}
}
/**
* {@inheritdoc}
*/
public function del($fd, $flag)
{
switch ($flag) {
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][$flag])) {
\event_del($this->_allEvents[$fd_key][$flag]);
unset($this->_allEvents[$fd_key][$flag]);
}
if (empty($this->_allEvents[$fd_key])) {
unset($this->_allEvents[$fd_key]);
}
break;
case self::EV_SIGNAL:
$fd_key = (int)$fd;
if (isset($this->_eventSignal[$fd_key])) {
\event_del($this->_eventSignal[$fd_key]);
unset($this->_eventSignal[$fd_key]);
}
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
// 这里 fd 为timerid
if (isset($this->_eventTimer[$fd])) {
\event_del($this->_eventTimer[$fd][2]);
unset($this->_eventTimer[$fd]);
}
break;
}
return true;
}
/**
* Timer callback.
*
* @param mixed $_null1
* @param int $_null2
* @param mixed $timer_id
*/
protected function timerCallback($_null1, $_null2, $timer_id)
{
if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) {
\event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]);
}
try {
\call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) {
$this->del($timer_id, self::EV_TIMER_ONCE);
}
}
/**
* {@inheritdoc}
*/
public function clearAllTimer()
{
foreach ($this->_eventTimer as $task_data) {
\event_del($task_data[2]);
}
$this->_eventTimer = array();
}
/**
* {@inheritdoc}
*/
public function loop()
{
\event_base_loop($this->_eventBase);
}
/**
* Destroy loop.
*
* @return void
*/
public function destroy()
{
foreach ($this->_eventSignal as $event) {
\event_del($event);
}
}
/**
* Get timer count.
*
* @return integer
*/
public function getTimerCount()
{
return \count($this->_eventTimer);
}
}

View File

@ -0,0 +1,264 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events\React;
use Workerman\Events\EventInterface;
use React\EventLoop\TimerInterface;
use React\EventLoop\LoopInterface;
/**
* Class StreamSelectLoop
* @package Workerman\Events\React
*/
class Base implements LoopInterface
{
/**
* @var array
*/
protected $_timerIdMap = array();
/**
* @var int
*/
protected $_timerIdIndex = 0;
/**
* @var array
*/
protected $_signalHandlerMap = array();
/**
* @var LoopInterface
*/
protected $_eventLoop = null;
/**
* Base constructor.
*/
public function __construct()
{
$this->_eventLoop = new \React\EventLoop\StreamSelectLoop();
}
/**
* Add event listener to event loop.
*
* @param int $fd
* @param int $flag
* @param callable $func
* @param array $args
* @return bool
*/
public function add($fd, $flag, $func, array $args = array())
{
$args = (array)$args;
switch ($flag) {
case EventInterface::EV_READ:
return $this->addReadStream($fd, $func);
case EventInterface::EV_WRITE:
return $this->addWriteStream($fd, $func);
case EventInterface::EV_SIGNAL:
if (isset($this->_signalHandlerMap[$fd])) {
$this->removeSignal($fd, $this->_signalHandlerMap[$fd]);
}
$this->_signalHandlerMap[$fd] = $func;
return $this->addSignal($fd, $func);
case EventInterface::EV_TIMER:
$timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) {
\call_user_func_array($func, $args);
});
$this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj;
return $this->_timerIdIndex;
case EventInterface::EV_TIMER_ONCE:
$index = ++$this->_timerIdIndex;
$timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) {
$this->del($index,EventInterface::EV_TIMER_ONCE);
\call_user_func_array($func, $args);
});
$this->_timerIdMap[$index] = $timer_obj;
return $this->_timerIdIndex;
}
return false;
}
/**
* Remove event listener from event loop.
*
* @param mixed $fd
* @param int $flag
* @return bool
*/
public function del($fd, $flag)
{
switch ($flag) {
case EventInterface::EV_READ:
return $this->removeReadStream($fd);
case EventInterface::EV_WRITE:
return $this->removeWriteStream($fd);
case EventInterface::EV_SIGNAL:
if (!isset($this->_eventLoop[$fd])) {
return false;
}
$func = $this->_eventLoop[$fd];
unset($this->_eventLoop[$fd]);
return $this->removeSignal($fd, $func);
case EventInterface::EV_TIMER:
case EventInterface::EV_TIMER_ONCE:
if (isset($this->_timerIdMap[$fd])){
$timer_obj = $this->_timerIdMap[$fd];
unset($this->_timerIdMap[$fd]);
$this->cancelTimer($timer_obj);
return true;
}
}
return false;
}
/**
* Main loop.
*
* @return void
*/
public function loop()
{
$this->run();
}
/**
* Destroy loop.
*
* @return void
*/
public function destroy()
{
}
/**
* Get timer count.
*
* @return integer
*/
public function getTimerCount()
{
return \count($this->_timerIdMap);
}
/**
* @param resource $stream
* @param callable $listener
*/
public function addReadStream($stream, $listener)
{
return $this->_eventLoop->addReadStream($stream, $listener);
}
/**
* @param resource $stream
* @param callable $listener
*/
public function addWriteStream($stream, $listener)
{
return $this->_eventLoop->addWriteStream($stream, $listener);
}
/**
* @param resource $stream
*/
public function removeReadStream($stream)
{
return $this->_eventLoop->removeReadStream($stream);
}
/**
* @param resource $stream
*/
public function removeWriteStream($stream)
{
return $this->_eventLoop->removeWriteStream($stream);
}
/**
* @param float|int $interval
* @param callable $callback
* @return \React\EventLoop\Timer\Timer|TimerInterface
*/
public function addTimer($interval, $callback)
{
return $this->_eventLoop->addTimer($interval, $callback);
}
/**
* @param float|int $interval
* @param callable $callback
* @return \React\EventLoop\Timer\Timer|TimerInterface
*/
public function addPeriodicTimer($interval, $callback)
{
return $this->_eventLoop->addPeriodicTimer($interval, $callback);
}
/**
* @param TimerInterface $timer
*/
public function cancelTimer(TimerInterface $timer)
{
return $this->_eventLoop->cancelTimer($timer);
}
/**
* @param callable $listener
*/
public function futureTick($listener)
{
return $this->_eventLoop->futureTick($listener);
}
/**
* @param int $signal
* @param callable $listener
*/
public function addSignal($signal, $listener)
{
return $this->_eventLoop->addSignal($signal, $listener);
}
/**
* @param int $signal
* @param callable $listener
*/
public function removeSignal($signal, $listener)
{
return $this->_eventLoop->removeSignal($signal, $listener);
}
/**
* Run.
*/
public function run()
{
return $this->_eventLoop->run();
}
/**
* Stop.
*/
public function stop()
{
return $this->_eventLoop->stop();
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events\React;
/**
* Class ExtEventLoop
* @package Workerman\Events\React
*/
class ExtEventLoop extends Base
{
public function __construct()
{
$this->_eventLoop = new \React\EventLoop\ExtEventLoop();
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events\React;
use Workerman\Events\EventInterface;
/**
* Class ExtLibEventLoop
* @package Workerman\Events\React
*/
class ExtLibEventLoop extends Base
{
public function __construct()
{
$this->_eventLoop = new \React\EventLoop\ExtLibeventLoop();
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events\React;
/**
* Class StreamSelectLoop
* @package Workerman\Events\React
*/
class StreamSelectLoop extends Base
{
public function __construct()
{
$this->_eventLoop = new \React\EventLoop\StreamSelectLoop();
}
}

View File

@ -0,0 +1,357 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
use Throwable;
use Workerman\Worker;
/**
* select eventloop
*/
class Select implements EventInterface
{
/**
* All listeners for read/write event.
*
* @var array
*/
public $_allEvents = array();
/**
* Event listeners of signal.
*
* @var array
*/
public $_signalEvents = array();
/**
* Fds waiting for read event.
*
* @var array
*/
protected $_readFds = array();
/**
* Fds waiting for write event.
*
* @var array
*/
protected $_writeFds = array();
/**
* Fds waiting for except event.
*
* @var array
*/
protected $_exceptFds = array();
/**
* Timer scheduler.
* {['data':timer_id, 'priority':run_timestamp], ..}
*
* @var \SplPriorityQueue
*/
protected $_scheduler = null;
/**
* All timer event listeners.
* [[func, args, flag, timer_interval], ..]
*
* @var array
*/
protected $_eventTimer = array();
/**
* Timer id.
*
* @var int
*/
protected $_timerId = 1;
/**
* Select timeout.
*
* @var int
*/
protected $_selectTimeout = 100000000;
/**
* Paired socket channels
*
* @var array
*/
protected $channel = array();
/**
* Construct.
*/
public function __construct()
{
// Init SplPriorityQueue.
$this->_scheduler = new \SplPriorityQueue();
$this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
}
/**
* {@inheritdoc}
*/
public function add($fd, $flag, $func, $args = array())
{
switch ($flag) {
case self::EV_READ:
case self::EV_WRITE:
$count = $flag === self::EV_READ ? \count($this->_readFds) : \count($this->_writeFds);
if ($count >= 1024) {
echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n";
} else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) {
echo "Warning: system call select exceeded the maximum number of connections 256.\n";
}
$fd_key = (int)$fd;
$this->_allEvents[$fd_key][$flag] = array($func, $fd);
if ($flag === self::EV_READ) {
$this->_readFds[$fd_key] = $fd;
} else {
$this->_writeFds[$fd_key] = $fd;
}
break;
case self::EV_EXCEPT:
$fd_key = (int)$fd;
$this->_allEvents[$fd_key][$flag] = array($func, $fd);
$this->_exceptFds[$fd_key] = $fd;
break;
case self::EV_SIGNAL:
// Windows not support signal.
if(\DIRECTORY_SEPARATOR !== '/') {
return false;
}
$fd_key = (int)$fd;
$this->_signalEvents[$fd_key][$flag] = array($func, $fd);
\pcntl_signal($fd, array($this, 'signalHandler'));
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
$timer_id = $this->_timerId++;
$run_time = \microtime(true) + $fd;
$this->_scheduler->insert($timer_id, -$run_time);
$this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd);
$select_timeout = ($run_time - \microtime(true)) * 1000000;
$select_timeout = $select_timeout <= 0 ? 1 : $select_timeout;
if( $this->_selectTimeout > $select_timeout ){
$this->_selectTimeout = (int) $select_timeout;
}
return $timer_id;
}
return true;
}
/**
* Signal handler.
*
* @param int $signal
*/
public function signalHandler($signal)
{
\call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal));
}
/**
* {@inheritdoc}
*/
public function del($fd, $flag)
{
$fd_key = (int)$fd;
switch ($flag) {
case self::EV_READ:
unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]);
if (empty($this->_allEvents[$fd_key])) {
unset($this->_allEvents[$fd_key]);
}
return true;
case self::EV_WRITE:
unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]);
if (empty($this->_allEvents[$fd_key])) {
unset($this->_allEvents[$fd_key]);
}
return true;
case self::EV_EXCEPT:
unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]);
if(empty($this->_allEvents[$fd_key]))
{
unset($this->_allEvents[$fd_key]);
}
return true;
case self::EV_SIGNAL:
if(\DIRECTORY_SEPARATOR !== '/') {
return false;
}
unset($this->_signalEvents[$fd_key]);
\pcntl_signal($fd, SIG_IGN);
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE;
unset($this->_eventTimer[$fd_key]);
return true;
}
return false;
}
/**
* Tick for timer.
*
* @return void
*/
protected function tick()
{
$tasks_to_insert = [];
while (!$this->_scheduler->isEmpty()) {
$scheduler_data = $this->_scheduler->top();
$timer_id = $scheduler_data['data'];
$next_run_time = -$scheduler_data['priority'];
$time_now = \microtime(true);
$this->_selectTimeout = (int) (($next_run_time - $time_now) * 1000000);
if ($this->_selectTimeout <= 0) {
$this->_scheduler->extract();
if (!isset($this->_eventTimer[$timer_id])) {
continue;
}
// [func, args, flag, timer_interval]
$task_data = $this->_eventTimer[$timer_id];
if ($task_data[2] === self::EV_TIMER) {
$next_run_time = $time_now + $task_data[3];
$tasks_to_insert[] = [$timer_id, -$next_run_time];
}
try {
\call_user_func_array($task_data[0], $task_data[1]);
} catch (Throwable $e) {
Worker::stopAll(250, $e);
}
if (isset($this->_eventTimer[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) {
$this->del($timer_id, self::EV_TIMER_ONCE);
}
} else {
break;
}
}
foreach ($tasks_to_insert as $item) {
$this->_scheduler->insert($item[0], $item[1]);
}
if (!$this->_scheduler->isEmpty()) {
$scheduler_data = $this->_scheduler->top();
$next_run_time = -$scheduler_data['priority'];
$time_now = \microtime(true);
$this->_selectTimeout = \max((int) (($next_run_time - $time_now) * 1000000), 0);
return;
}
$this->_selectTimeout = 100000000;
}
/**
* {@inheritdoc}
*/
public function clearAllTimer()
{
$this->_scheduler = new \SplPriorityQueue();
$this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
$this->_eventTimer = array();
}
/**
* {@inheritdoc}
*/
public function loop()
{
while (1) {
if(\DIRECTORY_SEPARATOR === '/') {
// Calls signal handlers for pending signals
\pcntl_signal_dispatch();
}
$read = $this->_readFds;
$write = $this->_writeFds;
$except = $this->_exceptFds;
$ret = false;
if ($read || $write || $except) {
// Waiting read/write/signal/timeout events.
try {
$ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout);
} catch (\Exception $e) {} catch (\Error $e) {}
} else {
$this->_selectTimeout >= 1 && usleep($this->_selectTimeout);
}
if (!$this->_scheduler->isEmpty()) {
$this->tick();
}
if (!$ret) {
continue;
}
if ($read) {
foreach ($read as $fd) {
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][self::EV_READ])) {
\call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0],
array($this->_allEvents[$fd_key][self::EV_READ][1]));
}
}
}
if ($write) {
foreach ($write as $fd) {
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) {
\call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0],
array($this->_allEvents[$fd_key][self::EV_WRITE][1]));
}
}
}
if($except) {
foreach($except as $fd) {
$fd_key = (int) $fd;
if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) {
\call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0],
array($this->_allEvents[$fd_key][self::EV_EXCEPT][1]));
}
}
}
}
}
/**
* Destroy loop.
*
* @return void
*/
public function destroy()
{
}
/**
* Get timer count.
*
* @return integer
*/
public function getTimerCount()
{
return \count($this->_eventTimer);
}
}

View File

@ -0,0 +1,230 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author Ares<aresrr#qq.com>
* @link http://www.workerman.net/
* @link https://github.com/ares333/Workerman
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
use Workerman\Worker;
use Swoole\Event;
use Swoole\Timer;
class Swoole implements EventInterface
{
protected $_timer = array();
protected $_timerOnceMap = array();
protected $mapId = 0;
protected $_fd = array();
// milisecond
public static $signalDispatchInterval = 500;
protected $_hasSignal = false;
/**
*
* {@inheritdoc}
*
* @see \Workerman\Events\EventInterface::add()
*/
public function add($fd, $flag, $func, $args = array())
{
switch ($flag) {
case self::EV_SIGNAL:
$res = \pcntl_signal($fd, $func, false);
if (! $this->_hasSignal && $res) {
Timer::tick(static::$signalDispatchInterval,
function () {
\pcntl_signal_dispatch();
});
$this->_hasSignal = true;
}
return $res;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
$method = self::EV_TIMER === $flag ? 'tick' : 'after';
if ($this->mapId > \PHP_INT_MAX) {
$this->mapId = 0;
}
$mapId = $this->mapId++;
$t = (int)($fd * 1000);
if ($t < 1) {
$t = 1;
}
$timer_id = Timer::$method($t,
function ($timer_id = null) use ($func, $args, $mapId) {
try {
\call_user_func_array($func, (array)$args);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
// EV_TIMER_ONCE
if (! isset($timer_id)) {
// may be deleted in $func
if (\array_key_exists($mapId, $this->_timerOnceMap)) {
$timer_id = $this->_timerOnceMap[$mapId];
unset($this->_timer[$timer_id],
$this->_timerOnceMap[$mapId]);
}
}
});
if ($flag === self::EV_TIMER_ONCE) {
$this->_timerOnceMap[$mapId] = $timer_id;
$this->_timer[$timer_id] = $mapId;
} else {
$this->_timer[$timer_id] = null;
}
return $timer_id;
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int) $fd;
if (! isset($this->_fd[$fd_key])) {
if ($flag === self::EV_READ) {
$res = Event::add($fd, $func, null, SWOOLE_EVENT_READ);
$fd_type = SWOOLE_EVENT_READ;
} else {
$res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE);
$fd_type = SWOOLE_EVENT_WRITE;
}
if ($res) {
$this->_fd[$fd_key] = $fd_type;
}
} else {
$fd_val = $this->_fd[$fd_key];
$res = true;
if ($flag === self::EV_READ) {
if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) {
$res = Event::set($fd, $func, null,
SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
$this->_fd[$fd_key] |= SWOOLE_EVENT_READ;
}
} else {
if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) {
$res = Event::set($fd, null, $func,
SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
$this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE;
}
}
}
return $res;
}
}
/**
*
* {@inheritdoc}
*
* @see \Workerman\Events\EventInterface::del()
*/
public function del($fd, $flag)
{
switch ($flag) {
case self::EV_SIGNAL:
return \pcntl_signal($fd, SIG_IGN, false);
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
// already remove in EV_TIMER_ONCE callback.
if (! \array_key_exists($fd, $this->_timer)) {
return true;
}
$res = Timer::clear($fd);
if ($res) {
$mapId = $this->_timer[$fd];
if (isset($mapId)) {
unset($this->_timerOnceMap[$mapId]);
}
unset($this->_timer[$fd]);
}
return $res;
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int) $fd;
if (isset($this->_fd[$fd_key])) {
$fd_val = $this->_fd[$fd_key];
if ($flag === self::EV_READ) {
$flag_remove = ~ SWOOLE_EVENT_READ;
} else {
$flag_remove = ~ SWOOLE_EVENT_WRITE;
}
$fd_val &= $flag_remove;
if (0 === $fd_val) {
$res = Event::del($fd);
if ($res) {
unset($this->_fd[$fd_key]);
}
} else {
$res = Event::set($fd, null, null, $fd_val);
if ($res) {
$this->_fd[$fd_key] = $fd_val;
}
}
} else {
$res = true;
}
return $res;
}
}
/**
*
* {@inheritdoc}
*
* @see \Workerman\Events\EventInterface::clearAllTimer()
*/
public function clearAllTimer()
{
foreach (array_keys($this->_timer) as $v) {
Timer::clear($v);
}
$this->_timer = array();
$this->_timerOnceMap = array();
}
/**
*
* {@inheritdoc}
*
* @see \Workerman\Events\EventInterface::loop()
*/
public function loop()
{
Event::wait();
}
/**
*
* {@inheritdoc}
*
* @see \Workerman\Events\EventInterface::destroy()
*/
public function destroy()
{
Event::exit();
posix_kill(posix_getpid(), SIGINT);
}
/**
*
* {@inheritdoc}
*
* @see \Workerman\Events\EventInterface::getTimerCount()
*/
public function getTimerCount()
{
return \count($this->_timer);
}
}

260
vendor/workerman/workerman/Events/Uv.php vendored Normal file
View File

@ -0,0 +1,260 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author 爬山虎<blogdaren@163.com>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Events;
use Workerman\Worker;
/**
* libuv eventloop
*/
class Uv implements EventInterface
{
/**
* Event Loop.
* @var object
*/
protected $_eventLoop = null;
/**
* All listeners for read/write event.
*
* @var array
*/
protected $_allEvents = array();
/**
* Event listeners of signal.
*
* @var array
*/
protected $_eventSignal = array();
/**
* All timer event listeners.
*
* @var array
*/
protected $_eventTimer = array();
/**
* Timer id.
*
* @var int
*/
protected static $_timerId = 1;
/**
* @brief Constructor
*
* @param object $loop
*
* @return void
*/
public function __construct(\UVLoop $loop = null)
{
if(!extension_loaded('uv'))
{
throw new \Exception(__CLASS__ . ' requires the UV extension, but detected it has NOT been installed yet.');
}
if(empty($loop) || !$loop instanceof \UVLoop)
{
$this->_eventLoop = \uv_default_loop();
return;
}
$this->_eventLoop = $loop;
}
/**
* @brief Add a timer
*
* @param resource $fd
* @param int $flag
* @param callback $func
* @param mixed $args
*
* @return mixed
*/
public function add($fd, $flag, $func, $args = null)
{
switch ($flag)
{
case self::EV_SIGNAL:
$signalCallback = function($watcher, $socket)use($func, $fd){
try {
\call_user_func($func, $fd);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
};
$signalWatcher = \uv_signal_init();
\uv_signal_start($signalWatcher, $signalCallback, $fd);
$this->_eventSignal[$fd] = $signalWatcher;
return true;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
$repeat = $flag === self::EV_TIMER_ONCE ? 0 : (int)($fd * 1000);
$param = array($func, (array)$args, $flag, $fd, self::$_timerId);
$timerWatcher = \uv_timer_init();
\uv_timer_start($timerWatcher, 1, $repeat, function($watcher)use($param){
call_user_func_array([$this, 'timerCallback'], [$param]);
});
$this->_eventTimer[self::$_timerId] = $timerWatcher;
return self::$_timerId++;
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int)$fd;
$ioCallback = function($watcher, $status, $events, $fd)use($func){
try {
\call_user_func($func, $fd);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
};
$ioWatcher = \uv_poll_init($this->_eventLoop, $fd);
$real_flag = $flag === self::EV_READ ? \Uv::READABLE : \Uv::WRITABLE;
\uv_poll_start($ioWatcher, $real_flag, $ioCallback);
$this->_allEvents[$fd_key][$flag] = $ioWatcher;
return true;
default:
break;
}
}
/**
* @brief Remove a timer
*
* @param resource $fd
* @param int $flag
*
* @return boolean
*/
public function del($fd, $flag)
{
switch ($flag)
{
case self::EV_READ:
case self::EV_WRITE:
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][$flag])) {
$watcher = $this->_allEvents[$fd_key][$flag];
\uv_is_active($watcher) && \uv_poll_stop($watcher);
unset($this->_allEvents[$fd_key][$flag]);
}
if (empty($this->_allEvents[$fd_key])) {
unset($this->_allEvents[$fd_key]);
}
break;
case self::EV_SIGNAL:
$fd_key = (int)$fd;
if (isset($this->_eventSignal[$fd_key])) {
$watcher = $this->_eventSignal[$fd_key];
\uv_is_active($watcher) && \uv_signal_stop($watcher);
unset($this->_eventSignal[$fd_key]);
}
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
if (isset($this->_eventTimer[$fd])) {
$watcher = $this->_eventTimer[$fd];
\uv_is_active($watcher) && \uv_timer_stop($watcher);
unset($this->_eventTimer[$fd]);
}
break;
}
return true;
}
/**
* @brief Timer callback
*
* @param array $input
*
* @return void
*/
public function timerCallback($input)
{
if(!is_array($input)) return;
$timer_id = $input[4];
if ($input[2] === self::EV_TIMER_ONCE)
{
$watcher = $this->_eventTimer[$timer_id];
\uv_is_active($watcher) && \uv_timer_stop($watcher);
unset($this->_eventTimer[$timer_id]);
}
try {
\call_user_func_array($input[0], $input[1]);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
}
/**
* @brief Remove all timers
*
* @return void
*/
public function clearAllTimer()
{
if(!is_array($this->_eventTimer)) return;
foreach($this->_eventTimer as $watcher)
{
\uv_is_active($watcher) && \uv_timer_stop($watcher);
}
$this->_eventTimer = array();
}
/**
* @brief Start loop
*
* @return void
*/
public function loop()
{
\Uv_run();
}
/**
* @brief Destroy loop
*
* @return void
*/
public function destroy()
{
!empty($this->_eventLoop) && \uv_loop_delete($this->_eventLoop);
$this->_allEvents = [];
}
/**
* @brief Get timer count
*
* @return integer
*/
public function getTimerCount()
{
return \count($this->_eventTimer);
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*
* @link http://www.workerman.net/
*/
// Pcre.jit is not stable, temporarily disabled.
ini_set('pcre.jit', 0);
// For onError callback.
const WORKERMAN_CONNECT_FAIL = 1;
// For onError callback.
const WORKERMAN_SEND_FAIL = 2;
// Define OS Type
const OS_TYPE_LINUX = 'linux';
const OS_TYPE_WINDOWS = 'windows';
// Compatible with php7
if (!class_exists('Error')) {
class Error extends Exception
{
}
}
if (!interface_exists('SessionHandlerInterface')) {
interface SessionHandlerInterface {
public function close();
public function destroy($session_id);
public function gc($maxlifetime);
public function open($save_path ,$session_name);
public function read($session_id);
public function write($session_id , $session_data);
}
}

View File

@ -0,0 +1,22 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Lib;
/**
* Do not use Workerman\Lib\Timer.
* Please use Workerman\Timer.
* This class is only used for compatibility with workerman 3.*
* @package Workerman\Lib
*/
class Timer extends \Workerman\Timer {}

View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2009-2015 walkor<walkor@workerman.net> and contributors (see https://github.com/walkor/workerman/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,125 @@
<?php
namespace Workerman\Protocols;
class Dns
{
/**
* 检查包的完整性
* 如果能够得到包长则返回包的在buffer中的长度否则返回0继续等待数据
* 如果协议有问题则可以返回false当前客户端连接会因此断开
* @param string $buffer
* @return int
*/
public static function input($buffer)
{
return 200;
}
/**
* 打包,当向客户端发送数据的时候会自动调用
* @param string $buffer
* @return string
*/
public static function encode($buffer)
{
$buffer=json_decode($buffer);
$type=$buffer->type;
switch($type){
case 'A':
$type='0001';
$lenth='0004';
$ip=$buffer->detail;
$n=0;
foreach($ip as $i){
$nss=explode('.',$i);
$detail[$n]='';
foreach($nss as $part){
$tpart=dechex($part);
$detail[$n]=$detail[$n].$tpart;
};
$n+1;
};
break;
case 'NS':
$type='0002';
$lenth='0004';
$ns=$buffer->detail;
$n=0;
foreach($ns as $i){
$nss=explode('.',$i);
$detail[$n]='';
foreach($nss as $part){
$len=strlen($part);
$tpart=bin2hex($part);
$detail[$n]=$detail[$n].$len.$tpart;
};
$detail[$n]=$detail[$n].'00';
$n+1;
};
break;
}
$ttl=str_pad(dechex($buffer->ttl),8,"0",STR_PAD_LEFT);
$status='8180';
$questions='0001';
$AnswerRRs='0001';
$AuthorityRRs='0000';
$AdditionalRRs='0000';
$answer='';
foreach($detail as $c){
$answer=$answer.'C00C'.$type.'0001'.$ttl.$lenth.$c;
}
$response=$buffer->id.$status.$questions.$AnswerRRs.$AuthorityRRs.$AdditionalRRs.$buffer->query.$answer;
return hex2bin($response);
}
/**
* 解包当接收到的数据字节数等于input返回的值大于0的值自动调用
* 并传递给onMessage回调函数的$data参数
* @param string $buffer
* @return string
*/
public static function decode($buffer)
{
$data=bin2hex($buffer);
$id=substr($data,0,4);
$type=substr($data,-8,4);
switch($type){
case '0001':
$type='A';
break;
case '0002':
$type='NS';
break;
case '000c':
$type='PTR';
break;
case '001c':
$type='AAAA';
break;
case '0005':
$type='CNAME';
break;
case '0010':
$type='TEXT';
break;
}
$name=substr($data,24,-8);
$namede=str_split($name,2);
$realname='';
foreach($namede as $cha){
$chat=hex2bin($cha);
if(!ctype_alnum($chat)){
$chat='.';
}
$realname=$realname.$chat;
}
$realname=substr($realname,1,-1);
$query=substr($data,24);
#$returndata="$type".'|||'."$realname";
$returndata= json_encode(array('type' => "$type", 'name' => "$realname", 'id'=>"$id", 'query'=>"$query"));
return $returndata;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Protocols;
use Workerman\Connection\TcpConnection;
/**
* Frame Protocol.
*/
class Frame
{
/**
* Check the integrity of the package.
*
* @param string $buffer
* @param TcpConnection $connection
* @return int
*/
public static function input($buffer, TcpConnection $connection)
{
if (\strlen($buffer) < 4) {
return 0;
}
$unpack_data = \unpack('Ntotal_length', $buffer);
return $unpack_data['total_length'];
}
/**
* Decode.
*
* @param string $buffer
* @return string
*/
public static function decode($buffer)
{
return \substr($buffer, 4);
}
/**
* Encode.
*
* @param string $buffer
* @return string
*/
public static function encode($buffer)
{
$total_length = 4 + \strlen($buffer);
return \pack('N', $total_length) . $buffer;
}
}

View File

@ -0,0 +1,324 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Protocols;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Protocols\Http\Session;
use Workerman\Protocols\Websocket;
use Workerman\Worker;
/**
* Class Http.
* @package Workerman\Protocols
*/
class Http
{
/**
* Request class name.
*
* @var string
*/
protected static $_requestClass = 'Workerman\Protocols\Http\Request';
/**
* Upload tmp dir.
*
* @var string
*/
protected static $_uploadTmpDir = '';
/**
* Open cache.
*
* @var bool.
*/
protected static $_enableCache = true;
/**
* Get or set session name.
*
* @param string|null $name
* @return string
*/
public static function sessionName($name = null)
{
if ($name !== null && $name !== '') {
Session::$name = (string)$name;
}
return Session::$name;
}
/**
* Get or set the request class name.
*
* @param string|null $class_name
* @return string
*/
public static function requestClass($class_name = null)
{
if ($class_name) {
static::$_requestClass = $class_name;
}
return static::$_requestClass;
}
/**
* Enable or disable Cache.
*
* @param mixed $value
*/
public static function enableCache($value)
{
static::$_enableCache = (bool)$value;
}
/**
* Check the integrity of the package.
*
* @param string $recv_buffer
* @param TcpConnection $connection
* @return int
*/
public static function input($recv_buffer, TcpConnection $connection)
{
static $input = array();
if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) {
return $input[$recv_buffer];
}
$crlf_pos = \strpos($recv_buffer, "\r\n\r\n");
if (false === $crlf_pos) {
// Judge whether the package length exceeds the limit.
if ($recv_len = \strlen($recv_buffer) >= 16384) {
$connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true);
return 0;
}
return 0;
}
$head_len = $crlf_pos + 4;
$method = \strstr($recv_buffer, ' ', true);
if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD' || $method === 'DELETE') {
if (!isset($recv_buffer[512])) {
$input[$recv_buffer] = $head_len;
if (\count($input) > 512) {
unset($input[key($input)]);
}
}
return $head_len;
} else if ($method !== 'POST' && $method !== 'PUT' && $method !== 'PATCH') {
$connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
return 0;
}
$header = \substr($recv_buffer, 0, $crlf_pos);
$length = false;
if ($pos = \strpos($header, "\r\nContent-Length: ")) {
$length = $head_len + (int)\substr($header, $pos + 18, 10);
} else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) {
$length = $head_len + $match[1];
}
if ($length !== false) {
if (!isset($recv_buffer[512])) {
$input[$recv_buffer] = $length;
if (\count($input) > 512) {
unset($input[key($input)]);
}
}
if ($length > $connection->maxPackageSize) {
$connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true);
return 0;
}
return $length;
}
$connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
return 0;
}
/**
* Http decode.
*
* @param string $recv_buffer
* @param TcpConnection $connection
* @return \Workerman\Protocols\Http\Request
*/
public static function decode($recv_buffer, TcpConnection $connection)
{
static $requests = array();
$cacheable = static::$_enableCache && !isset($recv_buffer[512]);
if (true === $cacheable && isset($requests[$recv_buffer])) {
$request = $requests[$recv_buffer];
$request->connection = $connection;
$connection->__request = $request;
$request->properties = array();
return $request;
}
$request = new static::$_requestClass($recv_buffer);
$request->connection = $connection;
$connection->__request = $request;
if (true === $cacheable) {
$requests[$recv_buffer] = $request;
if (\count($requests) > 512) {
unset($requests[key($requests)]);
}
}
return $request;
}
/**
* Http encode.
*
* @param string|Response $response
* @param TcpConnection $connection
* @return string
*/
public static function encode($response, TcpConnection $connection)
{
if (isset($connection->__request)) {
$connection->__request->session = null;
$connection->__request->connection = null;
$connection->__request = null;
}
if (!\is_object($response)) {
$ext_header = '';
if (isset($connection->__header)) {
foreach ($connection->__header as $name => $value) {
if (\is_array($value)) {
foreach ($value as $item) {
$ext_header = "$name: $item\r\n";
}
} else {
$ext_header = "$name: $value\r\n";
}
}
unset($connection->__header);
}
$body_len = \strlen((string)$response);
return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$ext_header}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\n\r\n$response";
}
if (isset($connection->__header)) {
$response->withHeaders($connection->__header);
unset($connection->__header);
}
if (isset($response->file)) {
$file = $response->file['file'];
$offset = $response->file['offset'];
$length = $response->file['length'];
$file_size = (int)\filesize($file);
$body_len = $length > 0 ? $length : $file_size - $offset;
$response->withHeaders(array(
'Content-Length' => $body_len,
'Accept-Ranges' => 'bytes',
));
if ($offset || $length) {
$offset_end = $offset + $body_len - 1;
$response->header('Content-Range', "bytes $offset-$offset_end/$file_size");
}
if ($body_len < 2 * 1024 * 1024) {
$connection->send((string)$response . file_get_contents($file, false, null, $offset, $body_len), true);
return '';
}
$handler = \fopen($file, 'r');
if (false === $handler) {
$connection->close(new Response(403, null, '403 Forbidden'));
return '';
}
$connection->send((string)$response, true);
static::sendStream($connection, $handler, $offset, $length);
return '';
}
return (string)$response;
}
/**
* Send remainder of a stream to client.
*
* @param TcpConnection $connection
* @param resource $handler
* @param int $offset
* @param int $length
*/
protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0)
{
$connection->bufferFull = false;
if ($offset !== 0) {
\fseek($handler, $offset);
}
$offset_end = $offset + $length;
// Read file content from disk piece by piece and send to client.
$do_write = function () use ($connection, $handler, $length, $offset_end) {
// Send buffer not full.
while ($connection->bufferFull === false) {
// Read from disk.
$size = 1024 * 1024;
if ($length !== 0) {
$tell = \ftell($handler);
$remain_size = $offset_end - $tell;
if ($remain_size <= 0) {
fclose($handler);
$connection->onBufferDrain = null;
return;
}
$size = $remain_size > $size ? $size : $remain_size;
}
$buffer = \fread($handler, $size);
// Read eof.
if ($buffer === '' || $buffer === false) {
fclose($handler);
$connection->onBufferDrain = null;
return;
}
$connection->send($buffer, true);
}
};
// Send buffer full.
$connection->onBufferFull = function ($connection) {
$connection->bufferFull = true;
};
// Send buffer drain.
$connection->onBufferDrain = function ($connection) use ($do_write) {
$connection->bufferFull = false;
$do_write();
};
$do_write();
}
/**
* Set or get uploadTmpDir.
*
* @return bool|string
*/
public static function uploadTmpDir($dir = null)
{
if (null !== $dir) {
static::$_uploadTmpDir = $dir;
}
if (static::$_uploadTmpDir === '') {
if ($upload_tmp_dir = \ini_get('upload_tmp_dir')) {
static::$_uploadTmpDir = $upload_tmp_dir;
} else if ($upload_tmp_dir = \sys_get_temp_dir()) {
static::$_uploadTmpDir = $upload_tmp_dir;
}
}
return static::$_uploadTmpDir;
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Protocols\Http;
/**
* Class Chunk
* @package Workerman\Protocols\Http
*/
class Chunk
{
/**
* Chunk buffer.
*
* @var string
*/
protected $_buffer = null;
/**
* Chunk constructor.
* @param string $buffer
*/
public function __construct($buffer)
{
$this->_buffer = $buffer;
}
/**
* __toString
*
* @return string
*/
public function __toString()
{
return \dechex(\strlen($this->_buffer))."\r\n$this->_buffer\r\n";
}
}

View File

@ -0,0 +1,673 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Protocols\Http;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Session;
use Workerman\Protocols\Http;
use Workerman\Worker;
/**
* Class Request
* @package Workerman\Protocols\Http
*/
class Request
{
/**
* Connection.
*
* @var TcpConnection
*/
public $connection = null;
/**
* Session instance.
*
* @var Session
*/
public $session = null;
/**
* Properties.
*
* @var array
*/
public $properties = array();
/**
* @var int
*/
public static $maxFileUploads = 1024;
/**
* Http buffer.
*
* @var string
*/
protected $_buffer = null;
/**
* Request data.
*
* @var array
*/
protected $_data = null;
/**
* Enable cache.
*
* @var bool
*/
protected static $_enableCache = true;
/**
* Request constructor.
*
* @param string $buffer
*/
public function __construct($buffer)
{
$this->_buffer = $buffer;
}
/**
* $_GET.
*
* @param string|null $name
* @param mixed|null $default
* @return mixed|null
*/
public function get($name = null, $default = null)
{
if (!isset($this->_data['get'])) {
$this->parseGet();
}
if (null === $name) {
return $this->_data['get'];
}
return isset($this->_data['get'][$name]) ? $this->_data['get'][$name] : $default;
}
/**
* $_POST.
*
* @param string|null $name
* @param mixed|null $default
* @return mixed|null
*/
public function post($name = null, $default = null)
{
if (!isset($this->_data['post'])) {
$this->parsePost();
}
if (null === $name) {
return $this->_data['post'];
}
return isset($this->_data['post'][$name]) ? $this->_data['post'][$name] : $default;
}
/**
* Get header item by name.
*
* @param string|null $name
* @param mixed|null $default
* @return array|string|null
*/
public function header($name = null, $default = null)
{
if (!isset($this->_data['headers'])) {
$this->parseHeaders();
}
if (null === $name) {
return $this->_data['headers'];
}
$name = \strtolower($name);
return isset($this->_data['headers'][$name]) ? $this->_data['headers'][$name] : $default;
}
/**
* Get cookie item by name.
*
* @param string|null $name
* @param mixed|null $default
* @return array|string|null
*/
public function cookie($name = null, $default = null)
{
if (!isset($this->_data['cookie'])) {
$this->_data['cookie'] = array();
\parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->_data['cookie']);
}
if ($name === null) {
return $this->_data['cookie'];
}
return isset($this->_data['cookie'][$name]) ? $this->_data['cookie'][$name] : $default;
}
/**
* Get upload files.
*
* @param string|null $name
* @return array|null
*/
public function file($name = null)
{
if (!isset($this->_data['files'])) {
$this->parsePost();
}
if (null === $name) {
return $this->_data['files'];
}
return isset($this->_data['files'][$name]) ? $this->_data['files'][$name] : null;
}
/**
* Get method.
*
* @return string
*/
public function method()
{
if (!isset($this->_data['method'])) {
$this->parseHeadFirstLine();
}
return $this->_data['method'];
}
/**
* Get http protocol version.
*
* @return string
*/
public function protocolVersion()
{
if (!isset($this->_data['protocolVersion'])) {
$this->parseProtocolVersion();
}
return $this->_data['protocolVersion'];
}
/**
* Get host.
*
* @param bool $without_port
* @return string
*/
public function host($without_port = false)
{
$host = $this->header('host');
if ($host && $without_port && $pos = \strpos($host, ':')) {
return \substr($host, 0, $pos);
}
return $host;
}
/**
* Get uri.
*
* @return mixed
*/
public function uri()
{
if (!isset($this->_data['uri'])) {
$this->parseHeadFirstLine();
}
return $this->_data['uri'];
}
/**
* Get path.
*
* @return mixed
*/
public function path()
{
if (!isset($this->_data['path'])) {
$this->_data['path'] = (string)\parse_url($this->uri(), PHP_URL_PATH);
}
return $this->_data['path'];
}
/**
* Get query string.
*
* @return mixed
*/
public function queryString()
{
if (!isset($this->_data['query_string'])) {
$this->_data['query_string'] = (string)\parse_url($this->uri(), PHP_URL_QUERY);
}
return $this->_data['query_string'];
}
/**
* Get session.
*
* @return bool|\Workerman\Protocols\Http\Session
*/
public function session()
{
if ($this->session === null) {
$session_id = $this->sessionId();
if ($session_id === false) {
return false;
}
$this->session = new Session($session_id);
}
return $this->session;
}
/**
* Get/Set session id.
*
* @param $session_id
* @return string
*/
public function sessionId($session_id = null)
{
if ($session_id) {
unset($this->sid);
}
if (!isset($this->sid)) {
$session_name = Session::$name;
$sid = $session_id ? '' : $this->cookie($session_name);
if ($sid === '' || $sid === null) {
if ($this->connection === null) {
Worker::safeEcho('Request->session() fail, header already send');
return false;
}
$sid = $session_id ? $session_id : static::createSessionId();
$cookie_params = Session::getCookieParams();
$this->connection->__header['Set-Cookie'] = array($session_name . '=' . $sid
. (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain'])
. (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime'])
. (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path'])
. (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite'])
. (!$cookie_params['secure'] ? '' : '; Secure')
. (!$cookie_params['httponly'] ? '' : '; HttpOnly'));
}
$this->sid = $sid;
}
return $this->sid;
}
/**
* Get http raw head.
*
* @return string
*/
public function rawHead()
{
if (!isset($this->_data['head'])) {
$this->_data['head'] = \strstr($this->_buffer, "\r\n\r\n", true);
}
return $this->_data['head'];
}
/**
* Get http raw body.
*
* @return string
*/
public function rawBody()
{
return \substr($this->_buffer, \strpos($this->_buffer, "\r\n\r\n") + 4);
}
/**
* Get raw buffer.
*
* @return string
*/
public function rawBuffer()
{
return $this->_buffer;
}
/**
* Enable or disable cache.
*
* @param mixed $value
*/
public static function enableCache($value)
{
static::$_enableCache = (bool)$value;
}
/**
* Parse first line of http header buffer.
*
* @return void
*/
protected function parseHeadFirstLine()
{
$first_line = \strstr($this->_buffer, "\r\n", true);
$tmp = \explode(' ', $first_line, 3);
$this->_data['method'] = $tmp[0];
$this->_data['uri'] = isset($tmp[1]) ? $tmp[1] : '/';
}
/**
* Parse protocol version.
*
* @return void
*/
protected function parseProtocolVersion()
{
$first_line = \strstr($this->_buffer, "\r\n", true);
$protoco_version = substr(\strstr($first_line, 'HTTP/'), 5);
$this->_data['protocolVersion'] = $protoco_version ? $protoco_version : '1.0';
}
/**
* Parse headers.
*
* @return void
*/
protected function parseHeaders()
{
static $cache = [];
$this->_data['headers'] = array();
$raw_head = $this->rawHead();
$end_line_position = \strpos($raw_head, "\r\n");
if ($end_line_position === false) {
return;
}
$head_buffer = \substr($raw_head, $end_line_position + 2);
$cacheable = static::$_enableCache && !isset($head_buffer[2048]);
if ($cacheable && isset($cache[$head_buffer])) {
$this->_data['headers'] = $cache[$head_buffer];
return;
}
$head_data = \explode("\r\n", $head_buffer);
foreach ($head_data as $content) {
if (false !== \strpos($content, ':')) {
list($key, $value) = \explode(':', $content, 2);
$key = \strtolower($key);
$value = \ltrim($value);
} else {
$key = \strtolower($content);
$value = '';
}
if (isset($this->_data['headers'][$key])) {
$this->_data['headers'][$key] = "{$this->_data['headers'][$key]},$value";
} else {
$this->_data['headers'][$key] = $value;
}
}
if ($cacheable) {
$cache[$head_buffer] = $this->_data['headers'];
if (\count($cache) > 128) {
unset($cache[key($cache)]);
}
}
}
/**
* Parse head.
*
* @return void
*/
protected function parseGet()
{
static $cache = [];
$query_string = $this->queryString();
$this->_data['get'] = array();
if ($query_string === '') {
return;
}
$cacheable = static::$_enableCache && !isset($query_string[1024]);
if ($cacheable && isset($cache[$query_string])) {
$this->_data['get'] = $cache[$query_string];
return;
}
\parse_str($query_string, $this->_data['get']);
if ($cacheable) {
$cache[$query_string] = $this->_data['get'];
if (\count($cache) > 256) {
unset($cache[key($cache)]);
}
}
}
/**
* Parse post.
*
* @return void
*/
protected function parsePost()
{
static $cache = [];
$this->_data['post'] = $this->_data['files'] = array();
$content_type = $this->header('content-type', '');
if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) {
$http_post_boundary = '--' . $match[1];
$this->parseUploadFiles($http_post_boundary);
return;
}
$body_buffer = $this->rawBody();
if ($body_buffer === '') {
return;
}
$cacheable = static::$_enableCache && !isset($body_buffer[1024]);
if ($cacheable && isset($cache[$body_buffer])) {
$this->_data['post'] = $cache[$body_buffer];
return;
}
if (\preg_match('/\bjson\b/i', $content_type)) {
$this->_data['post'] = (array) json_decode($body_buffer, true);
} else {
\parse_str($body_buffer, $this->_data['post']);
}
if ($cacheable) {
$cache[$body_buffer] = $this->_data['post'];
if (\count($cache) > 256) {
unset($cache[key($cache)]);
}
}
}
/**
* Parse upload files.
*
* @param string $http_post_boundary
* @return void
*/
protected function parseUploadFiles($http_post_boundary)
{
$http_post_boundary = \trim($http_post_boundary, '"');
$buffer = $this->_buffer;
$post_encode_string = '';
$files_encode_string = '';
$files = [];
$boday_position = strpos($buffer, "\r\n\r\n") + 4;
$offset = $boday_position + strlen($http_post_boundary) + 2;
$max_count = static::$maxFileUploads;
while ($max_count-- > 0 && $offset) {
$offset = $this->parseUploadFile($http_post_boundary, $offset, $post_encode_string, $files_encode_string, $files);
}
if ($post_encode_string) {
parse_str($post_encode_string, $this->_data['post']);
}
if ($files_encode_string) {
parse_str($files_encode_string, $this->_data['files']);
\array_walk_recursive($this->_data['files'], function (&$value) use ($files) {
$value = $files[$value];
});
}
}
/**
* @param $boundary
* @param $section_start_offset
* @return int
*/
protected function parseUploadFile($boundary, $section_start_offset, &$post_encode_string, &$files_encode_str, &$files)
{
$file = [];
$boundary = "\r\n$boundary";
$section_end_offset = \strpos($this->_buffer, $boundary, $section_start_offset);
if (!$section_end_offset) {
return 0;
}
$content_lines_end_offset = \strpos($this->_buffer, "\r\n\r\n", $section_start_offset);
if (!$content_lines_end_offset || $content_lines_end_offset + 4 > $section_end_offset) {
return 0;
}
$content_lines_str = \substr($this->_buffer, $section_start_offset, $content_lines_end_offset - $section_start_offset);
$content_lines = \explode("\r\n", trim($content_lines_str . "\r\n"));
$boundary_value = \substr($this->_buffer, $content_lines_end_offset + 4, $section_end_offset - $content_lines_end_offset - 4);
$upload_key = false;
foreach ($content_lines as $content_line) {
if (!\strpos($content_line, ': ')) {
return 0;
}
list($key, $value) = \explode(': ', $content_line);
switch (strtolower($key)) {
case "content-disposition":
// Is file data.
if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) {
$error = 0;
$tmp_file = '';
$size = \strlen($boundary_value);
$tmp_upload_dir = HTTP::uploadTmpDir();
if (!$tmp_upload_dir) {
$error = UPLOAD_ERR_NO_TMP_DIR;
} else if ($boundary_value === '') {
$error = UPLOAD_ERR_NO_FILE;
} else {
$tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.');
if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) {
$error = UPLOAD_ERR_CANT_WRITE;
}
}
$upload_key = $match[1];
// Parse upload files.
$file = [
'name' => $match[2],
'tmp_name' => $tmp_file,
'size' => $size,
'error' => $error,
'type' => null,
];
break;
} // Is post field.
else {
// Parse $_POST.
if (\preg_match('/name="(.*?)"$/', $value, $match)) {
$k = $match[1];
$post_encode_string .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&';
}
return $section_end_offset + \strlen($boundary) + 2;
}
break;
case "content-type":
$file['type'] = \trim($value);
break;
}
}
if ($upload_key === false) {
return 0;
}
$files_encode_str .= \urlencode($upload_key) . '=' . \count($files) . '&';
$files[] = $file;
return $section_end_offset + \strlen($boundary) + 2;
}
/**
* Create session id.
*
* @return string
*/
protected static function createSessionId()
{
return \bin2hex(\pack('d', \microtime(true)) . random_bytes(8));
}
/**
* Setter.
*
* @param string $name
* @param mixed $value
* @return void
*/
public function __set($name, $value)
{
$this->properties[$name] = $value;
}
/**
* Getter.
*
* @param string $name
* @return mixed|null
*/
public function __get($name)
{
return isset($this->properties[$name]) ? $this->properties[$name] : null;
}
/**
* Isset.
*
* @param string $name
* @return bool
*/
public function __isset($name)
{
return isset($this->properties[$name]);
}
/**
* Unset.
*
* @param string $name
* @return void
*/
public function __unset($name)
{
unset($this->properties[$name]);
}
/**
* __toString.
*/
public function __toString()
{
return $this->_buffer;
}
/**
* __destruct.
*
* @return void
*/
public function __destruct()
{
if (isset($this->_data['files'])) {
\clearstatcache();
\array_walk_recursive($this->_data['files'], function($value, $key){
if ($key === 'tmp_name') {
if (\is_file($value)) {
\unlink($value);
}
}
});
}
}
}

Some files were not shown because too many files have changed in this diff Show More