Compare commits

..

24 Commits
1.0.0 ... 1.1.2

Author SHA1 Message Date
whale
3c41d17802 fix a bug 2020-04-26 17:25:41 +08:00
whale
4ba5e3fc57 add static.html 2020-04-26 17:16:49 +08:00
whale
920680ee3d add static file server and fix root mapping bug 2020-04-26 17:15:27 +08:00
whale
c632977ca1 update value comment 2020-04-26 16:04:02 +08:00
whale
94834c6625 update for class Annotation of Middleware 2020-04-26 15:56:06 +08:00
whale
e3ffeec782 update for IDE support 2020-04-26 15:08:09 +08:00
whale
438a204751 Merge remote-tracking branch 'origin/master' 2020-04-26 15:01:31 +08:00
whale
b0331f6346 fix some stupid bug 2020-04-26 15:01:18 +08:00
Whale
0cbb81788e Update README.md 2020-04-19 10:19:48 +08:00
Whale
7173da9ad2 Update README.md 2020-04-18 19:39:54 +08:00
Whale
302e2c60da Update README.md 2020-04-18 18:09:37 +08:00
whale
87e637f759 fix some bug and add HTTP image upload 2020-04-17 16:51:33 +08:00
whale
1d2aaf3c99 Normalization of Context class 2020-04-15 10:55:10 +08:00
whale
676527205f update README.md 2020-04-15 09:56:27 +08:00
whale
b560246efb add context() fetch data mode
enable coroutine override
2020-04-14 23:46:42 +08:00
whale
c1f720a0b3 update README.md 2020-03-29 16:31:10 +08:00
whale
9a28126765 add Middleware and release version 1.1.0 2020-03-29 16:29:02 +08:00
whale
c2fcdf9668 add Middleware 2020-03-25 22:41:47 +08:00
whale
6861d27629 add Middleware 2020-03-25 18:35:16 +08:00
whale
50a64d2d0b fix websocket close event 2020-03-20 14:50:12 +08:00
whale
80ec6ad030 update README.md 2020-03-19 18:34:43 +08:00
whale
a8ee9ee9c2 update README.md 2020-03-19 18:29:33 +08:00
whale
67a62415a0 update README.md 2020-03-19 18:27:55 +08:00
whale
4187bab913 add global_function and ZMRequest class 2020-03-19 17:43:27 +08:00
34 changed files with 806 additions and 99 deletions

View File

@@ -2,14 +2,14 @@
[![作者QQ](https://img.shields.io/badge/作者QQ-627577391-orange.svg)]()
[![zhamao License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
[![版本](https://img.shields.io/badge/version-2020.3.2-green.svg)]()
[![版本](https://img.shields.io/badge/version-1.1-green.svg)]()
[![this counter](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/this.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=this)
[![goto counter](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/goto.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=goto)
[![TODO counter](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/TODO.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO)
一个异步、多平台兼容的 **聊天机器人** 框架。
<img src="./resources/images/logo.png" height = "200" alt="炸毛框架" align=center/>
<img src="https://avatars0.githubusercontent.com/u/48620312" height = "200" alt="炸毛框架" align=center/>
## 简介
zhamao-framework 是一个基于 酷Q 的 PHP Swoole 的机器人框架,它会对 QQ 机器人收到的消息进行解析处理,并以模块化的形式进行开发,来完成机器人的自然语言对话等功能。
@@ -18,6 +18,9 @@ zhamao-framework 是一个基于 酷Q 的 PHP Swoole 的机器人框架,它会
除了起到解析消息的作用,炸毛框架 还提供了完整的 WebSocket + HTTP 服务器,你还能用此框架构建出高性能的 API 接口服务器。
## 开始
你可以使用 GitHub 的 `Use This Template` 功能快速将本项目克隆到你的公开或私有仓库,也可以直接 clone 本项目到本地私有开发。
## 文档
本项目文档正在努力编写中。
@@ -38,18 +41,40 @@ Pages[https://framework.zhamao.xin/](https://framework.zhamao.xin/)
| 模块名称 | 说明 | 模块地址 |
| ------------------ | -------------------------------- | ------------------------------------------------------------ |
| 微信公众号兼容模块 | 为框架提供微信公众号订阅号兼容层 | [zhamao-wechat-patch](https://github.com/zhamao-robot/zhamao-wechat-patch) |
| 通用模块 | 图片上传和下载模块 | [zhamao-general-tools](https://github.com/zhamao-robot/zhamao-general-tools) |
## 计划开发内容
- [ ] WebSocket测试脚本客户端
- [X] Session 和中间层管理模块
- [ ] 支持本地和远程两种方式的定时器(计划任务)
- [ ] 常驻服务脚本
- [ ] 一些常用的通用 API 例如经济(用户积分、亲密度等)的模块
- [ ] 图灵机器人/腾讯AI 聊天模块
- [ ] 分词模块(可能会放弃计划,因为目前好用的分词都是其他语言的)
- [ ] HTTP 过滤器、Auth 模块、完整的 MVC 兼容(可能会放弃计划,因为框架主打机器人开发)
- [ ] Redis 连接池或开箱即用的相应功能内置
- [ ] 2.0 版本抛弃 `ModBase` 继承结构,完全使用上下文代替
- [ ] 更好的 Logger稳定和漂亮的控制台输出
- [ ] 日志服务
- [ ] 模块支持 Phar 打包(可能会比较靠后支持)
- [ ] 兼容面向过程的模块编写方案(可能会比较靠后支持)
- [ ] 完整的单元测试(如果有需求则尽快开发)
## 从 cqbot-swoole 升级
目前新的框架采用了全新的注解机制,所以旧版的框架上写的模块到新框架需要重新编写。当然为了减少工作量,新的框架也最大限度地保留了旧版框架编写的风格,一般情况下根据新版框架的文档仅需修改少量地方即可完成重写。
旧版框架并入了 `old` 分支,如果想继续使用旧版框架请移步分支。升级过程中如果遇到问题可以找作者。
## 贡献
## 贡献和捐赠
如果你在使用过程中发现任何问题,可以提交 Issue 或自行 Fork 后修改并提交 Pull Request。目前项目仅一人维护耗费精力较大所以非常欢迎对框架的贡献。
本项目为作者闲暇时间开发,如果觉得好用,不妨进行捐助~你的捐助会让我更加有动力完善插件,感谢你的支持!
我们会将捐赠的资金用于本项目驱动的炸毛机器人和框架文档的服务器开销上。
### 支付宝
![支付宝二维码](/resources/images/alipay_img.jpg)
## 关于
框架和 SDK 是 炸毛机器人 项目的核心框架开源部分。炸毛机器人3276124472是作者写的一个高性能机器人曾获全国计算机设计大赛一等奖。
@@ -57,4 +82,4 @@ Pages[https://framework.zhamao.xin/](https://framework.zhamao.xin/)
本项目在更行内容时,请及时关注 GitHub 动态,更新前请将自己的模块代码做好备份。
项目框架采用 Apache-2.0 协议开源,在分发或重写修改等操作时需遵守协议。项目模块部分(`Module` 文件夹) 在非借鉴框架内代码时可不遵守 Apache-2.0 协议进行分发和修改(声明版权)。
项目框架采用 Apache-2.0 协议开源,在分发或重写修改等操作时需遵守协议。项目模块部分(`Module` 文件夹) 在非借鉴框架内代码时可不遵守 Apache-2.0 协议进行分发和修改(声明版权)。

View File

@@ -37,8 +37,15 @@ switch ($argv[1] ?? '') {
}
$loader = new FrameworkLoader($argv);
break;
case '--help':
case '-h':
echo "\nUsage: ".$argv[0]." [OPTION]\n";
echo "\nzhamao-framework start script, provides several startup arguments.";
echo "\n\n -h, --help\t\tShow this help menu";
echo "\n framework, server\tstart main framework, this is default option\n\n";
break;
default:
echo "Unknown option \"{$argv[1]}\"!\n";
echo "Unknown option \"{$argv[1]}\"!\n\"--help\" for more information\n";
break;
}

141
config/file_header.json Normal file
View File

@@ -0,0 +1,141 @@
{
"ai": "application/postscript",
"aif": "audio/x-aiff",
"aifc": "audio/x-aiff",
"aiff": "audio/x-aiff",
"asc": "text/plain",
"au": "audio/basic",
"avi": "video/x-msvideo",
"bcpio": "application/x-bcpio",
"bin": "application/octet-stream",
"bmp": "image/bmp",
"cdf": "application/x-netcdf",
"class": "application/octet-stream",
"cpio": "application/x-cpio",
"cpt": "application/mac-compactpro",
"csh": "application/x-csh",
"css": "text/css",
"dcr": "application/x-director",
"dir": "application/x-director",
"djv": "image/vnd.djvu",
"djvu": "image/vnd.djvu",
"dll": "application/octet-stream",
"dms": "application/octet-stream",
"doc": "application/msword",
"dvi": "application/x-dvi",
"dxr": "application/x-director",
"eps": "application/postscript",
"etx": "text/x-setext",
"exe": "application/octet-stream",
"ez": "application/andrew-inset",
"gif": "image/gif",
"gtar": "application/x-gtar",
"hdf": "application/x-hdf",
"hqx": "application/mac-binhex40",
"htm": "text/html",
"html": "text/html",
"ice": "x-conference/x-cooltalk",
"ief": "image/ief",
"iges": "model/iges",
"igs": "model/iges",
"jpe": "image/jpeg",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"js": "application/x-javascript",
"kar": "audio/midi",
"latex": "application/x-latex",
"lha": "application/octet-stream",
"lzh": "application/octet-stream",
"m3u": "audio/x-mpegurl",
"man": "application/x-troff-man",
"me": "application/x-troff-me",
"mesh": "model/mesh",
"mid": "audio/midi",
"midi": "audio/midi",
"mif": "application/vnd.mif",
"mov": "video/quicktime",
"movie": "video/x-sgi-movie",
"mp2": "audio/mpeg",
"mp3": "audio/mpeg",
"mpe": "video/mpeg",
"mpeg": "video/mpeg",
"mpg": "video/mpeg",
"mpga": "audio/mpeg",
"ms": "application/x-troff-ms",
"msh": "model/mesh",
"mxu": "video/vnd.mpegurl",
"nc": "application/x-netcdf",
"oda": "application/oda",
"pbm": "image/x-portable-bitmap",
"pdb": "chemical/x-pdb",
"pdf": "application/pdf",
"pgm": "image/x-portable-graymap",
"pgn": "application/x-chess-pgn",
"png": "image/png",
"pnm": "image/x-portable-anymap",
"ppm": "image/x-portable-pixmap",
"ppt": "application/vnd.ms-powerpoint",
"ps": "application/postscript",
"qt": "video/quicktime",
"ra": "audio/x-realaudio",
"ram": "audio/x-pn-realaudio",
"ras": "image/x-cmu-raster",
"rgb": "image/x-rgb",
"rm": "audio/x-pn-realaudio",
"roff": "application/x-troff",
"rpm": "audio/x-pn-realaudio-plugin",
"rtf": "text/rtf",
"rtx": "text/richtext",
"sgm": "text/sgml",
"sgml": "text/sgml",
"sh": "application/x-sh",
"shar": "application/x-shar",
"silo": "model/mesh",
"sit": "application/x-stuffit",
"skd": "application/x-koan",
"skm": "application/x-koan",
"skp": "application/x-koan",
"skt": "application/x-koan",
"smi": "application/smil",
"smil": "application/smil",
"snd": "audio/basic",
"so": "application/octet-stream",
"spl": "application/x-futuresplash",
"src": "application/x-wais-source",
"sv4cpio": "application/x-sv4cpio",
"sv4crc": "application/x-sv4crc",
"swf": "application/x-shockwave-flash",
"t": "application/x-troff",
"tar": "application/x-tar",
"tcl": "application/x-tcl",
"tex": "application/x-tex",
"texi": "application/x-texinfo",
"texinfo": "application/x-texinfo",
"tif": "image/tiff",
"tiff": "image/tiff",
"tr": "application/x-troff",
"tsv": "text/tab-separated-values",
"txt": "text/plain",
"ustar": "application/x-ustar",
"vcd": "application/x-cdlink",
"vrml": "model/vrml",
"wav": "audio/x-wav",
"wbmp": "image/vnd.wap.wbmp",
"wbxml": "application/vnd.wap.wbxml",
"wml": "text/vnd.wap.wml",
"wmlc": "application/vnd.wap.wmlc",
"wmls": "text/vnd.wap.wmlscript",
"wmlsc": "application/vnd.wap.wmlscriptc",
"wrl": "model/vrml",
"xbm": "image/x-xbitmap",
"xht": "application/xhtml+xml",
"xhtml": "application/xhtml+xml",
"xls": "application/vnd.ms-excel",
"xml": "text/xml",
"xpm": "image/x-xpixmap",
"xsl": "text/xml",
"xwd": "image/x-xwindowdump",
"xyz": "chemical/x-xyz",
"zip": "application/zip",
"": "application/octet-stream"
}

View File

@@ -64,4 +64,16 @@ $config['init_atomics'] = [
/** 自动保存的缓存保存时间(秒) */
$config['auto_save_interval'] = 900;
return $config;
/** 上下文接口类 implemented from ContextInterface */
$config['context_class'] = \ZM\Context\Context::class;
/** 静态文件访问 */
$config['static_file_server'] = [
'status' => false,
'document_root' => WORKING_DIR . '/resources/html',
'document_index' => [
'index.html'
]
];
return $config;

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>This is example</title>
</head>
<body>
<h1>Hello zhamao!</h1>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,7 @@
<?php
//这里写你的全局函数
function phptest(){
echo "Nothing.\n";
}

View File

@@ -3,6 +3,7 @@
namespace Framework;
use Swoole\Runtime;
use ZM\Event\EventHandler;
use Exception;
use Swoole\WebSocket\Server;
@@ -38,6 +39,7 @@ class FrameworkLoader
chdir(__DIR__ . '/../..');
define('WORKING_DIR', getcwd());
Runtime::enableCoroutine();
$this->requireGlobalFunctions();
$this->registerAutoloader('classLoader');
self::$settings = new GlobalConfig();
@@ -108,4 +110,4 @@ class FrameworkLoader
self::$run_time = microtime(true);
EventHandler::callSwooleEvent("WorkerStart", $server, $worker_id);
}
}
}

View File

@@ -18,8 +18,7 @@ class GlobalConfig
public $success = false;
public function __construct() {
/** @noinspection PhpIncludeInspection */
include_once WORKING_DIR.'/config/global.php';
include_once WORKING_DIR . '/config/global.php';
global $config;
$this->success = true;
$this->config = $config;
@@ -30,4 +29,8 @@ class GlobalConfig
if ($r === null) return null;
return $r;
}
}
public function getAll() {
return $this->config;
}
}

View File

@@ -46,13 +46,12 @@ class ZMBuf
// Atomic可跨进程读写的原子计数任何地方均可使用
/** @var null|swoole_atomic */
static $info_level = null;//保存log等级的原子计数
/** @var swoole_atomic $reload_time */
public static $events = [];
/** @var Atomic[] */
public static $atomics;
public static $req_mapping = [];
public static $config = [];
public static $context = [];
static function get($name, $default = null) {
return self::$cache[$name] ?? $default;
@@ -100,7 +99,7 @@ class ZMBuf
}
static function config($config_name) {
return self::$config ?? null;
return self::$config[$config_name] ?? null;
}
public static function resetCache() {
@@ -117,4 +116,4 @@ class ZMBuf
self::$atomics[$k] = new Atomic($v);
}
}
}
}

View File

@@ -1,5 +1,9 @@
<?php
use Framework\Console;
use Framework\ZMBuf;
use ZM\Context\ContextInterface;
function classLoader($p) {
$filepath = getClassPath($p);
if ($filepath === null)
@@ -8,7 +12,7 @@ function classLoader($p) {
try {
require_once $filepath;
} catch (Exception $e) {
echo "Error when finding class: ".$p.PHP_EOL;
echo "Error when finding class: " . $p . PHP_EOL;
die;
}
}
@@ -143,4 +147,35 @@ function matchArgs($pattern, $context) {
}
return $result;
} else return false;
}
}
function set_coroutine_params($array) {
$cid = Co::getCid();
if ($cid == -1) die("Cannot set coroutine params at none coroutine mode.");
ZMBuf::$context[$cid] = $array;
foreach (ZMBuf::$context as $c => $v) {
if (!Co::exists($c)) unset(ZMBuf::$context[$c]);
}
}
/**
* @return ContextInterface|null
*/
function context() {
$cid = Co::getCid();
$c_class = ZMBuf::globals("context_class");
if (isset(ZMBuf::$context[$cid])) {
return new $c_class(ZMBuf::$context[$cid], $cid);
} else {
while (($pcid = Co::getPcid($cid)) !== -1) {
if (isset(ZMBuf::$context[$cid])) return new $c_class(ZMBuf::$context[$cid], $cid);
else $cid = $pcid;
}
return null;
}
}
function debug($msg) {
if (ZMBuf::$atomics["info_level"]->get() == 1)
Console::log(date("[H:i:s ") . "DEBUG] " . $msg, 'gray');
}

View File

@@ -6,7 +6,7 @@ namespace Module\Example;
use Framework\Console;
use ZM\Annotation\CQ\CQCommand;
use ZM\Annotation\Http\Controller;
use ZM\Annotation\Http\Middleware;
use ZM\Annotation\Http\RequestMapping;
use ZM\Annotation\Swoole\SwooleEventAt;
use ZM\Connection\CQConnection;
@@ -15,7 +15,6 @@ use ZM\ModBase;
/**
* Class Hello
* @package Module\Example
* @Controller("/view")
*/
class Hello extends ModBase
{
@@ -34,17 +33,11 @@ class Hello extends ModBase
}
/**
* @RequestMapping("/test/{ping}")
*/
public function ping($param){
return "You input id is: ".$param["ping"];
}
/**
* @RequestMapping("/test/pong")
* @RequestMapping("/test/ping")
* @Middleware("timer")
*/
public function pong(){
$this->response->end("ping");
return "pong";
}
/**
@@ -54,4 +47,4 @@ class Hello extends ModBase
Console::info("Unknown connection , I will close it.");
$this->connection->close();
}
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Module\Middleware;
use Framework\Console;
use ZM\Annotation\Http\After;
use ZM\Annotation\Http\Before;
use ZM\Annotation\Http\MiddlewareClass;
use ZM\Http\MiddlewareInterface;
/**
* Class AuthMiddleware
* 示例中间件:用于统计路由函数运行时间用的
* @package Module\Middleware
* @MiddlewareClass()
*/
class TimerMiddleware implements MiddlewareInterface
{
private $starttime;
/**
* @Before()
* @return bool
*/
public function onBefore() {
$this->starttime = microtime(true);
return true;
}
/**
* @After()
*/
public function onAfter() {
Console::info("Using " . round((microtime(true) - $this->starttime) * 1000, 2) . " ms.");
}
public function getName() { return "timer"; }
}

View File

@@ -3,25 +3,20 @@
namespace ZM\Annotation;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\AnnotationReader;
use Framework\ZMBuf;
use Doctrine\Common\Annotations\{AnnotationException, AnnotationReader};
use Framework\{Console, ZMBuf};
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ZM\Annotation\CQ\{CQAfter, CQBefore, CQCommand, CQMessage, CQMetaEvent, CQNotice, CQRequest};
use ZM\Annotation\Http\Controller;
use ZM\Annotation\Http\RequestMapping;
use ZM\Annotation\Http\{After, Before, Controller, HandleException, Middleware, MiddlewareClass, RequestMapping};
use ZM\Annotation\Interfaces\CustomAnnotation;
use ZM\Annotation\Interfaces\Level;
use ZM\Annotation\Module\Closed;
use ZM\Annotation\Module\InitBuffer;
use ZM\Annotation\Module\SaveBuffer;
use ZM\Annotation\Swoole\OnStart;
use ZM\Annotation\Swoole\SwooleEventAfter;
use ZM\Annotation\Swoole\SwooleEventAt;
use ZM\Annotation\Module\{Closed, InitBuffer, SaveBuffer};
use ZM\Annotation\Swoole\{OnStart, SwooleEventAfter, SwooleEventAt};
use ZM\Annotation\Interfaces\Rule;
use ZM\Connection\WSConnection;
use ZM\Http\MiddlewareInterface;
use ZM\Utils\DataProvider;
class AnnotationParser
@@ -31,8 +26,7 @@ class AnnotationParser
* @throws ReflectionException
* @throws AnnotationException
*/
public static function registerMods()
{
public static function registerMods() {
self::loadAnnotationClasses();
$all_class = getAllClasses(WORKING_DIR . "/src/Module/", "Module");
ZMBuf::$req_mapping[0] = [
@@ -46,6 +40,7 @@ class AnnotationParser
$class_prefix = '';
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
$class_annotations = $reader->getClassAnnotations($reflection_class);
$middleware_addon = null;
foreach ($class_annotations as $vs) {
if ($vs instanceof Closed) {
continue 2;
@@ -55,6 +50,34 @@ class AnnotationParser
DataProvider::addSaveBuffer($vs->buf_name, $vs->sub_folder);
} elseif ($vs instanceof InitBuffer) {
ZMBuf::set($vs->buf_name, []);
} elseif ($vs instanceof MiddlewareClass) {
Console::info("正在注册中间件 " . $vs->class);
$result = [
"class" => "\\" . $reflection_class->getName()
];
foreach ($methods as $vss) {
if ($vss->getName() == "getName") {
/** @var MiddlewareInterface $tmp */
$tmp = new $v();
$result["name"] = $tmp->getName();
continue;
}
$method_annotations = $reader->getMethodAnnotations($vss);
foreach ($method_annotations as $vsss) {
if ($vss instanceof Rule) $vss = self::registerRuleEvent($vsss, $vss, $reflection_class);
else $vss = self::registerMethod($vsss, $vss, $reflection_class);
//echo get_class($vsss) . PHP_EOL;
if ($vsss instanceof Before) $result["before"] = $vsss->method;
if ($vsss instanceof After) $result["after"] = $vsss->method;
if ($vsss instanceof HandleException) {
$result["exceptions"][$vsss->class_name] = $vsss->method;
}
}
}
ZMBuf::$events[MiddlewareClass::class][$result["name"]] = $result;
continue 2;
} elseif ($vs instanceof Middleware) {
$middleware_addon = $vs;
}
}
foreach ($methods as $vs) {
@@ -70,13 +93,15 @@ class AnnotationParser
elseif ($vss instanceof CQRequest) ZMBuf::$events[CQRequest::class][] = $vss;
elseif ($vss instanceof CQMetaEvent) ZMBuf::$events[CQMetaEvent::class][] = $vss;
elseif ($vss instanceof CQCommand) ZMBuf::$events[CQCommand::class][] = $vss;
elseif ($vss instanceof RequestMapping) self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix);
elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss;
elseif ($vss instanceof RequestMapping) {
self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix);
if($middleware_addon !== null)
ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method] = $middleware_addon->middleware;
} elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss;
elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss;
elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss;
elseif ($vss instanceof OnStart) {
ZMBuf::$events[OnStart::class][]=$vss;
}
elseif ($vss instanceof OnStart) ZMBuf::$events[OnStart::class][] = $vss;
elseif ($vss instanceof Middleware) ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method] = $vss->middleware;
}
}
}
@@ -84,7 +109,7 @@ class AnnotationParser
ZMBuf::$req_mapping = $tree[0];
//给支持level的排个序
foreach (ZMBuf::$events as $class_name => $v) {
if ((new $class_name()) instanceof Level) {
if (is_a($class_name, Level::class, true)) {
for ($i = 0; $i < count(ZMBuf::$events[$class_name]) - 1; ++$i) {
for ($j = 0; $j < count(ZMBuf::$events[$class_name]) - $i - 1; ++$j) {
$l1 = ZMBuf::$events[$class_name][$j]->level;
@@ -100,8 +125,7 @@ class AnnotationParser
}
}
private static function getRuleCallback($rule_str)
{
private static function getRuleCallback($rule_str) {
$func = null;
$rule = $rule_str;
if ($rule != "") {
@@ -179,23 +203,20 @@ class AnnotationParser
return $func;
}
private static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class)
{
private static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
$vss->callback = self::getRuleCallback($vss->getRule());
$vss->method = $method->getName();
$vss->class = $class->getName();
return $vss;
}
private static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class)
{
private static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
$vss->method = $method->getName();
$vss->class = $class->getName();
return $vss;
}
private static function registerRequestMapping(RequestMapping $vss, ReflectionMethod $method, ReflectionClass $class, string $prefix)
{
private static function registerRequestMapping(RequestMapping $vss, ReflectionMethod $method, ReflectionClass $class, string $prefix) {
$array = ZMBuf::$req_mapping;
$uid = count($array);
$prefix_exp = explode("/", $prefix);
@@ -211,9 +232,9 @@ class AnnotationParser
}
}
if ($prefix_exp == [] && $route_exp == []) {
$array[$uid - 1]['method'] = $method->getName();
$array[$uid - 1]['class'] = $class->getName();
$array[$uid - 1]['request_method'] = $vss->request_method;
$array[0]['method'] = $method->getName();
$array[0]['class'] = $class->getName();
$array[0]['request_method'] = $vss->request_method;
ZMBuf::$req_mapping = $array;
return;
}
@@ -263,8 +284,7 @@ class AnnotationParser
ZMBuf::$req_mapping = $array;
}
private static function loadAnnotationClasses()
{
private static function loadAnnotationClasses() {
$class = getAllClasses(WORKING_DIR . "/src/ZM/Annotation/", "ZM\\Annotation");
foreach ($class as $v) {
$s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php";
@@ -277,8 +297,7 @@ class AnnotationParser
}
}
public static function genTree($items)
{
public static function genTree($items) {
$tree = array();
foreach ($items as $item)
if (isset($items[$item['pid']]))
@@ -287,4 +306,4 @@ class AnnotationParser
$tree[] = &$items[$item['id']];
return $tree;
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace ZM\Annotation\Http;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class After
* @package ZM\Annotation\Http
* @Annotation
* @Target("METHOD")
*/
class After extends AnnotationBase
{
}

View File

@@ -0,0 +1,19 @@
<?php
namespace ZM\Annotation\Http;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class Before
* @package ZM\Annotation\Http
* @Annotation
* @Target("METHOD")
*/
class Before extends AnnotationBase
{
}

View File

@@ -0,0 +1,23 @@
<?php
namespace ZM\Annotation\Http;
use Doctrine\Common\Annotations\Annotation\Target;
use Exception;
use ZM\Annotation\AnnotationBase;
/**
* Class HandleException
* @package ZM\Annotation\Http
* @Annotation
* @Target("METHOD")
*/
class HandleException extends AnnotationBase
{
/**
* @var string
*/
public $class_name = Exception::class;
}

View File

@@ -0,0 +1,24 @@
<?php
namespace ZM\Annotation\Http;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class Middleware
* @package ZM\Annotation\Http
* @Annotation
* @Target("ALL")
*/
class Middleware extends AnnotationBase
{
/**
* @var string
* @Required()
*/
public $middleware;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace ZM\Annotation\Http;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class MiddlewareClass
* @package ZM\Annotation\Http
* @Annotation
* @Target("CLASS")
*/
class MiddlewareClass extends AnnotationBase
{
}

View File

@@ -0,0 +1,71 @@
<?php
namespace ZM\Context;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use swoole_server;
use ZM\Http\Response;
class Context implements ContextInterface
{
private $server = null;
private $frame = null;
private $data = null;
private $request = null;
private $response = null;
private $cid;
public function __construct($param, $cid) {
if (isset($param["server"])) $this->server = $param["server"];
if (isset($param["frame"])) $this->frame = $param["frame"];
if (isset($param["data"])) $this->data = $param["data"];
if (isset($param["request"])) $this->request = $param["request"];
if (isset($param["response"])) $this->response = $param["response"];
$this->cid = $cid;
}
/**
* @return swoole_server|null
*/
public function getServer() {
return $this->server;
}
/**
* @return Frame|null
*/
public function getFrame() {
return $this->frame;
}
/**
* @return array|null
*/
public function getData() {
return $this->data;
}
/**
* @return Request|null
*/
public function getRequest() {
return $this->request;
}
/**
* @return Response|null
*/
public function getResponse() {
return $this->response;
}
/**
* @return int|null
*/
public function getCid() {
return $this->cid;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace ZM\Context;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
use ZM\Http\Response;
interface ContextInterface
{
public function __construct($param, $cid);
/** @return Server */
public function getServer();
/** @return Frame */
public function getFrame();
/** @return mixed */
public function getData();
/** @return int */
public function getCid();
/** @return Response */
public function getResponse();
/** @return Request */
public function getRequest();
}

View File

@@ -69,7 +69,7 @@ class DB
}
}
public static function rawQuery(string $line, $params) {
public static function rawQuery(string $line, $params = []) {
if (ZMBuf::get("sql_log") === true) {
$starttime = microtime(true);
}
@@ -117,4 +117,8 @@ class DB
return false;
}
}
}
public static function isTableExists($table) {
return in_array($table, self::$table_list);
}
}

View File

@@ -23,6 +23,6 @@ class InsertBody
}
public function save() {
DB::rawQuery('INSERT INTO ' . $this->table->getTableName() . ' VALUES ('.implode(',', array_fill(0, 5, '?')).')', $this->row);
DB::rawQuery('INSERT INTO ' . $this->table->getTableName() . ' VALUES ('.implode(',', array_fill(0, count($this->row), '?')).')', $this->row);
}
}
}

View File

@@ -44,10 +44,12 @@ class SelectBody
return $this->fetchAll()[0] ?? null;
}
public function value() {
public function value($key = null) {
$r = $this->fetchFirst();
if ($r === null) return null;
return current($r);
if ($key === null)
return current($r);
else return $r[$key] ?? null;
}
public function execute() {
@@ -85,4 +87,4 @@ class SelectBody
}
return [$msg, $array ?? []];
}
}
}

View File

@@ -5,6 +5,7 @@ namespace ZM\Event;
use Co;
use Error;
use Exception;
use Framework\Console;
use Framework\ZMBuf;
@@ -28,6 +29,9 @@ class EventHandler
ZMUtil::stop();
return;
} catch(Error $e) {
var_export($e);
ZMUtil::stop();
}
break;
case "message":
@@ -39,6 +43,9 @@ class EventHandler
} catch (Exception $e) {
/** @var Response $param1 */
$param1->status(500);
Console::info($param0->server["remote_addr"].":".$param0->server["remote_port"].
" [".$param1->getStatusCode()."] ".$param0->server["request_uri"]
);
if (!$param1->isEnd()) $param1->end("Internal server error: " . $e->getMessage());
Console::error("Internal server error (500), caused by uncaught exception.");
Console::log($e->getTraceAsString(), "gray");
@@ -112,4 +119,4 @@ class EventHandler
ZMBuf::unsetByValue("sent_api", $req["echo"]);
}
}
}
}

View File

@@ -39,17 +39,19 @@ class MessageEvent implements SwooleEvent
*/
public function onActivate() {
ZMUtil::checkWait();
$conn = ConnectionManager::get($this->frame->fd);
set_coroutine_params(["server" => $this->server, "frame" => $this->frame, "connection" => $conn]);
try {
if (ConnectionManager::get($this->frame->fd)->getType() == "qq") {
if ($conn->getType() == "qq") {
$data = json_decode($this->frame->data, true);
if (isset($data["post_type"])) {
set_coroutine_params(["data" => $data, "connection" => $conn]);
EventHandler::callCQEvent($data, ConnectionManager::get($this->frame->fd), 0);
} else
EventHandler::callCQResponse($data);
}
foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) {
if (strtolower($v->type) == "message" && $this->parseSwooleRule($v)) {
$conn = ConnectionManager::get($this->frame->fd);
$c = $v->class;
/** @var ModBase $class */
$class = new $c(["server" => $this->server, "frame" => $this->frame, "connection" => $conn], ModHandleType::SWOOLE_MESSAGE);
@@ -91,4 +93,4 @@ class MessageEvent implements SwooleEvent
}
return true;
}
}
}

View File

@@ -5,10 +5,15 @@ namespace ZM\Event\Swoole;
use Closure;
use Doctrine\Common\Annotations\AnnotationException;
use Exception;
use Framework\Console;
use Framework\ZMBuf;
use Swoole\Http\Request;
use ZM\Annotation\Http\MiddlewareClass;
use ZM\Annotation\Swoole\SwooleEventAfter;
use ZM\Annotation\Swoole\SwooleEventAt;
use ZM\Http\MiddlewareInterface;
use ZM\Http\Response;
use ZM\ModBase;
use ZM\ModHandleType;
@@ -30,6 +35,10 @@ class RequestEvent implements SwooleEvent
$this->response = $response;
}
/**
* @return $this|SwooleEvent
* @throws Exception
*/
public function onActivate() {
ZMUtil::checkWait();
foreach (ZMBuf::globals("http_header") as $k => $v) {
@@ -55,9 +64,6 @@ class RequestEvent implements SwooleEvent
} elseif ($node["son"][0]["name"] == $r) {
$node = $node["son"][0];
continue;
} else {
$this->responseStatus(404);
return $this;
}
} elseif ($cnt >= 1) {
if (isset($node["param_route"])) {
@@ -76,20 +82,89 @@ class RequestEvent implements SwooleEvent
}
}
}
$this->responseStatus(404);
if (ZMBuf::globals("static_file_server")["status"]) {
$base_dir = ZMBuf::globals("static_file_server")["document_root"];
$base_index = ZMBuf::globals("static_file_server")["document_index"];
$uri = $this->request->server["request_uri"];
$path = realpath($base_dir . urldecode($uri));
if ($path !== false) {
if (is_dir($path)) $path = $path . '/';
$work = realpath(WORKING_DIR) . '/';
if (strpos($path, $work) !== 0) {
$this->responseStatus(403);
return $this;
}
if (is_dir($path)) {
foreach ($base_index as $vp) {
if (is_file($path . $vp)) {
Console::info("[200] " . $uri . " (static)");
$exp = strtolower(pathinfo($path . $vp)['extension'] ?? "unknown");
$this->response->setHeader("Content-Type", ZMBuf::config("file_header")[$exp] ?? "application/octet-stream");
$this->response->end(file_get_contents($path . $vp));
return $this;
}
}
} elseif (is_file($path)) {
Console::info("[200] " . $uri . " (static)");
$exp = strtolower(pathinfo($path)['extension'] ?? "unknown");
$this->response->setHeader("Content-Type", ZMBuf::config("file_header")[$exp] ?? "application/octet-stream");
$this->response->end(file_get_contents($path));
return $this;
}
}
}
$this->response->status(404);
$this->response->end(ZMUtil::getHttpCodePage(404));
return $this;
}
set_coroutine_params(["request" => $this->request, "response" => $this->response, "params" => $params]);
if (in_array(strtoupper($this->request->server["request_method"]), $node["request_method"] ?? [])) { //判断目标方法在不在里面
$c_name = $node["class"];
/** @var ModBase $class */
$class = new $c_name(["request" => $this->request, "response" => $this->response, "params" => $params], ModHandleType::SWOOLE_REQUEST);
$r = call_user_func_array([$class, $node["method"]], [$params]);
if (is_string($r) && !$this->response->isEnd()) $this->response->end($r);
if ($class->block_continue) return $this;
if ($this->response->isEnd()) return $this;
if (isset(ZMBuf::$events[MiddlewareInterface::class][$c_name][$node["method"]])) {
$middleware = ZMBuf::$events[MiddlewareInterface::class][$c_name][$node["method"]];
if (!isset(ZMBuf::$events[MiddlewareClass::class][$middleware])) throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$middleware}\"!");
$middleware = ZMBuf::$events[MiddlewareClass::class][$middleware];
$before = $middleware["class"];
$r = new $before();
$before_result = true;
if (isset($middleware["before"])) {
$before_result = call_user_func([$r, $middleware["before"]], $this->request, $this->response, $params);
if ($before_result !== false) $before_result = true;
}
if ($before_result) {
try {
/** @var ModBase $class */
$class = new $c_name(["request" => $this->request, "response" => $this->response, "params" => $params], ModHandleType::SWOOLE_REQUEST);
$result = call_user_func_array([$class, $node["method"]], [$params]);
if (is_string($result) && !$this->response->isEnd()) $this->response->end($result);
if (!$this->response->isEnd()) goto eventCall;
} catch (Exception $e) {
if (!isset($middleware["exceptions"])) throw $e;
foreach ($middleware["exceptions"] as $name => $method) {
if ($e instanceof $name) {
call_user_func([$r, $method], $e, $this->request, $this->response, $params);
return $this;
}
}
throw $e;
}
}
if (isset($middleware["after"])) {
call_user_func([$r, $middleware["after"]], $this->request, $this->response, $params);
return $this;
}
} else {
/** @var ModBase $class */
$class = new $c_name(["request" => $this->request, "response" => $this->response, "params" => $params], ModHandleType::SWOOLE_REQUEST);
$r = call_user_func_array([$class, $node["method"]], [$params]);
if (is_string($r) && !$this->response->isEnd()) $this->response->end($r);
if (!$this->response->isEnd()) goto eventCall;
}
}
eventCall:
foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) {
if (strtolower($v->type) == "request" && $this->parseSwooleRule($v)) {
$c = $v->class;
@@ -127,7 +202,7 @@ class RequestEvent implements SwooleEvent
}
private function parseSwooleRule($v) {
switch (explode(":",$v->rule)[0]) {
switch (explode(":", $v->rule)[0]) {
case "containsGet":
case "containsPost":
if ($v->callback instanceof Closure) return call_user_func($v->callback, $this->request);
@@ -141,4 +216,4 @@ class RequestEvent implements SwooleEvent
}
return true;
}
}
}

View File

@@ -8,6 +8,7 @@ use Framework\ZMBuf;
use Swoole\Server;
use ZM\Annotation\Swoole\SwooleEventAfter;
use ZM\Annotation\Swoole\SwooleEventAt;
use ZM\Connection\ConnectionManager;
use ZM\ModBase;
use ZM\ModHandleType;
use ZM\Utils\ZMUtil;
@@ -28,6 +29,8 @@ class WSCloseEvent implements SwooleEvent
*/
public function onActivate() {
ZMUtil::checkWait();
ConnectionManager::close($this->fd);
set_coroutine_params(["server" => $this->server, "fd" => $this->fd]);
foreach(ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) {
if(strtolower($v->type) == "close" && $this->parseSwooleRule($v)) {
$c = $v->class;
@@ -58,4 +61,4 @@ class WSCloseEvent implements SwooleEvent
private function parseSwooleRule($v) {
return true;
}
}
}

View File

@@ -55,6 +55,7 @@ class WSOpenEvent implements SwooleEvent
$this->conn = new $type_conn($this->server, $this->request->fd);
}
ZMBuf::$connect[$this->request->fd] = $this->conn;
set_coroutine_params(["server" => $this->server, "request" => $this->request, "connection" => $this->conn]);
foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) {
if (strtolower($v->type) == "open" && $this->parseSwooleRule($v) === true) {
$c = $v->class;
@@ -90,4 +91,4 @@ class WSOpenEvent implements SwooleEvent
}
return true;
}
}
}

View File

@@ -6,6 +6,7 @@ namespace ZM\Event\Swoole;
use Co;
use Doctrine\Common\Annotations\AnnotationException;
use Exception;
use ReflectionException;
use Swoole\Coroutine;
use Swoole\Timer;
@@ -14,6 +15,7 @@ use ZM\Annotation\AnnotationParser;
use ZM\Annotation\Swoole\OnStart;
use ZM\Annotation\Swoole\SwooleEventAfter;
use ZM\Connection\ConnectionManager;
use ZM\Context\ContextInterface;
use ZM\DB\DB;
use Framework\Console;
use Framework\GlobalConfig;
@@ -58,11 +60,11 @@ class WorkerStartEvent implements SwooleEvent
$name = explode(".", $v);
if (($prefix = end($name)) == "json") {
ZMBuf::$config[$name[0]] = json_decode(Co::readFile(WORKING_DIR . '/config/' . $v), true);
Console::info("已读取配置文件(json)" . $prefix);
Console::info("已读取配置文件:" . $v);
} elseif ($prefix == "php") {
ZMBuf::$config[$name[0]] = include_once WORKING_DIR . '/config/' . $v;
if (is_array(ZMBuf::$config[$name[0]]))
Console::info("已读取配置文件(php)" . $prefix);
Console::info("已读取配置文件:" . $v);
}
}
if (ZMBuf::globals("sql_config")["sql_host"] != "") {
@@ -94,6 +96,7 @@ class WorkerStartEvent implements SwooleEvent
$class = new $class_name(["server" => $this->server, "worker_id" => $this->worker_id], ModHandleType::SWOOLE_WORKER_START);
call_user_func_array([$class, $v->method], []);
}
set_coroutine_params(["server" => $this->server, "worker_id" => $this->worker_id]);
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
/** @var AnnotationBase $v */
if (strtolower($v->type) == "workerstart") {
@@ -120,6 +123,7 @@ class WorkerStartEvent implements SwooleEvent
/**
* @throws AnnotationException
* @throws ReflectionException
* @throws Exception
*/
private function loadAllClass() {
//加载phar包
@@ -144,6 +148,11 @@ class WorkerStartEvent implements SwooleEvent
//加载Custom目录下的自定义的内部类
ConnectionManager::registerCustomClass();
//加载自定义的全局函数
if(file_exists(WORKING_DIR."/src/Custom/global_function.php"))
require_once WORKING_DIR."/src/Custom/global_function.php";
$this->afterCheck();
}
private function setAutosaveTimer($globals) {
@@ -152,4 +161,14 @@ class WorkerStartEvent implements SwooleEvent
DataProvider::saveBuffer();
});
}
}
/**
* @throws Exception
*/
private function afterCheck() {
$context_class = ZMBuf::globals("context_class");
if(!is_a($context_class, ContextInterface::class, true)) {
throw new Exception("Context class must implemented from ContextInterface!");
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace ZM\Http;
interface MiddlewareInterface
{
public function getName();
}

View File

@@ -21,6 +21,7 @@ class Response
*/
private $response;
private $is_end = false;
private $status_code;
public function __construct(\Swoole\Http\Response $response) {
$this->response = $response;
@@ -90,9 +91,14 @@ class Response
* @return mixed
*/
public function status($http_code, $reason = null) {
$this->status_code = $http_code;
return $this->response->status($http_code, $reason);
}
public function getStatusCode() {
return $this->status_code ?? 200;
}
/**
* @param $http_code
* @param $reason
@@ -157,6 +163,11 @@ class Response
public function isEnd() { return $this->is_end; }
public function endWithStatus($status_code = 200, $content = null){
$this->status($status_code);
$this->end($content);
}
/**
* @param $filename
* @param $offset
@@ -226,4 +237,4 @@ class Response
}
}
}

View File

@@ -10,7 +10,6 @@ use Framework\ZMBuf;
class DataProvider
{
const HEADER_TYPE = '{"ai":"application/postscript","aif":"audio/x-aiff","aifc":"audio/x-aiff","aiff":"audio/x-aiff","asc":"text/plain","au":"audio/basic","avi":"video/x-msvideo","bcpio":"application/x-bcpio","bin":"application/octet-stream","bmp":"image/bmp","cdf":"application/x-netcdf","class":"application/octet-stream","cpio":"application/x-cpio","cpt":"application/mac-compactpro","csh":"application/x-csh","css":"text/css","dcr":"application/x-director","dir":"application/x-director","djv":"image/vnd.djvu","djvu":"image/vnd.djvu","dll":"application/octet-stream","dms":"application/octet-stream","doc":"application/msword","dvi":"application/x-dvi","dxr":"application/x-director","eps":"application/postscript","etx":"text/x-setext","exe":"application/octet-stream","ez":"application/andrew-inset","gif":"image/gif","gtar":"application/x-gtar","hdf":"application/x-hdf","hqx":"application/mac-binhex40","htm":"text/html","html":"text/html","ice":"x-conference/x-cooltalk","ief":"image/ief","iges":"model/iges","igs":"model/iges","jpe":"image/jpeg","jpeg":"image/jpeg","jpg":"image/jpeg","js":"application/x-javascript","kar":"audio/midi","latex":"application/x-latex","lha":"application/octet-stream","lzh":"application/octet-stream","m3u":"audio/x-mpegurl","man":"application/x-troff-man","me":"application/x-troff-me","mesh":"model/mesh","mid":"audio/midi","midi":"audio/midi","mif":"application/vnd.mif","mov":"video/quicktime","movie":"video/x-sgi-movie","mp2":"audio/mpeg","mp3":"audio/mpeg","mpe":"video/mpeg","mpeg":"video/mpeg","mpg":"video/mpeg","mpga":"audio/mpeg","ms":"application/x-troff-ms","msh":"model/mesh","mxu":"video/vnd.mpegurl","nc":"application/x-netcdf","oda":"application/oda","pbm":"image/x-portable-bitmap","pdb":"chemical/x-pdb","pdf":"application/pdf","pgm":"image/x-portable-graymap","pgn":"application/x-chess-pgn","png":"image/png","pnm":"image/x-portable-anymap","ppm":"image/x-portable-pixmap","ppt":"application/vnd.ms-powerpoint","ps":"application/postscript","qt":"video/quicktime","ra":"audio/x-realaudio","ram":"audio/x-pn-realaudio","ras":"image/x-cmu-raster","rgb":"image/x-rgb","rm":"audio/x-pn-realaudio","roff":"application/x-troff","rpm":"audio/x-pn-realaudio-plugin","rtf":"text/rtf","rtx":"text/richtext","sgm":"text/sgml","sgml":"text/sgml","sh":"application/x-sh","shar":"application/x-shar","silo":"model/mesh","sit":"application/x-stuffit","skd":"application/x-koan","skm":"application/x-koan","skp":"application/x-koan","skt":"application/x-koan","smi":"application/smil","smil":"application/smil","snd":"audio/basic","so":"application/octet-stream","spl":"application/x-futuresplash","src":"application/x-wais-source","sv4cpio":"application/x-sv4cpio","sv4crc":"application/x-sv4crc","swf":"application/x-shockwave-flash","t":"application/x-troff","tar":"application/x-tar","tcl":"application/x-tcl","tex":"application/x-tex","texi":"application/x-texinfo","texinfo":"application/x-texinfo","tif":"image/tiff","tiff":"image/tiff","tr":"application/x-troff","tsv":"text/tab-separated-values","txt":"text/plain","ustar":"application/x-ustar","vcd":"application/x-cdlink","vrml":"model/vrml","wav":"audio/x-wav","wbmp":"image/vnd.wap.wbmp","wbxml":"application/vnd.wap.wbxml","wml":"text/vnd.wap.wml","wmlc":"application/vnd.wap.wmlc","wmls":"text/vnd.wap.wmlscript","wmlsc":"application/vnd.wap.wmlscriptc","wrl":"model/vrml","xbm":"image/x-xbitmap","xht":"application/xhtml+xml","xhtml":"application/xhtml+xml","xls":"application/vnd.ms-excel","xml":"text/xml","xpm":"image/x-xpixmap","xsl":"text/xml","xwd":"image/x-xwindowdump","xyz":"chemical/x-xyz","zip":"application/zip"}';
public static $buffer_list = [];
public static function getResourceFolder() {
@@ -40,7 +39,7 @@ class DataProvider
return ZMBuf::globals("http_reverse_link");
}
private static function getJsonData(string $string) {
public static function getJsonData(string $string) {
if(!file_exists(self::getDataConfig().$string)) return [];
return json_decode(Co::readFile(self::getDataConfig().$string), true);
}
@@ -52,4 +51,4 @@ class DataProvider
public static function getDataFolder() {
return ZM_DATA;
}
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace ZM\Utils;
use Swlib\Saber;
use Swoole\Coroutine\Http\Client;
class ZMRequest
{
/**
* 使用Swoole协程客户端发起HTTP GET请求
* @version 1.1
* 返回请求后的body
* 如果请求失败或返回状态不是200则返回 false
* @param $url
* @param array $headers
* @param array $set
* @param bool $return_body
* @return bool|string|Client
*/
public static function get($url, $headers = [], $set = [], $return_body = true) {
$parse = parse_url($url);
$cli = new Client($parse["host"], ($parse["scheme"] == "https" ? 443 : (isset($parse["port"]) ? $parse["port"] : 80)), ($parse["scheme"] == "https" ? true : false));
$cli->setHeaders($headers);
$cli->set($set == [] ? ['timeout' => 15.0] : $set);
$cli->get($parse["path"] . (isset($parse["query"]) ? "?" . $parse["query"] : ""));
if ($return_body) {
if ($cli->errCode != 0 || $cli->statusCode != 200) return false;
$a = $cli->body;
$cli->close();
return $a;
} else {
$cli->close();
return $cli;
}
}
/**
* 使用Swoole协程客户端发起HTTP POST请求
* 返回请求后的body
* 如果请求失败或返回状态不是200则返回 false
* @param $url
* @param array $header
* @param $data
* @param array $set
* @param bool $return_body
* @return bool|string|Client
*/
public static function post($url, array $header, $data, $set = [], $return_body = true) {
$parse = parse_url($url);
$cli = new Client($parse["host"], ($parse["scheme"] == "https" ? 443 : (isset($parse["port"]) ? $parse["port"] : 80)), ($parse["scheme"] == "https" ? true : false));
$cli->set($set == [] ? ['timeout' => 15.0] : $set);
$cli->setHeaders($header);
$cli->post($parse["path"] . (isset($parse["query"]) ? ("?" . $parse["query"]) : ""), $data);
if ($return_body) {
if ($cli->errCode != 0 || $cli->statusCode != 200) return false;
$a = $cli->body;
$cli->close();
return $a;
} else {
$cli->close();
return $cli;
}
}
/**
* @param $option
* @return Saber
*/
public static function session($option) {
return Saber::session($option);
}
}