Commit 0803a1fe authored by wolfcode's avatar wolfcode

update Core && fix bug

parent 3eb27bc2
......@@ -50,19 +50,20 @@ class InstallCheck implements MiddlewareInterface
try {
$conn = mysqli_connect($dbHost, $dbUser, $dbPwd, null, $dbPort);
mysqli_query($conn, "SET NAMES {$dbCharset}");
$initDb = mysqli_select_db($conn, $dbName);
if (!$initDb) {
try {
mysqli_select_db($conn, $dbName);
} catch (\mysqli_sql_exception $exception) {
if (!mysqli_query($conn, "CREATE DATABASE IF NOT EXISTS `{$dbName}` DEFAULT CHARACTER SET {$dbCharset};")) {
$errorMsg = "数据库{$dbName} 不存在,也没权限创建新的数据库!";
mysqli_close($conn);
return response($errorMsg, 400);
}
mysqli_select_db($conn, $dbName);
}
// 先建表
$db_data = file_get_contents($db_base_data);
$sqlFormat = sql_split($db_data);
$counts = count($sqlFormat);
mysqli_select_db($conn, $dbName);
for ($index = 0; $index < $counts; $index++) {
$sql = trim($sqlFormat[$index]);
if (strstr($sql, 'CREATE TABLE')) {
......@@ -79,7 +80,7 @@ class InstallCheck implements MiddlewareInterface
mysqli_close($conn);
@touch($lock_file);
return $handler($request);
} catch (\Exception $e) {
} catch (\Throwable $e) {
$errorMsg = "连接 MySQL 失败: " . mysqli_connect_error() . $e->getMessage();
return response($errorMsg, 400);
}
......
......@@ -25,7 +25,7 @@
},
"require": {
"php": ">=7.2",
"workerman/webman-framework": "^1.3.0",
"workerman/webman-framework": "1.4.3",
"monolog/monolog": "^2.0",
"webman/auto-route": "^1.0",
"webman/think-orm": "1.0.2",
......@@ -40,7 +40,8 @@
"webman/think-cache": "^1.0",
"aliyuncs/oss-sdk-php": "^2.4",
"qcloud/cos-sdk-v5": "^2.5",
"jasongrimes/paginator": "^1.0"
"jasongrimes/paginator": "^1.0",
"webman/console": "1.0.27"
},
"suggest": {
"ext-event": "For better performance. "
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "02d0c65ff3d87ccf79b24943c0ba01d7",
"content-hash": "1e7532d2b14481835ed4cafcfb0c520b",
"packages": [
{
"name": "aliyuncs/oss-sdk-php",
......@@ -3634,6 +3634,58 @@
},
"time": "2022-04-01T07:37:43+00:00"
},
{
"name": "webman/console",
"version": "v1.0.27",
"source": {
"type": "git",
"url": "https://github.com/webman-php/console.git",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/console/zipball/e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"shasum": ""
},
"require": {
"symfony/console": ">=5.0"
},
"require-dev": {
"workerman/webman": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Webman\\Console\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "Webman console",
"homepage": "http://www.workerman.net",
"keywords": [
"webman console"
],
"support": {
"email": "walkor@workerman.net",
"forum": "http://www.workerman.net/questions",
"issues": "https://github.com/webman-php/console/issues",
"source": "https://github.com/webman-php/console",
"wiki": "http://www.workerman.net/doc/webman"
},
"time": "2022-07-01T08:59:02+00:00"
},
{
"name": "webman/think-cache",
"version": "v1.0.1",
......@@ -3771,16 +3823,16 @@
},
{
"name": "workerman/webman-framework",
"version": "v1.3.12",
"version": "v1.4.3",
"source": {
"type": "git",
"url": "https://github.com/walkor/webman-framework.git",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01"
"reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/walkor/webman-framework/zipball/a5b392e68a88993e2c94f73805630458b6058c01",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01",
"url": "https://api.github.com/repos/walkor/webman-framework/zipball/0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"shasum": ""
},
"require": {
......@@ -3838,7 +3890,7 @@
"type": "patreon"
}
],
"time": "2022-04-28T12:25:46+00:00"
"time": "2022-08-15T12:35:14+00:00"
},
{
"name": "workerman/workerman",
......
<?php
return [
'enable' => true,
'phar_file_output_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman.phar',
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
//'exclude_pattern' => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
'exclude_files' => [
'.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
]
];
......@@ -7,8 +7,5 @@ INSERT INTO `category` VALUES (1, '生活', 1, '2022-04-16 20:54:11', NULL, 0);
INSERT INTO `category` VALUES (2, '技术', 1, '2022-04-16 20:54:11', NULL, 0);
INSERT INTO `category` VALUES (3, '折腾', 1, '2022-04-16 20:54:11', NULL, 0);
INSERT INTO `article` VALUES (1, '蒹葭', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。\n蒹葭采采,白露未已。所谓伊人,在', 1, '/upload/20220517/dip1652765664FSjzHW.jpg', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。<br>\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。<br>\n蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚。<br>', '2022-05-08', 11, 1, 0, '2022-05-08 15:55:46', '2022-05-17 13:34:29');
INSERT INTO `article` VALUES (2, '值得收藏的一份MySQL规范', '本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。\n命名规范\n\n1) 库名、表名、字段名必须使用小写字母,\"_\"分割。', 2, '', '<div class=\"post\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\">\n<div class=\"single viewall\" id=\"article_content\" style=\"margin: 0px; padding: 5px 0px; border-width: 1px 0px 0px; border-top-style: dotted; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-top-color: rgb(24, 24, 27); border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; vertical-align: baseline; line-height: 30px; overflow-wrap: break-word; word-break: break-all; overflow: hidden; position: relative;\">\n<p style=\"margin-bottom: 1em; padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。</span></p>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">命名规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 库名、表名、字段名必须使用小写字母,\"_\"分割。<br style=\"margin: 0px; padding: 0px;\">\n2) 库名、表名、字段名不超过12个字符。<br style=\"margin: 0px; padding: 0px;\">\n3) 库名、表名、字段名禁止使用MySQL保留字,见附件。<br style=\"margin: 0px; padding: 0px;\">\n4) 库名、表名、字段名见名知意,建议使用名词而不是动词。<br style=\"margin: 0px; padding: 0px;\">\n5) 数据对象、变量的命名都采用英文字符,禁止使用中文命名。<br style=\"margin: 0px; padding: 0px;\">\n6) 临时库、表名必须以tmp为前缀,并以日期为后缀。<br style=\"margin: 0px; padding: 0px;\">\n7) 备份库、表必须以bak为前缀,并以日期为后缀。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">基础规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 所有表统一使用InnoDB存储引擎。<br style=\"margin: 0px; padding: 0px;\">\n2) 表字符集选择UTF8mb4。<br style=\"margin: 0px; padding: 0px;\">\n3) 所有表和列都需要添加注释。<br style=\"margin: 0px; padding: 0px;\">\n4) 禁止在数据库中存储图片、文件。<br style=\"margin: 0px; padding: 0px;\">\n5) 禁止在线上做数据库压力测试,如有特殊需要,需提前报备。<br style=\"margin: 0px; padding: 0px;\">\n6) 禁止客户端直接操作测试,生产数据库。<br style=\"margin: 0px; padding: 0px;\">\n7) 研发保证应用与数据库表结构版本的统一,并提供相应的数据库回滚策略。<br style=\"margin: 0px; padding: 0px;\">\n8) 表结构变更DBA审核未通过的,不允许上线。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">字段设计规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 每张表必须有整型主键。如:id bigint(20) UNSIGNED , NOT NULL,不要自增。<br style=\"margin: 0px; padding: 0px;\">\n2) 禁止DEFAULT NULL,建议NOT NULL 设置默认值。<br style=\"margin: 0px; padding: 0px;\">\n3) 存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE,或者使用bigint(需要做转换)。<br style=\"margin: 0px; padding: 0px;\">\n4) 建议使用UNSIGNED存储非负数值。<br style=\"margin: 0px; padding: 0px;\">\n5) 不建议使用ENUM类型,使用TINYINT来代替。<br style=\"margin: 0px; padding: 0px;\">\n6) 建议使用INT UNSIGNED存储IPV4。<br style=\"margin: 0px; padding: 0px;\">\n7) 禁止在数据库中存储明文密码。<br style=\"margin: 0px; padding: 0px;\">\n8) 整形定义中建议采用INT(10),而不是INT(1),INT(11)或其他。<br style=\"margin: 0px; padding: 0px;\">\n9) 存储状态,性别等,用TINYINT。<br style=\"margin: 0px; padding: 0px;\">\n10) 将过大字段拆分到其他表中。尽可能不使用TEXT、BLOB类型。如果必须使用,业务表中的TEXT,BLOB中字段,必须要拆分到单独的表中存储。<br style=\"margin: 0px; padding: 0px;\">\n11) 需要根据实际的宽度来选择VARCHAR(N)类型的宽度。<br style=\"margin: 0px; padding: 0px;\">\n12) N表示的是字符数不是字节数. VARCHAR(N),N尽可能小,进行排序和创建临时表一类的内存操作时,会使用N的长度申请内存。<br style=\"margin: 0px; padding: 0px;\">\n13) 存储年使用YEAR类型,存储日期使用DATE类型。&nbsp;<br style=\"margin: 0px; padding: 0px;\">\n14) 13 存储时间(精确到秒)建议使用TIMESTAMP类型,因为TIMESTAMP使用4字节,DATETIME使用8个字节。TIMESTAMP类型保存的值不能比1970早或比2037晚。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">一句话总结:</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p dir=\"ltr\" style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">能NOT NULL 就NOT NULL,char、varchar用NOT NULL DEFAULT \'\',tinyint、smallint、int用NOT NULL DEFAULT 0。<br style=\"margin: 0px; padding: 0px;\">\nchar、varchar取值要吝啬,根据实际需求给,比如人名一般不超过5个,varchar(5),不要varchar(200)。int、tinyint这类,int(1)和int(13)都是一样的,<br style=\"margin: 0px; padding: 0px;\">\n我们统一用int(10),tinyint取值范围[-128,127],加了unsigned取值[0,255],如果不需要存储负数,整型类型的加unsigned。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 单张表的索引数量控制在5个以内。<br style=\"margin: 0px; padding: 0px;\">\n2) 复合索引中的字段数建议不超过5个。<br style=\"margin: 0px; padding: 0px;\">\n3) 非唯一索引必须按照\"idx_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n4) 唯一索引必须按照\"uniq_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n5) 合理利用覆盖索引。不使用更新频繁的列做为索引。<br style=\"margin: 0px; padding: 0px;\">\n6) 对长字符串考虑使用前缀索引,前缀索引长度不超过8个字符。<br style=\"margin: 0px; padding: 0px;\">\n7) 索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面。<br style=\"margin: 0px; padding: 0px;\">\n8) 使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,UsingTemporary。<br style=\"margin: 0px; padding: 0px;\">\n9) UPDATE、DELETE语句需要根据WHERE条件添加索引。<br style=\"margin: 0px; padding: 0px;\">\n10) 合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c),但(a,c)只能用到部分索引。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引禁忌</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 不在选择性低的列上建立索引,例如\"性别\", \"状态\"\"类型\"。<br style=\"margin: 0px; padding: 0px;\">\n2) 不在索引列进行数学运算和函数运算。<br style=\"margin: 0px; padding: 0px;\">\n3) 尽量不使用外键。<br style=\"margin: 0px; padding: 0px;\">\n4) 高并发场景不建议使用唯一索引。<br style=\"margin: 0px; padding: 0px;\">\n5) 不使用前导查询,如like \"%ab\",like \"%ab%\"。<br style=\"margin: 0px; padding: 0px;\">\n6 SQL语句规范<br style=\"margin: 0px; padding: 0px;\">\n1) SQL语句中IN包含的值不应过多(不超过1000个)<br style=\"margin: 0px; padding: 0px;\">\n2) UPDATE、DELETE语句不使用LIMIT。<br style=\"margin: 0px; padding: 0px;\">\n3) WHERE条件中必须使用合适的类型,避免MySQL进行隐式类型转化。<br style=\"margin: 0px; padding: 0px;\">\n4) SELECT语句只获取需要的字段。<br style=\"margin: 0px; padding: 0px;\">\n5) SELECT、INSERT语句必须显式的指明字段名称,不使用SELECT *,不使用INSERT INTO table()。<br style=\"margin: 0px; padding: 0px;\">\n6) WHERE条件中的非等值条件(IN、BETWEEN、&lt;、&lt;=、&gt;、&gt;=)会导致后面的条件使用不了索引。<br style=\"margin: 0px; padding: 0px;\">\n7) 避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一起。<br style=\"margin: 0px; padding: 0px;\">\n8) INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()……),values的个数不应过多。<br style=\"margin: 0px; padding: 0px;\">\n9) 避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数中存在一定的bug。<br style=\"margin: 0px; padding: 0px;\">\n10) 避免使用JOIN。<br style=\"margin: 0px; padding: 0px;\">\n11) 使用合理的SQL语句减少与数据库的交互次数。<br style=\"margin: 0px; padding: 0px;\">\n12) 不使用ORDER BY RAND(),使用其他方法替换。<br style=\"margin: 0px; padding: 0px;\">\n13) 建议使用合理的分页方式以提高分页的效率。<br style=\"margin: 0px; padding: 0px;\">\n14) 统计表中记录数时使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。</span></p>\n</blockquote></div>\n</div>', '2022-05-17', 6, 1, 0, '2022-05-17 13:37:28', '2022-05-17 13:37:56');
INSERT INTO `article` VALUES (3, '我承认我找不到素材了', '那就这样吧!\n\n\n\n', 3, '', '那就这样吧!\n<div><br>\n</div>\n<div align=\"center\"><img src=\"/upload/20220517/Hkb1652765942zWOqaJ.jpg\"><br>\n</div>', '2022-05-17', 11, 1, 0, '2022-05-17 13:39:04', '2022-05-17 13:41:21');
INSERT INTO `article` VALUES (1, '蒹葭', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。\n蒹葭采采,白露未已。所谓伊人,在', 1, '/upload/20220517/dip1652765664FSjzHW.jpg', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。<br>\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。<br>\n蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚。<br>', '2022-05-08', 11, 1, 0, '2022-05-08 15:55:46', '2022-05-17 13:34:29');
INSERT INTO `article` VALUES (2, '值得收藏的一份MySQL规范', '本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。\n命名规范\n\n1) 库名、表名、字段名必须使用小写字母,\"_\"分割。', 2, '', '<div class=\"post\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\">\n<div class=\"single viewall\" id=\"article_content\" style=\"margin: 0px; padding: 5px 0px; border-width: 1px 0px 0px; border-top-style: dotted; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-top-color: rgb(24, 24, 27); border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; vertical-align: baseline; line-height: 30px; overflow-wrap: break-word; word-break: break-all; overflow: hidden; position: relative;\">\n<p style=\"margin-bottom: 1em; padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。</span></p>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">命名规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 库名、表名、字段名必须使用小写字母,\"_\"分割。<br style=\"margin: 0px; padding: 0px;\">\n2) 库名、表名、字段名不超过12个字符。<br style=\"margin: 0px; padding: 0px;\">\n3) 库名、表名、字段名禁止使用MySQL保留字,见附件。<br style=\"margin: 0px; padding: 0px;\">\n4) 库名、表名、字段名见名知意,建议使用名词而不是动词。<br style=\"margin: 0px; padding: 0px;\">\n5) 数据对象、变量的命名都采用英文字符,禁止使用中文命名。<br style=\"margin: 0px; padding: 0px;\">\n6) 临时库、表名必须以tmp为前缀,并以日期为后缀。<br style=\"margin: 0px; padding: 0px;\">\n7) 备份库、表必须以bak为前缀,并以日期为后缀。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">基础规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 所有表统一使用InnoDB存储引擎。<br style=\"margin: 0px; padding: 0px;\">\n2) 表字符集选择UTF8mb4。<br style=\"margin: 0px; padding: 0px;\">\n3) 所有表和列都需要添加注释。<br style=\"margin: 0px; padding: 0px;\">\n4) 禁止在数据库中存储图片、文件。<br style=\"margin: 0px; padding: 0px;\">\n5) 禁止在线上做数据库压力测试,如有特殊需要,需提前报备。<br style=\"margin: 0px; padding: 0px;\">\n6) 禁止客户端直接操作测试,生产数据库。<br style=\"margin: 0px; padding: 0px;\">\n7) 研发保证应用与数据库表结构版本的统一,并提供相应的数据库回滚策略。<br style=\"margin: 0px; padding: 0px;\">\n8) 表结构变更DBA审核未通过的,不允许上线。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">字段设计规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 每张表必须有整型主键。如:id bigint(20) UNSIGNED , NOT NULL,不要自增。<br style=\"margin: 0px; padding: 0px;\">\n2) 禁止DEFAULT NULL,建议NOT NULL 设置默认值。<br style=\"margin: 0px; padding: 0px;\">\n3) 存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE,或者使用bigint(需要做转换)。<br style=\"margin: 0px; padding: 0px;\">\n4) 建议使用UNSIGNED存储非负数值。<br style=\"margin: 0px; padding: 0px;\">\n5) 不建议使用ENUM类型,使用TINYINT来代替。<br style=\"margin: 0px; padding: 0px;\">\n6) 建议使用INT UNSIGNED存储IPV4。<br style=\"margin: 0px; padding: 0px;\">\n7) 禁止在数据库中存储明文密码。<br style=\"margin: 0px; padding: 0px;\">\n8) 整形定义中建议采用INT(10),而不是INT(1),INT(11)或其他。<br style=\"margin: 0px; padding: 0px;\">\n9) 存储状态,性别等,用TINYINT。<br style=\"margin: 0px; padding: 0px;\">\n10) 将过大字段拆分到其他表中。尽可能不使用TEXT、BLOB类型。如果必须使用,业务表中的TEXT,BLOB中字段,必须要拆分到单独的表中存储。<br style=\"margin: 0px; padding: 0px;\">\n11) 需要根据实际的宽度来选择VARCHAR(N)类型的宽度。<br style=\"margin: 0px; padding: 0px;\">\n12) N表示的是字符数不是字节数. VARCHAR(N),N尽可能小,进行排序和创建临时表一类的内存操作时,会使用N的长度申请内存。<br style=\"margin: 0px; padding: 0px;\">\n13) 存储年使用YEAR类型,存储日期使用DATE类型。&nbsp;<br style=\"margin: 0px; padding: 0px;\">\n14) 13 存储时间(精确到秒)建议使用TIMESTAMP类型,因为TIMESTAMP使用4字节,DATETIME使用8个字节。TIMESTAMP类型保存的值不能比1970早或比2037晚。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">一句话总结:</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p dir=\"ltr\" style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">能NOT NULL 就NOT NULL,char、varchar用NOT NULL DEFAULT \'\',tinyint、smallint、int用NOT NULL DEFAULT 0。<br style=\"margin: 0px; padding: 0px;\">\nchar、varchar取值要吝啬,根据实际需求给,比如人名一般不超过5个,varchar(5),不要varchar(200)。int、tinyint这类,int(1)和int(13)都是一样的,<br style=\"margin: 0px; padding: 0px;\">\n我们统一用int(10),tinyint取值范围[-128,127],加了unsigned取值[0,255],如果不需要存储负数,整型类型的加unsigned。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 单张表的索引数量控制在5个以内。<br style=\"margin: 0px; padding: 0px;\">\n2) 复合索引中的字段数建议不超过5个。<br style=\"margin: 0px; padding: 0px;\">\n3) 非唯一索引必须按照\"idx_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n4) 唯一索引必须按照\"uniq_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n5) 合理利用覆盖索引。不使用更新频繁的列做为索引。<br style=\"margin: 0px; padding: 0px;\">\n6) 对长字符串考虑使用前缀索引,前缀索引长度不超过8个字符。<br style=\"margin: 0px; padding: 0px;\">\n7) 索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面。<br style=\"margin: 0px; padding: 0px;\">\n8) 使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,UsingTemporary。<br style=\"margin: 0px; padding: 0px;\">\n9) UPDATE、DELETE语句需要根据WHERE条件添加索引。<br style=\"margin: 0px; padding: 0px;\">\n10) 合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c),但(a,c)只能用到部分索引。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引禁忌</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 不在选择性低的列上建立索引,例如\"性别\", \"状态\"\"类型\"。<br style=\"margin: 0px; padding: 0px;\">\n2) 不在索引列进行数学运算和函数运算。<br style=\"margin: 0px; padding: 0px;\">\n3) 尽量不使用外键。<br style=\"margin: 0px; padding: 0px;\">\n4) 高并发场景不建议使用唯一索引。<br style=\"margin: 0px; padding: 0px;\">\n5) 不使用前导查询,如like \"%ab\",like \"%ab%\"。<br style=\"margin: 0px; padding: 0px;\">\n6 SQL语句规范<br style=\"margin: 0px; padding: 0px;\">\n1) SQL语句中IN包含的值不应过多(不超过1000个)<br style=\"margin: 0px; padding: 0px;\">\n2) UPDATE、DELETE语句不使用LIMIT。<br style=\"margin: 0px; padding: 0px;\">\n3) WHERE条件中必须使用合适的类型,避免MySQL进行隐式类型转化。<br style=\"margin: 0px; padding: 0px;\">\n4) SELECT语句只获取需要的字段。<br style=\"margin: 0px; padding: 0px;\">\n5) SELECT、INSERT语句必须显式的指明字段名称,不使用SELECT *,不使用INSERT INTO table()。<br style=\"margin: 0px; padding: 0px;\">\n6) WHERE条件中的非等值条件(IN、BETWEEN、&lt;、&lt;=、&gt;、&gt;=)会导致后面的条件使用不了索引。<br style=\"margin: 0px; padding: 0px;\">\n7) 避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一起。<br style=\"margin: 0px; padding: 0px;\">\n8) INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()……),values的个数不应过多。<br style=\"margin: 0px; padding: 0px;\">\n9) 避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数中存在一定的bug。<br style=\"margin: 0px; padding: 0px;\">\n10) 避免使用JOIN。<br style=\"margin: 0px; padding: 0px;\">\n11) 使用合理的SQL语句减少与数据库的交互次数。<br style=\"margin: 0px; padding: 0px;\">\n12) 不使用ORDER BY RAND(),使用其他方法替换。<br style=\"margin: 0px; padding: 0px;\">\n13) 建议使用合理的分页方式以提高分页的效率。<br style=\"margin: 0px; padding: 0px;\">\n14) 统计表中记录数时使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。</span></p>\n</blockquote></div>\n</div>', '2022-05-17', 6, 1, 0, '2022-05-17 13:37:28', '2022-05-17 13:37:56');
INSERT INTO `article` VALUES (3, '我承认我找不到素材了', '那就这样吧!\n\n\n\n', 3, '', '那就这样吧!\n<div><br>\n</div>\n<div align=\"center\"><img src=\"/upload/20220517/Hkb1652765942zWOqaJ.jpg\"><br>\n</div>', '2022-05-17', 11, 1, 0, '2022-05-17 13:39:04', '2022-05-17 13:41:21');
\ No newline at end of file
INSERT INTO `article` VALUES (2, '我承认我找不到素材了', '那就这样吧!\n\n\n\n', 3, '', '那就这样吧!\n<div><br>\n</div>\n<div align=\"center\"><img src=\"/upload/20220517/Hkb1652765942zWOqaJ.jpg\"><br>\n</div>', '2022-05-17', 11, 1, 0, '2022-05-17 13:39:04', '2022-05-17 13:41:21');
INSERT INTO `banner` VALUES (1, '轮播图可以后台设置', '', 0, '', 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2020-03-16%2F5e6f456284b3e.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664443024&t=56aed7f75b80334354600cd8556d093c', 1, NULL, NULL, 1);
\ No newline at end of file
#!/usr/bin/env php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Protocols\Http;
use Workerman\Connection\TcpConnection;
use Webman\App;
use Webman\Config;
use Webman\Route;
use Webman\Middleware;
use Dotenv\Dotenv;
use support\Request;
use support\Log;
use support\Container;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
Config::load(config_path(), ['route', 'container']);
if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($timezone);
}
$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
if ( !file_exists($runtime_logs_path) || !is_dir($runtime_logs_path) ) {
if (!mkdir($runtime_logs_path,0777,true)) {
throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
}
}
$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
if ( !file_exists($runtime_views_path) || !is_dir($runtime_views_path) ) {
if (!mkdir($runtime_views_path,0777,true)) {
throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
}
}
Worker::$onMasterReload = function () {
if (function_exists('opcache_get_status')) {
if ($status = opcache_get_status()) {
if (isset($status['scripts']) && $scripts = $status['scripts']) {
foreach (array_keys($scripts) as $file) {
opcache_invalidate($file, true);
}
}
}
}
};
$config = config('server');
Worker::$pidFile = $config['pid_file'];
Worker::$stdoutFile = $config['stdout_file'];
Worker::$logFile = $config['log_file'];
Worker::$eventLoopClass = $config['event_loop'] ?? '';
TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10 * 1024 * 1024;
if (property_exists(Worker::class, 'statusFile')) {
Worker::$statusFile = $config['status_file'] ?? '';
}
if (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
foreach ($property_map as $property) {
if (isset($config[$property])) {
$worker->$property = $config[$property];
}
}
$worker->onWorkerStart = function ($worker) {
require_once base_path() . '/support/bootstrap.php';
$app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());
Http::requestClass(config('app.request_class', config('server.request_class', Request::class)));
$worker->onMessage = [$app, 'onMessage'];
};
}
// Windows does not support custom processes.
if (\DIRECTORY_SEPARATOR === '/') {
foreach (config('process', []) as $process_name => $config) {
worker_start($process_name, $config);
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
foreach ($project['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$name.$process_name", $config);
}
}
}
}
Worker::runAll();
Support\App::run();
......@@ -13,10 +13,12 @@
*/
use Dotenv\Dotenv;
use support\Container;
use support\Log;
use Webman\Bootstrap;
use Webman\Config;
use Webman\Route;
use Webman\Middleware;
use Webman\Util;
$worker = $worker ?? null;
......@@ -24,7 +26,7 @@ if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($timezone);
}
set_error_handler(function ($level, $message, $file = '', $line = 0, $context = []) {
set_error_handler(function ($level, $message, $file = '', $line = 0) {
if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line);
}
......@@ -46,45 +48,85 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
}
}
Config::reload(config_path(), ['route', 'container']);
Support\App::loadAllConfig(['route']);
foreach (config('autoload.files', []) as $file) {
include_once $file;
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['autoload']['files'] ?? [] as $file) {
include_once $file;
}
}
}
foreach (config('autoload.files', []) as $file) {
foreach ($projects['autoload']['files'] ?? [] as $file) {
include_once $file;
}
}
$container = Container::instance();
Route::container($container);
Middleware::container($container);
Middleware::load(config('middleware', []));
Middleware::load(config('middleware', []), '');
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
Middleware::load($project['middleware'] ?? []);
if (!is_array($project) || $name === 'static') {
continue;
}
Middleware::load($project['middleware'] ?? [], '');
}
Middleware::load($projects['middleware'] ?? [], $firm);
if ($static_middlewares = config("plugin.$firm.static.middleware")) {
Middleware::load(['__static__' => $static_middlewares], $firm);
}
}
Middleware::load(['__static__' => config('static.middleware', [])]);
Middleware::load(['__static__' => config('static.middleware', [])], '');
foreach (config('bootstrap', []) as $class_name) {
/** @var \Webman\Bootstrap $class_name */
if (!class_exists($class_name)) {
$log = "Warning: Class $class_name setting in config/bootstrap.php not found\r\n";
echo $log;
Log::error($log);
continue;
}
/** @var Bootstrap $class_name */
$class_name::start($worker);
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['bootstrap'] ?? [] as $class_name) {
/** @var \Webman\Bootstrap $class_name */
if (!class_exists($class_name)) {
$log = "Warning: Class $class_name setting in config/plugin/$firm/$name/bootstrap.php not found\r\n";
echo $log;
Log::error($log);
continue;
}
/** @var Bootstrap $class_name */
$class_name::start($worker);
}
}
foreach ($projects['bootstrap'] ?? [] as $class_name) {
if (!class_exists($class_name)) {
$log = "Warning: Class $class_name setting in plugin/$firm/config/bootstrap.php not found\r\n";
echo $log;
Log::error($log);
continue;
}
/** @var Bootstrap $class_name */
$class_name::start($worker);
}
}
$directory = base_path() . '/plugin';
$paths = [config_path()];
foreach (Util::scanDir($directory) as $path) {
if (is_dir($path = "$path/config")) {
$paths[] = $path;
}
}
Route::load($paths);
Route::load(config_path());
\ No newline at end of file
......@@ -26,22 +26,22 @@ use Webman\Config;
use Webman\Route;
// Phar support.
if (is_phar()) {
define('BASE_PATH', dirname(__DIR__));
if (\is_phar()) {
\define('BASE_PATH', dirname(__DIR__));
} else {
define('BASE_PATH', realpath(__DIR__ . '/../'));
\define('BASE_PATH', realpath(__DIR__ . '/../'));
}
define('WEBMAN_VERSION', '1.3.0');
\define('WEBMAN_VERSION', '1.4');
/**
* @param $return_phar
* @return false|string
*/
function base_path($return_phar = true)
function base_path(bool $return_phar = true)
{
static $real_path = '';
if (!$real_path) {
$real_path = is_phar() ? dirname(Phar::running(false)) : BASE_PATH;
$real_path = \is_phar() ? \dirname(Phar::running(false)) : BASE_PATH;
}
return $return_phar ? BASE_PATH : $real_path;
}
......@@ -61,7 +61,7 @@ function public_path()
{
static $path = '';
if (!$path) {
$path = get_realpath(config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public'));
$path = \config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public');
}
return $path;
}
......@@ -84,7 +84,7 @@ function runtime_path()
{
static $path = '';
if (!$path) {
$path = get_realpath(config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime'));
$path = \config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime');
}
return $path;
}
......@@ -95,7 +95,7 @@ function runtime_path()
* @param string $body
* @return Response
*/
function response($body = '', $status = 200, $headers = array())
function response($body = '', $status = 200, $headers = [])
{
return new Response($status, $headers, $body);
}
......@@ -107,7 +107,7 @@ function response($body = '', $status = 200, $headers = array())
*/
function json($data, $options = JSON_UNESCAPED_UNICODE)
{
return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options));
return new Response(200, ['Content-Type' => 'application/json'], \json_encode($data, $options));
}
/**
......@@ -129,19 +129,19 @@ function xml($xml)
*/
function jsonp($data, $callback_name = 'callback')
{
if (!is_scalar($data) && null !== $data) {
$data = json_encode($data);
if (!\is_scalar($data) && null !== $data) {
$data = \json_encode($data);
}
return new Response(200, [], "$callback_name($data)");
}
/**
* @param $location
* @param string $location
* @param int $status
* @param array $headers
* @return Response
*/
function redirect($location, $status = 302, $headers = [])
function redirect(string $location, int $status = 302, array $headers = [])
{
$response = new Response($status, ['Location' => $location]);
if (!empty($headers)) {
......@@ -156,55 +156,55 @@ function redirect($location, $status = 302, $headers = [])
* @param null $app
* @return Response
*/
function view($template, $vars = [], $app = null)
function view(string $template, array $vars = [], string $app = null)
{
static $handler;
if (null === $handler) {
$handler = config('view.handler');
}
$request = \request();
$plugin = $request->plugin ?? '';
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
return new Response(200, [], $handler::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
* @throws Throwable
*/
function raw_view($template, $vars = [], $app = null)
function raw_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], Raw::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
*/
function blade_view($template, $vars = [], $app = null)
function blade_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], Blade::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
*/
function think_view($template, $vars = [], $app = null)
function think_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], ThinkPHP::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
*/
function twig_view($template, $vars = [], $app = null)
function twig_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], Twig::render($template, $vars, $app));
}
......@@ -218,21 +218,21 @@ function request()
}
/**
* @param $key
* @param null $default
* @return mixed
* @param string|null $key
* @param $default
* @return array|mixed|null
*/
function config($key = null, $default = null)
function config(string $key = null, $default = null)
{
return Config::get($key, $default);
}
/**
* @param $name
* @param string $name
* @param ...$parameters
* @return string
*/
function route($name, ...$parameters)
function route(string $name, ...$parameters)
{
$route = Route::getByName($name);
if (!$route) {
......@@ -243,8 +243,8 @@ function route($name, ...$parameters)
return $route->url();
}
if (is_array(current($parameters))) {
$parameters = current($parameters);
if (\is_array(\current($parameters))) {
$parameters = \current($parameters);
}
return $route->url($parameters);
......@@ -257,7 +257,7 @@ function route($name, ...$parameters)
*/
function session($key = null, $default = null)
{
$session = request()->session();
$session = \request()->session();
if (null === $key) {
return $session;
}
......@@ -280,7 +280,7 @@ function session($key = null, $default = null)
}
/**
* @param null|string $id
* @param string $id
* @param array $parameters
* @param string|null $domain
* @param string|null $locale
......@@ -311,48 +311,50 @@ function locale(string $locale = null)
*/
function not_found()
{
return new Response(404, [], file_get_contents(public_path() . '/404.html'));
return new Response(404, [], \file_get_contents(public_path() . '/404.html'));
}
/**
* Copy dir.
* @param $source
* @param $dest
*
* @param string $source
* @param string $dest
* @param bool $overwrite
* @return void
*/
function copy_dir($source, $dest, $overwrite = false)
function copy_dir(string $source, string $dest, bool $overwrite = false)
{
if (is_dir($source)) {
if (\is_dir($source)) {
if (!is_dir($dest)) {
mkdir($dest);
\mkdir($dest);
}
$files = scandir($source);
$files = \scandir($source);
foreach ($files as $file) {
if ($file !== "." && $file !== "..") {
copy_dir("$source/$file", "$dest/$file");
\copy_dir("$source/$file", "$dest/$file");
}
}
} else if (file_exists($source) && ($overwrite || !file_exists($dest))) {
copy($source, $dest);
} else if (\file_exists($source) && ($overwrite || !\file_exists($dest))) {
\copy($source, $dest);
}
}
/**
* Remove dir.
* @param $dir
*
* @param string $dir
* @return bool
*/
function remove_dir($dir)
function remove_dir(string $dir)
{
if (is_link($dir) || is_file($dir)) {
return unlink($dir);
if (\is_link($dir) || \is_file($dir)) {
return \unlink($dir);
}
$files = array_diff(scandir($dir), array('.', '..'));
$files = \array_diff(\scandir($dir), array('.', '..'));
foreach ($files as $file) {
(is_dir("$dir/$file") && !is_link($dir)) ? remove_dir("$dir/$file") : unlink("$dir/$file");
(\is_dir("$dir/$file") && !\is_link($dir)) ? \remove_dir("$dir/$file") : \unlink("$dir/$file");
}
return rmdir($dir);
return \rmdir($dir);
}
/**
......@@ -369,15 +371,15 @@ function worker_bind($worker, $class)
'onBufferFull',
'onBufferDrain',
'onWorkerStop',
'onWebSocketConnect',
'onWebSocketConnect'
];
foreach ($callback_map as $name) {
if (method_exists($class, $name)) {
if (\method_exists($class, $name)) {
$worker->$name = [$class, $name];
}
}
if (method_exists($class, 'onWorkerStart')) {
call_user_func([$class, 'onWorkerStart'], $worker);
if (\method_exists($class, 'onWorkerStart')) {
[$class, 'onWorkerStart']($worker);
}
}
......@@ -406,10 +408,10 @@ function worker_start($process_name, $config)
}
$worker->onWorkerStart = function ($worker) use ($config) {
require_once base_path() . '/support/bootstrap.php';
require_once \base_path() . '/support/bootstrap.php';
foreach ($config['services'] ?? [] as $server) {
if (!class_exists($server['handler'])) {
if (!\class_exists($server['handler'])) {
echo "process error: class {$server['handler']} not exists\r\n";
continue;
}
......@@ -418,18 +420,18 @@ function worker_start($process_name, $config)
echo "listen: {$server['listen']}\n";
}
$instance = Container::make($server['handler'], $server['constructor'] ?? []);
worker_bind($listen, $instance);
\worker_bind($listen, $instance);
$listen->listen();
}
if (isset($config['handler'])) {
if (!class_exists($config['handler'])) {
if (!\class_exists($config['handler'])) {
echo "process error: class {$config['handler']} not exists\r\n";
return;
}
$instance = Container::make($config['handler'], $config['constructor'] ?? []);
worker_bind($worker, $instance);
\worker_bind($worker, $instance);
}
};
......@@ -444,10 +446,10 @@ function worker_start($process_name, $config)
*/
function get_realpath(string $file_path): string
{
if (strpos($file_path, 'phar://') === 0) {
if (\strpos($file_path, 'phar://') === 0) {
return $file_path;
} else {
return realpath($file_path);
return \realpath($file_path);
}
}
......@@ -456,7 +458,7 @@ function get_realpath(string $file_path): string
*/
function is_phar()
{
return class_exists(\Phar::class, false) && Phar::running();
return \class_exists(\Phar::class, false) && Phar::running();
}
/**
......@@ -469,26 +471,12 @@ function cpu_count()
return 1;
}
$count = 4;
if (is_callable('shell_exec')) {
if (strtolower(PHP_OS) === 'darwin') {
$count = (int)shell_exec('sysctl -n machdep.cpu.core_count');
if (\is_callable('shell_exec')) {
if (\strtolower(PHP_OS) === 'darwin') {
$count = (int)\shell_exec('sysctl -n machdep.cpu.core_count');
} else {
$count = (int)shell_exec('nproc');
$count = (int)\shell_exec('nproc');
}
}
return $count > 0 ? $count : 4;
}
if (!function_exists('env')) {
/**
* Gets the value of an environment variable.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
function env(string $key, $default = null)
{
return \Illuminate\Support\Env::get($key, $default);
}
}
\ No newline at end of file
......@@ -2,6 +2,11 @@
// 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 ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0::getLoader();
......@@ -21,12 +21,14 @@ use Composer\Semver\VersionParser;
* 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
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
......@@ -37,7 +39,7 @@ class InstalledVersions
/**
* @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}>}>
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
......@@ -241,7 +243,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
......@@ -255,7 +257,7 @@ class InstalledVersions
*
* @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}>}
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
......@@ -278,7 +280,7 @@ class InstalledVersions
* 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}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
......@@ -301,7 +303,7 @@ class InstalledVersions
* @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
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
......@@ -311,7 +313,7 @@ class InstalledVersions
/**
* @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}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
......
......@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
......
......@@ -2,26 +2,26 @@
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
'538ca81a9a966a6716601ecf48f4eaef' => $vendorDir . '/opis/closure/functions.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',
'2df68f9e79c919e2d88506611769ed2e' => $vendorDir . '/respect/stringifier/src/stringify.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php',
......
......@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
......
......@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
......@@ -12,6 +12,7 @@ return array(
'Workerman\\' => array($vendorDir . '/workerman/workerman'),
'Webman\\ThinkOrm\\' => array($vendorDir . '/webman/think-orm/src'),
'Webman\\ThinkCache\\' => array($vendorDir . '/webman/think-cache/src'),
'Webman\\Console\\' => array($vendorDir . '/webman/console/src'),
'Webman\\AutoRoute\\' => array($vendorDir . '/webman/auto-route/src'),
'Webman\\ActionHook\\' => array($vendorDir . '/webman/action-hook/src'),
'Webman\\' => array($vendorDir . '/workerman/webman-framework/src'),
......
......@@ -25,38 +25,15 @@ class ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
$includeFiles = \Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::$files;
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire403af8cd99d7ed8c6ce0c15ef03b20d0($fileIdentifier, $file);
}
......
......@@ -9,20 +9,20 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0
public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
'538ca81a9a966a6716601ecf48f4eaef' => __DIR__ . '/..' . '/opis/closure/functions.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php',
'2df68f9e79c919e2d88506611769ed2e' => __DIR__ . '/..' . '/respect/stringifier/src/stringify.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php',
......@@ -48,6 +48,7 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0
'Workerman\\' => 10,
'Webman\\ThinkOrm\\' => 16,
'Webman\\ThinkCache\\' => 18,
'Webman\\Console\\' => 15,
'Webman\\AutoRoute\\' => 17,
'Webman\\ActionHook\\' => 18,
'Webman\\' => 7,
......@@ -165,6 +166,10 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0
array (
0 => __DIR__ . '/..' . '/webman/think-cache/src',
),
'Webman\\Console\\' =>
array (
0 => __DIR__ . '/..' . '/webman/console/src',
),
'Webman\\AutoRoute\\' =>
array (
0 => __DIR__ . '/..' . '/webman/auto-route/src',
......
......@@ -3790,6 +3790,61 @@
},
"install-path": "../webman/auto-route"
},
{
"name": "webman/console",
"version": "v1.0.27",
"version_normalized": "1.0.27.0",
"source": {
"type": "git",
"url": "https://github.com/webman-php/console.git",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/console/zipball/e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"shasum": ""
},
"require": {
"symfony/console": ">=5.0"
},
"require-dev": {
"workerman/webman": "^1.0"
},
"time": "2022-07-01T08:59:02+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Webman\\Console\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "Webman console",
"homepage": "http://www.workerman.net",
"keywords": [
"webman console"
],
"support": {
"email": "walkor@workerman.net",
"forum": "http://www.workerman.net/questions",
"issues": "https://github.com/webman-php/console/issues",
"source": "https://github.com/webman-php/console",
"wiki": "http://www.workerman.net/doc/webman"
},
"install-path": "../webman/console"
},
{
"name": "webman/think-cache",
"version": "v1.0.1",
......@@ -3936,17 +3991,17 @@
},
{
"name": "workerman/webman-framework",
"version": "v1.3.12",
"version_normalized": "1.3.12.0",
"version": "v1.4.3",
"version_normalized": "1.4.3.0",
"source": {
"type": "git",
"url": "https://github.com/walkor/webman-framework.git",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01"
"reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/walkor/webman-framework/zipball/a5b392e68a88993e2c94f73805630458b6058c01",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01",
"url": "https://api.github.com/repos/walkor/webman-framework/zipball/0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"shasum": ""
},
"require": {
......@@ -3958,7 +4013,7 @@
"suggest": {
"ext-event": "For better performance. "
},
"time": "2022-04-28T12:25:46+00:00",
"time": "2022-08-15T12:35:14+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
......
<?php return array(
'root' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'name' => 'workerman/webman',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => NULL,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '8328e092da79093ae4d0d8e87589ad419cedf7a8',
'name' => 'workerman/webman',
'dev' => true,
),
'versions' => array(
'aliyuncs/oss-sdk-php' => array(
'pretty_version' => 'v2.4.3',
'version' => '2.4.3.0',
'reference' => '4ccead614915ee6685bf30016afb01aabd347e46',
'type' => 'library',
'install_path' => __DIR__ . '/../aliyuncs/oss-sdk-php',
'aliases' => array(),
'reference' => '4ccead614915ee6685bf30016afb01aabd347e46',
'dev_requirement' => false,
),
'doctrine/inflector' => array(
'pretty_version' => '2.0.4',
'version' => '2.0.4.0',
'reference' => '8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/inflector',
'aliases' => array(),
'reference' => '8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89',
'dev_requirement' => false,
),
'graham-campbell/result-type' => array(
'pretty_version' => 'v1.0.4',
'version' => '1.0.4.0',
'reference' => '0690bde05318336c7221785f2a932467f98b64ca',
'type' => 'library',
'install_path' => __DIR__ . '/../graham-campbell/result-type',
'aliases' => array(),
'reference' => '0690bde05318336c7221785f2a932467f98b64ca',
'dev_requirement' => false,
),
'gregwar/captcha' => array(
'pretty_version' => 'v1.1.9',
'version' => '1.1.9.0',
'reference' => '4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5',
'type' => 'captcha',
'install_path' => __DIR__ . '/../gregwar/captcha',
'aliases' => array(),
'reference' => '4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5',
'dev_requirement' => false,
),
'guzzlehttp/command' => array(
'pretty_version' => '1.2.2',
'version' => '1.2.2.0',
'reference' => '7883359e0ecab8a8f7c43aad2fc36360a35d21e8',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/command',
'aliases' => array(),
'reference' => '7883359e0ecab8a8f7c43aad2fc36360a35d21e8',
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '7.4.2',
'version' => '7.4.2.0',
'reference' => 'ac1ec1cd9b5624694c3a40be801d94137afb12b4',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'reference' => 'ac1ec1cd9b5624694c3a40be801d94137afb12b4',
'dev_requirement' => false,
),
'guzzlehttp/guzzle-services' => array(
'pretty_version' => '1.3.2',
'version' => '1.3.2.0',
'reference' => '4989d902dd4e0411b320e851c46f3c94d652d891',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle-services',
'aliases' => array(),
'reference' => '4989d902dd4e0411b320e851c46f3c94d652d891',
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '1.5.1',
'version' => '1.5.1.0',
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.2.1',
'version' => '2.2.1.0',
'reference' => 'c94a94f120803a18554c1805ef2e539f8285f9a2',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'reference' => 'c94a94f120803a18554c1805ef2e539f8285f9a2',
'dev_requirement' => false,
),
'guzzlehttp/uri-template' => array(
'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0',
'reference' => 'b945d74a55a25a949158444f09ec0d3c120d69e2',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/uri-template',
'aliases' => array(),
'reference' => 'b945d74a55a25a949158444f09ec0d3c120d69e2',
'dev_requirement' => false,
),
'illuminate/collections' => array(
'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0',
'reference' => 'fc232e89c0214dba5d2b431220a24b02d480a472',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/collections',
'aliases' => array(),
'reference' => 'fc232e89c0214dba5d2b431220a24b02d480a472',
'dev_requirement' => false,
),
'illuminate/container' => array(
'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0',
'reference' => '14062628d05f75047c5a1360b9350028427d568e',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/container',
'aliases' => array(),
'reference' => '14062628d05f75047c5a1360b9350028427d568e',
'dev_requirement' => false,
),
'illuminate/contracts' => array(
'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0',
'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts',
'aliases' => array(),
'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d',
'dev_requirement' => false,
),
'illuminate/database' => array(
'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0',
'reference' => '5a09b780d86613127cddbeb05e4dde22aeccbedf',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/database',
'aliases' => array(),
'reference' => '5a09b780d86613127cddbeb05e4dde22aeccbedf',
'dev_requirement' => false,
),
'illuminate/macroable' => array(
'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0',
'reference' => 'aed81891a6e046fdee72edd497f822190f61c162',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/macroable',
'aliases' => array(),
'reference' => 'aed81891a6e046fdee72edd497f822190f61c162',
'dev_requirement' => false,
),
'illuminate/support' => array(
'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0',
'reference' => '3f1de19528fc235d666f73d540d13a684da6bf3a',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/support',
'aliases' => array(),
'reference' => '3f1de19528fc235d666f73d540d13a684da6bf3a',
'dev_requirement' => false,
),
'jasongrimes/paginator' => array(
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
'reference' => '3411e3cd0c6479a0b514f26e4358f0273552f221',
'type' => 'library',
'install_path' => __DIR__ . '/../jasongrimes/paginator',
'aliases' => array(),
'reference' => '3411e3cd0c6479a0b514f26e4358f0273552f221',
'dev_requirement' => false,
),
'monolog/monolog' => array(
'pretty_version' => '2.5.0',
'version' => '2.5.0.0',
'reference' => '4192345e260f1d51b365536199744b987e160edc',
'type' => 'library',
'install_path' => __DIR__ . '/../monolog/monolog',
'aliases' => array(),
'reference' => '4192345e260f1d51b365536199744b987e160edc',
'dev_requirement' => false,
),
'nesbot/carbon' => array(
'pretty_version' => '2.57.0',
'version' => '2.57.0.0',
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(),
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
'dev_requirement' => false,
),
'nikic/fast-route' => array(
'pretty_version' => 'v1.3.0',
'version' => '1.3.0.0',
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/fast-route',
'aliases' => array(),
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
'dev_requirement' => false,
),
'opis/closure' => array(
'pretty_version' => '3.6.3',
'version' => '3.6.3.0',
'reference' => '3d81e4309d2a927abbe66df935f4bb60082805ad',
'type' => 'library',
'install_path' => __DIR__ . '/../opis/closure',
'aliases' => array(),
'reference' => '3d81e4309d2a927abbe66df935f4bb60082805ad',
'dev_requirement' => false,
),
'phpoption/phpoption' => array(
'pretty_version' => '1.8.1',
'version' => '1.8.1.0',
'reference' => 'eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15',
'type' => 'library',
'install_path' => __DIR__ . '/../phpoption/phpoption',
'aliases' => array(),
'reference' => 'eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15',
'dev_requirement' => false,
),
'psr/cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/cache',
'aliases' => array(),
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'dev_requirement' => false,
),
'psr/container' => array(
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
'dev_requirement' => false,
),
'psr/container-implementation' => array(
......@@ -235,10 +235,10 @@
'psr/http-client' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-client',
'aliases' => array(),
'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
'dev_requirement' => false,
),
'psr/http-client-implementation' => array(
......@@ -250,10 +250,10 @@
'psr/http-factory' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(),
'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be',
'dev_requirement' => false,
),
'psr/http-factory-implementation' => array(
......@@ -265,10 +265,10 @@
'psr/http-message' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'dev_requirement' => false,
),
'psr/http-message-implementation' => array(
......@@ -280,10 +280,10 @@
'psr/log' => array(
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'dev_requirement' => false,
),
'psr/log-implementation' => array(
......@@ -296,154 +296,154 @@
'psr/simple-cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'dev_requirement' => false,
),
'qcloud/cos-sdk-v5' => array(
'pretty_version' => 'v2.5.5',
'version' => '2.5.5.0',
'reference' => '40e51efc05d5addeb9029db7840846809bd666c4',
'type' => 'library',
'install_path' => __DIR__ . '/../qcloud/cos-sdk-v5',
'aliases' => array(),
'reference' => '40e51efc05d5addeb9029db7840846809bd666c4',
'dev_requirement' => false,
),
'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'dev_requirement' => false,
),
'respect/stringifier' => array(
'pretty_version' => '0.2.0',
'version' => '0.2.0.0',
'reference' => 'e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59',
'type' => 'library',
'install_path' => __DIR__ . '/../respect/stringifier',
'aliases' => array(),
'reference' => 'e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59',
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0',
'reference' => 'ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'reference' => 'ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b',
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v2.5.1',
'version' => '2.5.1.0',
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'dev_requirement' => false,
),
'symfony/finder' => array(
'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0',
'reference' => '9b630f3427f3ebe7cd346c277a1408b00249dad9',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(),
'reference' => '9b630f3427f3ebe7cd346c277a1408b00249dad9',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'dev_requirement' => false,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'reference' => '81b86b50cf841a64252b439e738e97f4a34e2783',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
'reference' => '81b86b50cf841a64252b439e738e97f4a34e2783',
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
'dev_requirement' => false,
),
'symfony/polyfill-php73' => array(
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'reference' => 'cc5db0e22b3cb4111010e48785a97f670b350ca5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php73',
'aliases' => array(),
'reference' => 'cc5db0e22b3cb4111010e48785a97f670b350ca5',
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'reference' => '4407588e0d3f1f52efb65fbe92babe41f37fe50c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'reference' => '4407588e0d3f1f52efb65fbe92babe41f37fe50c',
'dev_requirement' => false,
),
'symfony/service-contracts' => array(
'pretty_version' => 'v2.5.1',
'version' => '2.5.1.0',
'reference' => '24d9dc654b83e91aa59f9d167b131bc3b5bea24c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(),
'reference' => '24d9dc654b83e91aa59f9d167b131bc3b5bea24c',
'dev_requirement' => false,
),
'symfony/string' => array(
'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0',
'reference' => '3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),
'reference' => '3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8',
'dev_requirement' => false,
),
'symfony/translation' => array(
'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0',
'reference' => 'f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(),
'reference' => 'f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b',
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v2.5.1',
'version' => '2.5.1.0',
'reference' => '1211df0afa701e45a04253110e959d4af4ef0f07',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
'reference' => '1211df0afa701e45a04253110e959d4af4ef0f07',
'dev_requirement' => false,
),
'symfony/translation-implementation' => array(
......@@ -455,136 +455,145 @@
'topthink/think-cache' => array(
'pretty_version' => 'v2.0.6',
'version' => '2.0.6.0',
'reference' => '75a56b24affc65b51688fd89ada48c102757fd74',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-cache',
'aliases' => array(),
'reference' => '75a56b24affc65b51688fd89ada48c102757fd74',
'dev_requirement' => false,
),
'topthink/think-container' => array(
'pretty_version' => 'v2.0.4',
'version' => '2.0.4.0',
'reference' => '15c6d5813367c7c0cf501c7c043f48a6f359375c',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-container',
'aliases' => array(),
'reference' => '15c6d5813367c7c0cf501c7c043f48a6f359375c',
'dev_requirement' => false,
),
'topthink/think-helper' => array(
'pretty_version' => 'v3.1.6',
'version' => '3.1.6.0',
'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-helper',
'aliases' => array(),
'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff',
'dev_requirement' => false,
),
'topthink/think-orm' => array(
'pretty_version' => 'v2.0.53',
'version' => '2.0.53.0',
'reference' => '06783eda65547a70ea686360a897759e1f873fff',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-orm',
'aliases' => array(),
'reference' => '06783eda65547a70ea686360a897759e1f873fff',
'dev_requirement' => false,
),
'topthink/think-template' => array(
'pretty_version' => 'v2.0.8',
'version' => '2.0.8.0',
'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-template',
'aliases' => array(),
'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368',
'dev_requirement' => false,
),
'vlucas/phpdotenv' => array(
'pretty_version' => 'v5.4.1',
'version' => '5.4.1.0',
'reference' => '264dce589e7ce37a7ba99cb901eed8249fbec92f',
'type' => 'library',
'install_path' => __DIR__ . '/../vlucas/phpdotenv',
'aliases' => array(),
'reference' => '264dce589e7ce37a7ba99cb901eed8249fbec92f',
'dev_requirement' => false,
),
'voku/portable-ascii' => array(
'pretty_version' => '1.6.1',
'version' => '1.6.1.0',
'reference' => '87337c91b9dfacee02452244ee14ab3c43bc485a',
'type' => 'library',
'install_path' => __DIR__ . '/../voku/portable-ascii',
'aliases' => array(),
'reference' => '87337c91b9dfacee02452244ee14ab3c43bc485a',
'dev_requirement' => false,
),
'webman/action-hook' => array(
'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0',
'reference' => 'f5c0928f349eeb576b4208100d06d271bd4178b8',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/action-hook',
'aliases' => array(),
'reference' => 'f5c0928f349eeb576b4208100d06d271bd4178b8',
'dev_requirement' => false,
),
'webman/auto-route' => array(
'pretty_version' => 'v1.0.2',
'version' => '1.0.2.0',
'reference' => 'd3cf4ad8c182baf08572255268993753554dc94b',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/auto-route',
'aliases' => array(),
'reference' => 'd3cf4ad8c182baf08572255268993753554dc94b',
'dev_requirement' => false,
),
'webman/console' => array(
'pretty_version' => 'v1.0.27',
'version' => '1.0.27.0',
'reference' => 'e450967eaabc43eb0c93cfcd6d8f420c16e22b67',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/console',
'aliases' => array(),
'dev_requirement' => false,
),
'webman/think-cache' => array(
'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0',
'reference' => '25bd103d7fc9347aca680e677282db761cc90a43',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/think-cache',
'aliases' => array(),
'reference' => '25bd103d7fc9347aca680e677282db761cc90a43',
'dev_requirement' => false,
),
'webman/think-orm' => array(
'pretty_version' => 'v1.0.2',
'version' => '1.0.2.0',
'reference' => '5c686ecbdfbc99141d129aebd626cb8ded04830e',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/think-orm',
'aliases' => array(),
'reference' => '5c686ecbdfbc99141d129aebd626cb8ded04830e',
'dev_requirement' => false,
),
'workerman/validation' => array(
'pretty_version' => 'v3.0.2',
'version' => '3.0.2.0',
'reference' => '49387fff74acb63277ea7ed9a476ffe339348772',
'type' => 'library',
'install_path' => __DIR__ . '/../workerman/validation',
'aliases' => array(),
'reference' => '49387fff74acb63277ea7ed9a476ffe339348772',
'dev_requirement' => false,
),
'workerman/webman' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => NULL,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '8328e092da79093ae4d0d8e87589ad419cedf7a8',
'dev_requirement' => false,
),
'workerman/webman-framework' => array(
'pretty_version' => 'v1.3.12',
'version' => '1.3.12.0',
'pretty_version' => 'v1.4.3',
'version' => '1.4.3.0',
'reference' => '0f4d5b6c58823656bdc9603f762d4be6e41ae380',
'type' => 'library',
'install_path' => __DIR__ . '/../workerman/webman-framework',
'aliases' => array(),
'reference' => 'a5b392e68a88993e2c94f73805630458b6058c01',
'dev_requirement' => false,
),
'workerman/workerman' => array(
'pretty_version' => 'v4.0.35',
'version' => '4.0.35.0',
'reference' => '1d8b3f7f9a7cef3e9f655b6151c7e93061ace397',
'type' => 'library',
'install_path' => __DIR__ . '/../workerman/workerman',
'aliases' => array(),
'reference' => '1d8b3f7f9a7cef3e9f655b6151c7e93061ace397',
'dev_requirement' => false,
),
),
......
build
vendor
.idea
.vscode
.phpunit*
composer.lock
\ No newline at end of file
# console
webman console
https://www.workerman.net/plugin/1
{
"name": "webman/console",
"type": "library",
"keywords": [
"webman console"
],
"homepage": "http://www.workerman.net",
"license": "MIT",
"description": "Webman console",
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"support": {
"email": "walkor@workerman.net",
"issues": "https://github.com/webman-php/console/issues",
"forum": "http://www.workerman.net/questions",
"wiki": "http://www.workerman.net/doc/webman",
"source": "https://github.com/webman-php/console"
},
"require": {
"symfony/console": ">=5.0"
},
"autoload": {
"psr-4": {
"Webman\\Console\\" : "src"
}
},
"require-dev": {
"workerman/webman": "^1.0"
}
}
<?php
namespace Webman\Console;
use support\Container;
use support\Log;
use support\Request;
use Webman\App;
use Webman\Config;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http;
use Workerman\Worker;
use Dotenv\Dotenv;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
class Application
{
public static function run()
{
$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
if ( !file_exists($runtime_logs_path) || !is_dir($runtime_logs_path) ) {
if (!mkdir($runtime_logs_path,0777,true)) {
throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
}
}
$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
if ( !file_exists($runtime_views_path) || !is_dir($runtime_views_path) ) {
if (!mkdir($runtime_views_path,0777,true)) {
throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
}
}
if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
Config::reload(config_path(), ['route', 'container']);
Worker::$onMasterReload = function (){
if (function_exists('opcache_get_status')) {
if ($status = opcache_get_status()) {
if (isset($status['scripts']) && $scripts = $status['scripts']) {
foreach (array_keys($scripts) as $file) {
opcache_invalidate($file, true);
}
}
}
}
};
$config = config('server');
Worker::$pidFile = $config['pid_file'];
Worker::$stdoutFile = $config['stdout_file'];
Worker::$logFile = $config['log_file'];
Worker::$eventLoopClass = $config['event_loop'] ?? '';
TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10*1024*1024;
if (property_exists(Worker::class, 'statusFile')) {
Worker::$statusFile = $config['status_file'] ?? '';
}
if (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
foreach ($property_map as $property) {
if (isset($config[$property])) {
$worker->$property = $config[$property];
}
}
$worker->onWorkerStart = function ($worker) {
require_once base_path() . '/support/bootstrap.php';
$app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());
Http::requestClass(config('app.request_class', config('server.request_class', Request::class)));
$worker->onMessage = [$app, 'onMessage'];
};
}
// Windows does not support custom processes.
if (\DIRECTORY_SEPARATOR === '/') {
foreach (config('process', []) as $process_name => $config) {
// Remove monitor process.
if (class_exists(\Phar::class, false) && \Phar::running() && 'monitor' === $process_name) {
continue;
}
worker_start($process_name, $config);
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
foreach ($project['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$name.$process_name", $config);
}
}
}
}
Worker::runAll();
}
}
<?php
namespace Webman\Console;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command as Commands;
class Command extends Application
{
public function installInternalCommands()
{
$this->installCommands(__DIR__ . '/Commands', 'Webman\Console\Commands');
}
public function installCommands($path, $namspace = 'app\command')
{
$dir_iterator = new \RecursiveDirectoryIterator($path);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
if (is_dir($file)) {
continue;
}
$class_name = $namspace.'\\'.basename($file, '.php');
if (!is_a($class_name, Commands::class, true)) {
continue;
}
$this->add(new $class_name);
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Webman\Console\Application;
class ConnectionsCommand extends Command
{
protected static $defaultName = 'connections';
protected static $defaultDescription = 'Get worker connections.';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class InstallCommand extends Command
{
protected static $defaultName = 'install';
protected static $defaultDescription = 'Execute webman installation script';
/**
* @return void
*/
protected function configure()
{
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln("Execute installation for webman");
$install_function = "\\Webman\\Install::install";
if (is_callable($install_function)) {
$install_function();
return self::SUCCESS;
}
$output->writeln('<error>This command requires webman-framework version >= 1.3.0</error>');
return self::FAILURE;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class MakeBootstrapCommand extends Command
{
protected static $defaultName = 'make:bootstrap';
protected static $defaultDescription = 'Make bootstrap';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Bootstrap name');
$this->addArgument('enable', InputArgument::OPTIONAL, 'Enable or not');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$enable = in_array($input->getArgument('enable'), ['no', '0', 'false', 'n']) ? false : true;
$output->writeln("Make bootstrap $name");
$name = str_replace('\\', '/', $name);
if (!$bootstrap_str = Util::guessPath(app_path(), 'bootstrap')) {
$bootstrap_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Bootstrap' : 'bootstrap';
}
$upper = $bootstrap_str === 'Bootstrap';
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$file = app_path() . "/$bootstrap_str/$name.php";
$namespace = $upper ? 'App\Bootstrap' : 'app\bootstrap';
} else {
if($real_name = Util::guessPath(app_path(), $name)) {
$name = $real_name;
}
if ($upper && !$real_name) {
$name = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name));
}
$path = "$bootstrap_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
$this->createBootstrap($name, $namespace, $file);
if ($enable) {
$this->addConfig("$namespace\\$name", config_path() . '/bootstrap.php');
}
return self::SUCCESS;
}
/**
* @param $name
* @param $namespace
* @param $file
* @return void
*/
protected function createBootstrap($name, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$bootstrap_content = <<<EOF
<?php
namespace $namespace;
use Webman\Bootstrap;
class $name implements Bootstrap
{
public static function start(\$worker)
{
// Is it console environment ?
\$is_console = !\$worker;
if (\$is_console) {
// If you do not want to execute this in console, just return.
return;
}
}
}
EOF;
file_put_contents($file, $bootstrap_content);
}
public function addConfig($class, $config_file)
{
$config = include $config_file;
if(!in_array($class, $config ?? [])) {
$config_file_content = file_get_contents($config_file);
$config_file_content = preg_replace('/\];/', " $class::class,\n];", $config_file_content);
file_put_contents($config_file, $config_file_content);
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class MakeCommandCommand extends Command
{
protected static $defaultName = 'make:command';
protected static $defaultDescription = 'Make command';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Command name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$command = $name = $input->getArgument('name');
$output->writeln("Make command $name");
// make:command 不支持子目录
$name = str_replace(['\\', '/'], '', $name);
if (!$command_str = Util::guessPath(app_path(), 'command')) {
$command_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Command' : 'command';
}
$upper = $command_str === 'Command';
$name = ucfirst($name);
$file = app_path() . "/$command_str/$name.php";
$namespace = $upper ? 'App\Command' : 'app\command';
$this->createCommand($name, $namespace, $file, $command);
return self::SUCCESS;
}
protected function getClassName($name)
{
return preg_replace_callback('/:([a-zA-Z])/', function ($matches) {
return strtoupper($matches[1]);
}, ucfirst($name)) . 'Command';
}
/**
* @param $name
* @param $namespace
* @param $path
* @return void
*/
protected function createCommand($name, $namespace, $file, $command)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$desc = str_replace(':', ' ', $command);
$command_content = <<<EOF
<?php
namespace $namespace;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
class $name extends Command
{
protected static \$defaultName = '$command';
protected static \$defaultDescription = '$desc';
/**
* @return void
*/
protected function configure()
{
\$this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
}
/**
* @param InputInterface \$input
* @param OutputInterface \$output
* @return int
*/
protected function execute(InputInterface \$input, OutputInterface \$output)
{
\$name = \$input->getArgument('name');
\$output->writeln('Hello $command');
return self::SUCCESS;
}
}
EOF;
file_put_contents($file, $command_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class MakeControllerCommand extends Command
{
protected static $defaultName = 'make:controller';
protected static $defaultDescription = 'Make controller';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Controller name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Make controller $name");
$suffix = config('app.controller_suffix', '');
if ($suffix && !strpos($name, $suffix)) {
$name .= $suffix;
}
$name = str_replace('\\', '/', $name);
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$controller_str = Util::guessPath(app_path(), 'controller') ?: 'controller';
$file = app_path() . "/$controller_str/$name.php";
$namespace = $controller_str === 'Controller' ? 'App\Controller' : 'app\controller';
} else {
$name_str = substr($name, 0, $pos);
if($real_name_str = Util::guessPath(app_path(), $name_str)) {
$name_str = $real_name_str;
} else if ($real_section_name = Util::guessPath(app_path(), strstr($name_str, '/', true))) {
$upper = strtolower($real_section_name[0]) !== $real_section_name[0];
} else if ($real_base_controller = Util::guessPath(app_path(), 'controller')) {
$upper = strtolower($real_base_controller[0]) !== $real_base_controller[0];
}
$upper = $upper ?? strtolower($name_str[0]) !== $name_str[0];
if ($upper && !$real_name_str) {
$name_str = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name_str));
}
$path = "$name_str/" . ($upper ? 'Controller' : 'controller');
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
$this->createController($name, $namespace, $file);
return self::SUCCESS;
}
/**
* @param $name
* @param $namespace
* @param $file
* @return void
*/
protected function createController($name, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$controller_content = <<<EOF
<?php
namespace $namespace;
use support\Request;
class $name
{
public function index(Request \$request)
{
return response(__CLASS__);
}
}
EOF;
file_put_contents($file, $controller_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class MakeMiddlewareCommand extends Command
{
protected static $defaultName = 'make:middleware';
protected static $defaultDescription = 'Make middleware';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Middleware name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Make middleware $name");
$name = str_replace('\\', '/', $name);
if (!$middleware_str = Util::guessPath(app_path(), 'middleware')) {
$middleware_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Middleware' : 'middleware';
}
$upper = $middleware_str === 'Middleware';
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$file = app_path() . "/$middleware_str/$name.php";
$namespace = $upper ? 'App\Middleware' : 'app\middleware';
} else {
if($real_name = Util::guessPath(app_path(), $name)) {
$name = $real_name;
}
if ($upper && !$real_name) {
$name = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name));
}
$path = "$middleware_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
$this->createMiddleware($name, $namespace, $file);
return self::SUCCESS;
}
/**
* @param $name
* @param $namespace
* @param $path
* @return void
*/
protected function createMiddleware($name, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$middleware_content = <<<EOF
<?php
namespace $namespace;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
class $name implements MiddlewareInterface
{
public function process(Request \$request, callable \$next) : Response
{
return \$next(\$request);
}
}
EOF;
file_put_contents($file, $middleware_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class MakeModelCommand extends Command
{
protected static $defaultName = 'make:model';
protected static $defaultDescription = 'Make model';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Model name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$name = Util::nameToClass($name);
$output->writeln("Make model $name");
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$model_str = Util::guessPath(app_path(), 'model') ?: 'model';
$file = app_path() . "/$model_str/$name.php";
$namespace = $model_str === 'Model' ? 'App\Model' : 'app\model';
} else {
$name_str = substr($name, 0, $pos);
if($real_name_str = Util::guessPath(app_path(), $name_str)) {
$name_str = $real_name_str;
} else if ($real_section_name = Util::guessPath(app_path(), strstr($name_str, '/', true))) {
$upper = strtolower($real_section_name[0]) !== $real_section_name[0];
} else if ($real_base_controller = Util::guessPath(app_path(), 'controller')) {
$upper = strtolower($real_base_controller[0]) !== $real_base_controller[0];
}
$upper = $upper ?? strtolower($name_str[0]) !== $name_str[0];
if ($upper && !$real_name_str) {
$name_str = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name_str));
}
$path = "$name_str/" . ($upper ? 'Model' : 'model');
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
if (!config('database') && config('thinkorm')) {
$this->createTpModel($name, $namespace, $file);
} else {
$this->createModel($name, $namespace, $file);
}
return self::SUCCESS;
}
/**
* @param $class
* @param $namespace
* @param $file
* @return void
*/
protected function createModel($class, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$table = Util::classToName($class);
$table_val = 'null';
$pk = 'id';
$properties = '';
try {
$prefix = config('database.connections.mysql.prefix') ?? '';
$database = config('database.connections.mysql.database');
if (\support\Db::select("show tables like '{$prefix}{$table}s'")) {
$table = "{$prefix}{$table}s";
} else if (\support\Db::select("show tables like '{$prefix}{$table}'")) {
$table_val = "'$table'";
$table = "{$prefix}{$table}";
}
foreach (\support\Db::select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
if ($item->COLUMN_KEY === 'PRI') {
$pk = $item->COLUMN_NAME;
$item->COLUMN_COMMENT .= "(主键)";
}
$type = $this->getType($item->DATA_TYPE);
$properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n";
}
} catch (\Throwable $e) {}
$properties = rtrim($properties) ?: ' *';
$model_content = <<<EOF
<?php
namespace $namespace;
use support\Model;
/**
$properties
*/
class $class extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected \$table = $table_val;
/**
* The primary key associated with the table.
*
* @var string
*/
protected \$primaryKey = '$pk';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public \$timestamps = false;
}
EOF;
file_put_contents($file, $model_content);
}
/**
* @param $class
* @param $namespace
* @param $path
* @return void
*/
protected function createTpModel($class, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$table = Util::classToName($class);
$table_val = 'null';
$pk = 'id';
$properties = '';
try {
$prefix = config('thinkorm.connections.mysql.prefix') ?? '';
$database = config('thinkorm.connections.mysql.database');
if (\think\facade\Db::query("show tables like '{$prefix}{$table}'")) {
$table = "{$prefix}{$table}";
$table_val = "'$table'";
} else if (\think\facade\Db::query("show tables like '{$prefix}{$table}s'")) {
$table = "{$prefix}{$table}s";
$table_val = "'$table'";
}
foreach (\think\facade\Db::query("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
if ($item['COLUMN_KEY'] === 'PRI') {
$pk = $item['COLUMN_NAME'];
$item['COLUMN_COMMENT'] .= "(主键)";
}
$type = $this->getType($item['DATA_TYPE']);
$properties .= " * @property $type \${$item['COLUMN_NAME']} {$item['COLUMN_COMMENT']}\n";
}
} catch (\Throwable $e) {}
$properties = rtrim($properties) ?: ' *';
$model_content = <<<EOF
<?php
namespace $namespace;
use think\Model;
/**
$properties
*/
class $class extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected \$table = $table_val;
/**
* The primary key associated with the table.
*
* @var string
*/
protected \$pk = '$pk';
}
EOF;
file_put_contents($file, $model_content);
}
/**
* @param string $type
* @return string
*/
protected function getType(string $type)
{
if (strpos($type, 'int') !== false) {
return 'integer';
}
switch ($type) {
case 'varchar':
case 'string':
case 'text':
case 'date':
case 'time':
case 'guid':
case 'datetimetz':
case 'datetime':
case 'decimal':
case 'enum':
return 'string';
case 'boolean':
return 'integer';
case 'float':
return 'float';
default:
return 'mixed';
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Phar;
use RuntimeException;
class PharPackCommand extends Command
{
protected static $defaultName = 'phar:pack';
protected static $defaultDescription = 'Can be easily packaged a project into phar files. Easy to distribute and use.';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->checkEnv();
$phar_file_output_dir = config('plugin.webman.console.app.phar_file_output_dir');
if (empty($phar_file_output_dir)) {
throw new RuntimeException('Please set the phar file output directory.');
}
if (!file_exists($phar_file_output_dir) && !is_dir($phar_file_output_dir)) {
if (!mkdir($phar_file_output_dir,0777,true)) {
throw new RuntimeException("Failed to create phar file output directory. Please check the permission.");
}
}
$phar_filename = config('plugin.webman.console.app.phar_filename');
if (empty($phar_filename)) {
throw new RuntimeException('Please set the phar filename.');
}
$phar_file = rtrim($phar_file_output_dir,DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $phar_filename;
if (file_exists($phar_file)) {
unlink($phar_file);
}
$exclude_pattern = config('plugin.webman.console.app.exclude_pattern');
$phar = new Phar($phar_file,0,'webman');
$phar->startBuffering();
$signature_algorithm = config('plugin.webman.console.app.signature_algorithm');
if (!in_array($signature_algorithm,[Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512,Phar::OPENSSL])) {
throw new RuntimeException('The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.');
}
if ($signature_algorithm === Phar::OPENSSL) {
$private_key_file = config('plugin.webman.console.app.private_key_file');
if (!file_exists($private_key_file)) {
throw new RuntimeException("If the value of the signature algorithm is 'Phar::OPENSSL', you must set the private key file.");
}
$private = openssl_get_privatekey(file_get_contents($private_key_file));
$pkey = '';
openssl_pkey_export($private, $pkey);
$phar->setSignatureAlgorithm($signature_algorithm, $pkey);
} else {
$phar->setSignatureAlgorithm($signature_algorithm);
}
$phar->buildFromDirectory(BASE_PATH,$exclude_pattern);
$exclude_files = config('plugin.webman.console.app.exclude_files');
foreach ($exclude_files as $file) {
if($phar->offsetExists($file)){
$phar->delete($file);
}
}
$output->writeln('Files collect complete, begin add file to Phar.');
$phar->setStub("#!/usr/bin/env php
<?php
define('IN_PHAR', true);
Phar::mapPhar('webman');
require 'phar://webman/webman';
__HALT_COMPILER();
");
$output->writeln('Write requests to the Phar archive, save changes to disk.');
$phar->stopBuffering();
unset($phar);
return self::SUCCESS;
}
/**
* @throws RuntimeException
*/
private function checkEnv(): void
{
if (!class_exists(Phar::class, false)) {
throw new RuntimeException("The 'phar' extension is required for build phar package");
}
if (ini_get('phar.readonly')) {
throw new RuntimeException(
"The 'phar.readonly' is 'On', build phar must setting it 'Off' or exec with 'php -d phar.readonly=0 ./webman phar:pack'"
);
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Util;
class PluginCreateCommand extends Command
{
protected static $defaultName = 'plugin:create';
protected static $defaultDescription = 'Plugin create';
/**
* @return void
*/
protected function configure()
{
$this->addOption('name', 'name', InputOption::VALUE_REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = strtolower($input->getOption('name'));
$output->writeln("Create Plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$namespace = Util::nameToNamespace($name);
// Create dir config/plugin/$name
if (is_dir($plugin_config_path = config_path()."/plugin/$name")) {
$output->writeln("<error>Dir $plugin_config_path already exists</error>");
return self::FAILURE;
}
if (is_dir($plugin_path = base_path()."/vendor/$name")) {
$output->writeln("<error>Dir $plugin_path already exists</error>");
return self::FAILURE;
}
// Add psr-4
if ($err = $this->addAutoloadToComposerJson($name, $namespace)) {
$output->writeln("<error>$err</error>");
return self::FAILURE;
}
$this->createConfigFiles($plugin_config_path);
$this->createVendorFiles($name, $namespace, $plugin_path, $output);
return self::SUCCESS;
}
protected function addAutoloadToComposerJson($name, $namespace)
{
if (!is_file($composer_json_file = base_path()."/composer.json")) {
return "$composer_json_file not exists";
}
$composer_json = json_decode($composer_json_str = file_get_contents($composer_json_file), true);
if (!$composer_json) {
return "Bad $composer_json_file";
}
if(isset($composer_json['autoload']['psr-4'][$namespace."\\"])) {
return;
}
$namespace = str_replace("\\", "\\\\", $namespace);
$composer_json_str = str_replace('"psr-4": {', '"psr-4": {'."\n \"$namespace\\\\\" : \"vendor/$name/src\",", $composer_json_str);
file_put_contents($composer_json_file, $composer_json_str);
}
protected function createConfigFiles($plugin_config_path)
{
mkdir($plugin_config_path, 0777, true);
$app_str = <<<EOF
<?php
return [
'enable' => true,
];
EOF;
file_put_contents("$plugin_config_path/app.php", $app_str);
}
protected function createVendorFiles($name, $namespace, $plugin_path, $output)
{
mkdir("$plugin_path/src", 0777, true);
$this->createComposerJson($name, $namespace, $plugin_path);
if (is_callable('exec')) {
exec("composer dumpautoload");
} else {
$output->writeln("<info>Please run command 'composer dumpautoload'</info>");
}
}
/**
* @param $name
* @param $namespace
* @param $dest
* @return void
*/
protected function createComposerJson($name, $namespace, $dest)
{
$namespace = str_replace('\\', '\\\\', $namespace);
$composer_json_content = <<<EOT
{
"name": "$name",
"type": "library",
"license": "MIT",
"description": "Webman plugin $name",
"require": {
},
"autoload": {
"psr-4": {
"$namespace\\\\": "src"
}
}
}
EOT;
file_put_contents("$dest/composer.json", $composer_json_content);
}
/**
* @param $namespace
* @param $path_relations
* @param $dest_dir
* @return void
*/
protected function writeInstallFile($namespace, $path_relations, $dest_dir)
{
if (!is_dir($dest_dir)) {
mkdir($dest_dir, 0777, true);
}
$relations = [];
foreach($path_relations as $relation) {
$relations[$relation] = $relation;
}
$relations = var_export($relations, true);
$install_php_content = <<<EOT
<?php
namespace $namespace;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static \$pathRelation = $relations;
/**
* Install
* @return void
*/
public static function install()
{
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
if (\$pos = strrpos(\$dest, '/')) {
\$parent_dir = base_path().'/'.substr(\$dest, 0, \$pos);
if (!is_dir(\$parent_dir)) {
mkdir(\$parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/\$source", base_path()."/\$dest");
copy_dir(__DIR__ . "/\$source", base_path()."/\$dest");
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
/*if (is_link(base_path()."/\$dest")) {
unlink(base_path()."/\$dest");
}*/
remove_dir(base_path()."/\$dest");
}
}
}
EOT;
file_put_contents("$dest_dir/Install.php", $install_php_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
class PluginDisableCommand extends Command
{
protected static $defaultName = 'plugin:disable';
protected static $defaultDescription = 'Disable plugin by name';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$output->writeln("Disable plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$config_file = config_path() . "/plugin/$name/app.php";
if (!is_file($config_file)) {
return self::SUCCESS;
}
$config = include $config_file;
if (empty($config['enable'])) {
return self::SUCCESS;
}
$config_content = file_get_contents($config_file);
$config_content = preg_replace('/(\'enable\' *?=> *?)(true)/', '$1false', $config_content);
file_put_contents($config_file, $config_content);
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
class PluginEnableCommand extends Command
{
protected static $defaultName = 'plugin:enable';
protected static $defaultDescription = 'Enable plugin by name';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Enable plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$config_file = config_path() . "/plugin/$name/app.php";
if (!is_file($config_file)) {
$output->writeln("<error>$config_file not found</error>");
return self::FAILURE;
}
$config = include $config_file;
if (!isset($config['enable'])) {
$output->writeln("<error>Config key 'enable' not found</error>");
return self::FAILURE;
}
if ($config['enable']) {
return self::SUCCESS;
}
$config_content = file_get_contents($config_file);
$config_content = preg_replace('/(\'enable\' *?=> *?)(false)/', '$1true', $config_content);
file_put_contents($config_file, $config_content);
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Util;
class PluginExportCommand extends Command
{
protected static $defaultName = 'plugin:export';
protected static $defaultDescription = 'Plugin export';
/**
* @return void
*/
protected function configure()
{
$this->addOption('name', 'name', InputOption::VALUE_REQUIRED, 'Plugin name, for example foo/my-admin');
$this->addOption('source', 'source', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Directories to export');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Export Plugin');
$name = strtolower($input->getOption('name'));
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::INVALID;
}
$namespace = Util::nameToNamespace($name);
$path_relations = $input->getOption('source');
if (!in_array("config/plugin/$name", $path_relations)) {
if (is_dir("config/plugin/$name")) {
$path_relations[] = "config/plugin/$name";
}
}
$original_dest = $dest = base_path()."/vendor/$name";
$dest .= '/src';
$this->writeInstallFile($namespace, $path_relations, $dest);
$output->writeln("<info>Create $dest/Install.php</info>");
foreach ($path_relations as $source) {
$base_path = pathinfo("$dest/$source", PATHINFO_DIRNAME);
if (!is_dir($base_path)) {
mkdir($base_path, 0777, true);
}
$output->writeln("<info>Copy $source to $dest/$source </info>");
copy_dir($source, "$dest/$source");
}
$output->writeln("<info>Saved $name to $original_dest</info>");
return self::SUCCESS;
}
/**
* @param $namespace
* @param $path_relations
* @param $dest_dir
* @return void
*/
protected function writeInstallFile($namespace, $path_relations, $dest_dir)
{
if (!is_dir($dest_dir)) {
mkdir($dest_dir, 0777, true);
}
$relations = [];
foreach($path_relations as $relation) {
$relations[$relation] = $relation;
}
$relations = var_export($relations, true);
$install_php_content = <<<EOT
<?php
namespace $namespace;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static \$pathRelation = $relations;
/**
* Install
* @return void
*/
public static function install()
{
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
if (\$pos = strrpos(\$dest, '/')) {
\$parent_dir = base_path().'/'.substr(\$dest, 0, \$pos);
if (!is_dir(\$parent_dir)) {
mkdir(\$parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/\$source", base_path()."/\$dest");
copy_dir(__DIR__ . "/\$source", base_path()."/\$dest");
echo "Create \$dest\r\n";
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
\$path = base_path()."/\$dest";
if (!is_dir(\$path) && !is_file(\$path)) {
continue;
}
echo "Remove \$dest\r\n";
if (is_file(\$path) || is_link(\$path)) {
unlink(\$path);
continue;
}
remove_dir(\$path);
}
}
}
EOT;
file_put_contents("$dest_dir/Install.php", $install_php_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class PluginInstallCommand extends Command
{
protected static $defaultName = 'plugin:install';
protected static $defaultDescription = 'Execute plugin installation script';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Execute installation for plugin $name");
$namespace = Util::nameToNamespace($name);
$install_function = "\\{$namespace}\\Install::install";
$plugin_const = "\\{$namespace}\\Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($install_function)) {
$install_function();
}
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class PluginUninstallCommand extends Command
{
protected static $defaultName = 'plugin:uninstall';
protected static $defaultDescription = 'Execute plugin uninstall script';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Execute uninstall for plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$namespace = Util::nameToNamespace($name);
$uninstall_function = "\\{$namespace}\\Install::uninstall";
$plugin_const = "\\{$namespace}\\Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($uninstall_function)) {
$uninstall_function();
}
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class ReStartCommand extends Command
{
protected static $defaultName = 'restart';
protected static $defaultDescription = 'Restart workers. Use mode -d to start in DAEMON mode. Use mode -g to stop gracefully.';
protected function configure() : void
{
$this
->addOption('daemon', 'd', InputOption::VALUE_NONE, 'DAEMON mode')
->addOption('graceful', 'g', InputOption::VALUE_NONE, 'graceful stop');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class ReloadCommand extends Command
{
protected static $defaultName = 'reload';
protected static $defaultDescription = 'Reload codes. Use mode -g to reload gracefully.';
protected function configure() : void
{
$this
->addOption('graceful', 'd', InputOption::VALUE_NONE, 'graceful reload');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\Table;
use Webman\Route;
class RouteListCommand extends Command
{
protected static $defaultName = 'route:list';
protected static $defaultDescription = 'Route list';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$headers = ['uri', 'method', 'callback', 'middleware'];
$rows = [];
foreach (Route::getRoutes() as $route) {
foreach ($route->getMethods() as $method) {
$cb = $route->getCallback();
$cb = $cb instanceof \Closure ? 'Closure' : (is_array($cb) ? json_encode($cb) : var_export($cb, 1));
$rows[] = [$route->getPath(), $method, $cb, json_encode($route->getMiddleware() ?: null)];
}
}
$table = new Table($output);
$table->setHeaders($headers);
$table->setRows($rows);
$table->render();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class StartCommand extends Command
{
protected static $defaultName = 'start';
protected static $defaultDescription = 'Start worker in DEBUG mode. Use mode -d to start in DAEMON mode.';
protected function configure() : void
{
$this->addOption('daemon', 'd', InputOption::VALUE_NONE, 'DAEMON mode');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class StatusCommand extends Command
{
protected static $defaultName = 'status';
protected static $defaultDescription = 'Get worker status. Use mode -d to show live status.';
protected function configure() : void
{
$this->addOption('live', 'd', InputOption::VALUE_NONE, 'show live status');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class StopCommand extends Command
{
protected static $defaultName = 'stop';
protected static $defaultDescription = 'Stop worker. Use mode -g to stop gracefully.';
protected function configure() : void
{
$this
->addOption('graceful', 'g',InputOption::VALUE_NONE, 'graceful stop');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class VersionCommand extends Command
{
protected static $defaultName = 'version';
protected static $defaultDescription = 'Show webman version';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$installed_file = base_path() . '/vendor/composer/installed.php';
if (is_file($installed_file)) {
$version_info = include $installed_file;
}
$webman_framework_version = $version_info['versions']['workerman/webman-framework']['pretty_version'] ?? '';
$output->writeln("Webman-framework $webman_framework_version");
return self::SUCCESS;
}
}
<?php
namespace Webman\Console;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static $pathRelation = array (
'config/plugin/webman/console' => 'config/plugin/webman/console',
);
/**
* Install
* @return void
*/
public static function install()
{
copy(__DIR__ . "/webman", base_path()."/webman");
chmod(base_path()."/webman", 0755);
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
if (is_file(base_path()."/webman")) {
unlink(base_path() . "/webman");
}
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::$pathRelation as $source => $dest) {
if ($pos = strrpos($dest, '/')) {
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
if (!is_dir($parent_dir)) {
mkdir($parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/$source", base_path()."/$dest");
copy_dir(__DIR__ . "/$source", base_path()."/$dest");
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::$pathRelation as $source => $dest) {
$path = base_path()."/$dest";
if (!is_dir($path) && !is_file($path)) {
continue;
}
/*if (is_link($path) {
unlink($path);
}*/
remove_dir($path);
}
}
}
<?php
namespace Webman\Console;
class Util
{
public static function nameToNamespace($name)
{
$namespace = ucfirst($name);
$namespace = preg_replace_callback(['/-([a-zA-Z])/', '/(\/[a-zA-Z])/'], function ($matches) {
return strtoupper($matches[1]);
}, $namespace);
return str_replace('/', '\\' ,ucfirst($namespace));
}
public static function classToName($class)
{
$class = lcfirst($class);
return preg_replace_callback(['/([A-Z])/'], function ($matches) {
return '_' . strtolower($matches[1]);
}, $class);
}
public static function nameToClass($class)
{
$class = preg_replace_callback(['/-([a-zA-Z])/', '/_([a-zA-Z])/'], function ($matches) {
return strtoupper($matches[1]);
}, $class);
if (!($pos = strrpos($class, '/'))) {
$class = ucfirst($class);
} else {
$path = substr($class, 0, $pos);
$class = ucfirst(substr($class, $pos + 1));
$class = "$path/$class";
}
return $class;
}
public static function guessPath($base_path, $name, $return_full_path = false)
{
if (!is_dir($base_path)) {
return false;
}
$names = explode('/', trim(strtolower($name), '/'));
$realname = [];
$path = $base_path;
foreach ($names as $name) {
$finded = false;
foreach (scandir($path) ?: [] as $tmp_name) {
if (strtolower($tmp_name) === $name && is_dir("$path/$tmp_name")) {
$path = "$path/$tmp_name";
$realname[] = $tmp_name;
$finded = true;
break;
}
}
if (!$finded) {
return false;
}
}
$realname = implode(DIRECTORY_SEPARATOR, $realname);
return $return_full_path ? realpath($base_path . DIRECTORY_SEPARATOR . $realname) : $realname;
}
}
<?php
return [
'enable' => true,
'phar_file_output_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman.phar',
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
//'exclude_pattern' => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
'exclude_files' => [
'.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
]
];
#!/usr/bin/env php
<?php
use Webman\Config;
use Webman\Console\Command;
use Webman\Console\Util;
require_once __DIR__ . '/vendor/autoload.php';
if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) {
require_once __DIR__ . '/support/bootstrap.php';
} else {
if (class_exists('Support\App')) {
Support\App::loadAllConfig(['route']);
} else {
Config::reload(config_path(), ['route', 'container']);
}
}
$cli = new Command();
$cli->setName('webman cli');
$cli->installInternalCommands();
if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
$cli->installCommands($command_path);
}
foreach (config('plugin', []) as $firm => $projects) {
if (isset($projects['app'])) {
if ($command_str = Util::guessPath(base_path() . "/plugin/$firm", 'command')) {
$command_path = base_path() . "/plugin/$firm/$command_str";
$cli->installCommands($command_path, "plugin\\$firm\\$command_str");
}
}
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['command'] ?? [] as $command) {
$cli->add(new $command);
}
}
}
$cli->run();
......@@ -14,17 +14,19 @@
namespace Webman;
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Closure;
use FastRoute\Dispatcher;
use Monolog\Logger;
use Psr\Container\ContainerInterface;
use Throwable;
use Webman\Exception\ExceptionHandler;
use Webman\Exception\ExceptionHandlerInterface;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\Route\Route as RouteObject;
use Webman\Exception\ExceptionHandlerInterface;
use Webman\Exception\ExceptionHandler;
use Webman\Config;
use FastRoute\Dispatcher;
use Psr\Container\ContainerInterface;
use Monolog\Logger;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http;
use Workerman\Worker;
/**
* Class App
......@@ -33,16 +35,6 @@ use Monolog\Logger;
class App
{
/**
* @var bool
*/
protected static $_supportStaticFiles = true;
/**
* @var bool
*/
protected static $_supportPHPFiles = false;
/**
* @var array
*/
......@@ -89,33 +81,24 @@ class App
protected static $_request = null;
/**
* @var int
* @var string
*/
protected static $_gracefulStopTimer = null;
protected static $_requestClass = '';
/**
* App constructor.
* @param Worker $worker
* @param $container
* @param $logger
* @param $app_path
* @param $public_path
*
* @param string $request_class
* @param Logger $logger
* @param string $app_path
* @param string $public_path
*/
public function __construct(Worker $worker, $container, $logger, $app_path, $public_path)
public function __construct(string $request_class, Logger $logger, string $app_path, string $public_path)
{
static::$_worker = $worker;
static::$_container = $container;
static::$_requestClass = $request_class;
static::$_logger = $logger;
static::$_publicPath = $public_path;
// Phar support.
if (class_exists(\Phar::class, false) && \Phar::running()) {
static::$_appPath = $app_path;
} else {
static::$_appPath = \realpath($app_path);
}
static::$_supportStaticFiles = Config::get('static.enable', true);
static::$_supportPHPFiles = Config::get('app.support_php_files', false);
}
/**
......@@ -123,7 +106,7 @@ class App
* @param Request $request
* @return null
*/
public function onMessage(TcpConnection $connection, $request)
public function onMessage($connection, $request)
{
try {
static::$_request = $request;
......@@ -131,20 +114,14 @@ class App
$path = $request->path();
$key = $request->method() . $path;
if (isset(static::$_callbacks[$key])) {
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request);
return null;
}
if (static::unsafeUri($path)) {
return null;
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
return static::send($connection, $callback($request), $request);
}
if (static::findFile($connection, $path, $key, $request)) {
return null;
}
if (static::findRoute($connection, $path, $key, $request)) {
if (static::unsafeUri($connection, $path, $request) ||
static::findFile($connection, $path, $key, $request) ||
static::findRoute($connection, $path, $key, $request)
) {
return null;
}
......@@ -155,26 +132,55 @@ class App
static::send($connection, $callback($request), $request);
return null;
}
$plugin = $controller_and_action['plugin'];
$app = $controller_and_action['app'];
$controller = $controller_and_action['controller'];
$action = $controller_and_action['action'];
$callback = static::getCallback($app, [$controller_and_action['instance'], $action]);
static::$_callbacks[$key] = [$callback, $app, $controller, $action, null];
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
$callback = static::getCallback($plugin, $app, [$controller, $action]);
static::collectCallbacks($key, [$callback, $plugin, $app, $controller, $action, null]);
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request);
} catch (\Throwable $e) {
} catch (Throwable $e) {
static::send($connection, static::exceptionResponse($e, $request), $request);
}
return null;
}
/**
* @param $path
* @param $worker
* @return void
*/
public function onWorkerStart($worker)
{
static::$_worker = $worker;
Http::requestClass(static::$_requestClass);
}
/**
* @param string $key
* @param array $data
* @return void
*/
protected static function collectCallbacks(string $key, array $data)
{
static::$_callbacks[$key] = $data;
if (\count(static::$_callbacks) >= 1024) {
unset(static::$_callbacks[\key(static::$_callbacks)]);
}
}
/**
* @param TcpConnection $connection
* @param string $path
* @param $request
* @return bool
*/
protected static function unsafeUri($path)
protected static function unsafeUri(TcpConnection $connection, string $path, $request)
{
if (strpos($path, '/../') !== false || strpos($path,"\\") !== false || strpos($path, "\0") !== false) {
if (\strpos($path, '..') !== false ||
\strpos($path, "\\") !== false ||
\strpos($path, "\0") !== false ||
\strpos($path, '//') !== false || !$path) {
$callback = static::getFallback();
$request->app = $request->controller = $request->action = '';
static::send($connection, $callback($request), $request);
......@@ -184,9 +190,10 @@ class App
}
/**
* @return \Closure
* @return Closure
*/
protected static function getFallback() {
protected static function getFallback()
{
// when route, controller and action not found, try to use Route::fallback
return Route::getFallback() ?: function () {
return new Response(404, [], \file_get_contents(static::$_publicPath . '/404.html'));
......@@ -194,28 +201,32 @@ class App
}
/**
* @param \Throwable $e
* @param Throwable $e
* @param $request
* @return string|Response
*/
protected static function exceptionResponse(\Throwable $e, $request)
protected static function exceptionResponse(Throwable $e, $request)
{
try {
$app = $request->app ?: '';
$exception_config = Config::get('exception');
$plugin = $request->plugin ?: '';
$exception_config = static::config($plugin, 'exception');
$default_exception = $exception_config[''] ?? ExceptionHandler::class;
$exception_handler_class = $exception_config[$app] ?? $default_exception;
/** @var ExceptionHandlerInterface $exception_handler */
$exception_handler = static::$_container->make($exception_handler_class, [
$exception_handler = static::container($plugin)->make($exception_handler_class, [
'logger' => static::$_logger,
'debug' => Config::get('app.debug')
'debug' => static::config($plugin, 'app.debug')
]);
$exception_handler->report($e);
$response = $exception_handler->render($request, $e);
$response->exception($e);
return $response;
} catch (Throwable $e) {
$response = new Response(500, [], static::config($plugin, 'app.debug') ? (string)$e : $e->getMessage());
$response->exception($e);
return $response;
} catch (\Throwable $e) {
return Config::get('app.debug') ? (string)$e : $e->getMessage();
}
}
......@@ -225,37 +236,54 @@ class App
* @param null $args
* @param bool $with_global_middleware
* @param RouteObject $route
* @return \Closure|mixed
* @return callable
*/
protected static function getCallback($app, $call, $args = null, $with_global_middleware = true, $route = null)
protected static function getCallback(string $plugin, string $app, $call, array $args = null, bool $with_global_middleware = true, RouteObject $route = null)
{
$args = $args === null ? null : \array_values($args);
$middlewares = [];
if ($route) {
$route_middlewares = \array_reverse($route->getMiddleware());
foreach ($route_middlewares as $class_name) {
$middlewares[] = [App::container()->get($class_name), 'process'];
$middlewares[] = [$class_name, 'process'];
}
}
$middlewares = \array_merge($middlewares, Middleware::getMiddleware($plugin, $app, $with_global_middleware));
foreach ($middlewares as $key => $item) {
$middlewares[$key][0] = static::container($plugin)->get($item[0]);
}
$controller_reuse = static::config($plugin, 'app.controller_reuse', true);
if (\is_array($call) && \is_string($call[0])) {
if (!$controller_reuse) {
$call = function ($request, ...$args) use ($call, $plugin) {
$call[0] = static::container($plugin)->make($call[0]);
return $call($request, ...$args);
};
} else {
$call[0] = static::container($plugin)->get($call[0]);
}
}
$middlewares = \array_merge($middlewares, Middleware::getMiddleware($app, $with_global_middleware));
if ($middlewares) {
$callback = array_reduce($middlewares, function ($carry, $pipe) {
$callback = \array_reduce($middlewares, function ($carry, $pipe) {
return function ($request) use ($carry, $pipe) {
return $pipe($request, $carry);
};
}, function ($request) use ($call, $args) {
try {
if ($args === null) {
$response = $call($request);
} else {
$response = $call($request, ...$args);
}
} catch (\Throwable $e) {
} catch (Throwable $e) {
return static::exceptionResponse($e, $request);
}
if (\is_scalar($response) || null === $response) {
if (!$response instanceof Response) {
if (\is_array($response)) {
$response = 'Array';
}
$response = new Response(200, [], $response);
}
return $response;
......@@ -273,11 +301,12 @@ class App
}
/**
* @param string $plugin
* @return ContainerInterface
*/
public static function container()
public static function container(string $plugin = '')
{
return static::$_container;
return static::config($plugin, 'container');
}
/**
......@@ -305,91 +334,108 @@ class App
}
/**
* @param $connection
* @param $path
* @param $key
* @param TcpConnection $connection
* @param string $path
* @param string $key
* @param Request $request
* @return bool
*/
protected static function findRoute($connection, $path, $key, Request $request)
protected static function findRoute(TcpConnection $connection, string $path, string $key, $request)
{
$ret = Route::dispatch($request->method(), $path);
if ($ret[0] === Dispatcher::FOUND) {
$ret[0] = 'route';
$callback = $ret[1]['callback'];
$route = $ret[1]['route'];
$app = $controller = $action = '';
$route = clone $ret[1]['route'];
$plugin = $app = $controller = $action = '';
$args = !empty($ret[2]) ? $ret[2] : null;
if (\is_array($callback) && isset($callback[0]) && $controller = \get_class($callback[0])) {
if ($args) {
$route->setParams($args);
}
if (\is_array($callback)) {
$controller = $callback[0];
$plugin = static::getPluginByClass($controller);
$app = static::getAppByController($controller);
$action = static::getRealMethod($controller, $callback[1]) ?? '';
}
$callback = static::getCallback($app, $callback, $args, true, $route);
static::$_callbacks[$key] = [$callback, $app, $controller ? $controller : '', $action, $route];
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
$callback = static::getCallback($plugin, $app, $callback, $args, true, $route);
static::collectCallbacks($key, [$callback, $plugin, $app, $controller ?: '', $action, $route]);
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request);
if (\count(static::$_callbacks) > 1024) {
static::clearCache();
}
return true;
}
return false;
}
/**
* @param $connection
* @param $path
* @param $key
* @param $request
* @param TcpConnection $connection
* @param string $path
* @param string $key
* @param Request $request
* @return bool
*/
protected static function findFile($connection, $path, $key, $request)
protected static function findFile(TcpConnection $connection, string $path, string $key, $request)
{
if (preg_match('/%[0-9a-f]{2}/i', $path)) {
$path = urldecode($path);
if (static::unsafeUri($connection, $path, $request)) {
return true;
}
}
$path_explodes = \explode('/', trim($path, '/'));
$plugin = '';
if (isset($path_explodes[1]) && $path_explodes[0] === 'app') {
$public_dir = BASE_PATH . "/plugin/{$path_explodes[1]}/public";
$plugin = $path_explodes[1];
$path = \substr($path, strlen("/app/{$path_explodes[1]}/"));
} else {
$public_dir = static::$_publicPath;
}
$file = "$public_dir/$path";
if (!\is_file($file)) {
return false;
}
if (\pathinfo($file, PATHINFO_EXTENSION) === 'php') {
if (!static::$_supportPHPFiles) {
if (!static::config($plugin, 'app.support_php_files', false)) {
return false;
}
static::$_callbacks[$key] = [function ($request) use ($file) {
static::collectCallbacks($key, [function () use ($file) {
return static::execPhpFile($file);
}, '', '', '', null];
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
}, '', '', '', '', null]);
[, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, static::execPhpFile($file), $request);
return true;
}
if (!static::$_supportStaticFiles) {
if (!static::config($plugin, 'static.enable', false)) {
return false;
}
static::$_callbacks[$key] = [static::getCallback('__static__', function ($request) use ($file) {
static::collectCallbacks($key, [static::getCallback($plugin, '__static__', function ($request) use ($file) {
\clearstatcache(true, $file);
if (!\is_file($file)) {
$callback = static::getFallback();
return $callback($request);
}
return (new Response())->file($file);
}, null, false), '', '', '', null];
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
}, null, false), '', '', '', '', null]);
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request);
return true;
}
/**
* @param TcpConnection $connection
* @param $response
* @param Response $response
* @param Request $request
* @return void
*/
protected static function send(TcpConnection $connection, $response, Request $request)
protected static function send(TcpConnection $connection, $response, $request)
{
$keep_alive = $request->header('connection');
static::$_request = static::$_connection = null;
if (($keep_alive === null && $request->protocolVersion() === '1.1')
|| $keep_alive === 'keep-alive' || $keep_alive === 'Keep-Alive'
) {
......@@ -400,112 +446,111 @@ class App
}
/**
* @param $path
* @return array|bool
* @param string $path
* @return array|false
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \ReflectionException
*/
protected static function parseControllerAction($path)
protected static function parseControllerAction(string $path)
{
$suffix = config('app.controller_suffix', '');
$app = '';
if ($path === '/' || $path === '') {
$controller_class = 'app\controller\Index' . $suffix;
$path_explode = \explode('/', trim($path, '/'));
$is_plugin = isset($path_explode[1]) && $path_explode[0] === 'app';
$config_prefix = $is_plugin ? "plugin.{$path_explode[1]}." : '';
$path_prefix = $is_plugin ? "/app/{$path_explode[1]}" : '';
$class_prefix = $is_plugin ? "plugin\\{$path_explode[1]}" : '';
$suffix = Config::get("{$config_prefix}app.controller_suffix", '');
$relative_path = \trim(substr($path, strlen($path_prefix)), '/');
$path_explode = $relative_path ? \explode('/', $relative_path) : [];
$action = 'index';
if ($controller_action = static::getControllerAction($controller_class, $action)) {
if ($controller_action = static::guessControllerAction($path_explode, $action, $suffix, $class_prefix)) {
return $controller_action;
}
$controller_class = 'app\index\controller\Index' . $suffix;
if ($controller_action = static::getControllerAction($controller_class, $action)) {
return $controller_action;
$action = \end($path_explode);
unset($path_explode[count($path_explode) - 1]);
return static::guessControllerAction($path_explode, $action, $suffix, $class_prefix);
}
return false;
}
if ($path && $path[0] === '/') {
$path = \substr($path, 1);
}
$explode = \explode('/', $path);
$action = 'index';
$controller = $explode[0];
if ($controller === '') {
return false;
}
if (!empty($explode[1])) {
$action = $explode[1];
}
$controller_class = "app\\controller\\$controller$suffix";
/**
* @param $path_explode
* @param $action
* @param $suffix
* @return array|false
* @throws \ReflectionException
*/
protected static function guessControllerAction($path_explode, $action, $suffix, $class_prefix)
{
$map[] = "$class_prefix\\app\\controller\\" . \implode('\\', $path_explode);
foreach ($path_explode as $index => $section) {
$tmp = $path_explode;
\array_splice($tmp, $index, 1, [$section, 'controller']);
$map[] = "$class_prefix\\" . \implode('\\', \array_merge(['app'], $tmp));
}
$last_index = \count($map) - 1;
$map[$last_index] = \trim($map[$last_index], '\\') . '\\index';
foreach ($map as $controller_class) {
$controller_class .= $suffix;
if ($controller_action = static::getControllerAction($controller_class, $action)) {
return $controller_action;
}
$app = $explode[0];
$controller = $action = 'index';
if (!empty($explode[1])) {
$controller = $explode[1];
if (!empty($explode[2])) {
$action = $explode[2];
}
}
$controller_class = "app\\$app\\controller\\$controller$suffix";
if ($controller_action = static::getControllerAction($controller_class, $action)) {
return $controller_action;
}
return false;
}
/**
* @param $controller_class
* @param $action
* @param string $controller_class
* @param string $action
* @return array|false
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \ReflectionException
*/
protected static function getControllerAction($controller_class, $action)
protected static function getControllerAction(string $controller_class, string $action)
{
if (static::loadController($controller_class) && ($controller_class = (new \ReflectionClass($controller_class))->name) && \is_callable([$instance = static::$_container->get($controller_class), $action])) {
if (static::loadController($controller_class) && ($controller_class = (new \ReflectionClass($controller_class))->name) && \method_exists($controller_class, $action)) {
return [
'plugin' => static::getPluginByClass($controller_class),
'app' => static::getAppByController($controller_class),
'controller' => $controller_class,
'action' => static::getRealMethod($controller_class, $action),
'instance' => $instance,
'action' => static::getRealMethod($controller_class, $action)
];
}
return false;
}
/**
* @param $controller_class
* @param string $controller_class
* @return bool
*/
protected static function loadController($controller_class)
protected static function loadController(string $controller_class)
{
static $controller_files = [];
if (empty($controller_files)) {
$app_path = static::$_appPath;
$dir_iterator = new \RecursiveDirectoryIterator($app_path);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
$app_base_path_length = \strrpos($app_path, DIRECTORY_SEPARATOR) + 1;
foreach ($iterator as $spl_file) {
$file = (string)$spl_file;
if (\is_dir($file) || false === \strpos(strtolower($file), '/controller/') || $spl_file->getExtension() !== 'php') {
continue;
if (\class_exists($controller_class)) {
return true;
}
$controller_files[$file] = \str_replace(DIRECTORY_SEPARATOR, "\\", \strtolower(\substr(\substr($file, $app_base_path_length), 0, -4)));
$explodes = \explode('\\', strtolower(ltrim($controller_class, '\\')));
$base_path = $explodes[0] === 'plugin' ? BASE_PATH . '/plugin' : static::$_appPath;
unset($explodes[0]);
$file_name = \array_pop($explodes) . '.php';
$finded = true;
foreach ($explodes as $path_section) {
if (!$finded) {
break;
}
$dirs = Util::scanDir($base_path, false);
$finded = false;
foreach ($dirs as $name) {
if (\strtolower($name) === $path_section) {
$base_path = "$base_path/$name";
$finded = true;
break;
}
if (\class_exists($controller_class)) {
return true;
}
$controller_class = \strtolower($controller_class);
if ($controller_class[0] === "\\") {
$controller_class = \substr($controller_class, 1);
}
foreach ($controller_files as $real_path => $class_name) {
if ($class_name === $controller_class) {
require_once $real_path;
if (!$finded) {
return false;
}
foreach (\scandir($base_path) ?: [] as $name) {
if (\strtolower($name) === $file_name) {
require_once "$base_path/$name";
if (\class_exists($controller_class, false)) {
return true;
}
......@@ -515,26 +560,39 @@ class App
}
/**
* @param $controller_calss
* @return string
* @param string $controller_class
* @return mixed|string
*/
protected static function getAppByController($controller_calss)
public static function getPluginByClass(string $controller_class)
{
if ($controller_calss[0] === '\\') {
$controller_calss = \substr($controller_calss, 1);
$controller_class = \trim($controller_class, '\\');
$tmp = \explode('\\', $controller_class, 3);
if ($tmp[0] !== 'plugin') {
return '';
}
$tmp = \explode('\\', $controller_calss, 3);
if (!isset($tmp[1])) {
return $tmp[1] ?? '';
}
/**
* @param string $controller_class
* @return mixed|string
*/
protected static function getAppByController(string $controller_class)
{
$controller_class = \trim($controller_class, '\\');
$tmp = \explode('\\', $controller_class, 5);
$pos = $tmp[0] === 'plugin' ? 3 : 1;
if (!isset($tmp[$pos])) {
return '';
}
return strtolower($tmp[1]) === 'controller' ? '' : $tmp[1];
return \strtolower($tmp[$pos]) === 'controller' ? '' : $tmp[$pos];
}
/**
* @param $file
* @return string
* @param string $file
* @return false|string
*/
public static function execPhpFile($file)
public static function execPhpFile(string $file)
{
\ob_start();
// Try to include php file.
......@@ -547,19 +605,11 @@ class App
}
/**
* Clear cache.
*/
public static function clearCache()
{
static::$_callbacks = [];
}
/**
* @param $class
* @param $method
* @param string $class
* @param string $method
* @return string
*/
protected static function getRealMethod($class, $method)
protected static function getRealMethod(string $class, string $method)
{
$method = \strtolower($method);
$methods = \get_class_methods($class);
......@@ -571,4 +621,15 @@ class App
return $method;
}
/**
* @param string $plugin
* @param string $key
* @param $default
* @return array|mixed|null
*/
protected static function config(string $plugin, string $key, $default = null)
{
return Config::get($plugin ? "plugin.$plugin.$key" : $key, $default);
}
}
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
use Workerman\Worker;
......
......@@ -33,83 +33,169 @@ class Config
protected static $_loaded = false;
/**
* @param $config_path
* @param string $config_path
* @param array $exclude_file
* @param string|null $key
* @return void
*/
public static function load($config_path, $exclude_file = [])
public static function load(string $config_path, array $exclude_file = [], string $key = null)
{
static::$_configPath = $config_path;
if (!$config_path) {
return;
}
$dir_iterator = new \RecursiveDirectoryIterator($config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
/** var SplFileInfo $file */
if (is_dir($file) || $file->getExtension() != 'php' || \in_array($file->getBaseName('.php'), $exclude_file)) {
continue;
static::$_loaded = false;
$config = static::loadFromDir($config_path, $exclude_file);
if (!$config) {
static::$_loaded = true;
return;
}
$app_config_file = $file->getPath() . '/app.php';
if (!is_file($app_config_file)) {
continue;
if ($key !== null) {
foreach (\array_reverse(\explode('.', $key)) as $k) {
$config = [$k => $config];
}
$relative_path = str_replace($config_path . DIRECTORY_SEPARATOR, '', substr($file, 0, -4));
$explode = array_reverse(explode(DIRECTORY_SEPARATOR, $relative_path));
if (count($explode) >= 2) {
$app_config = include $app_config_file;
if (empty($app_config['enable'])) {
}
static::$_config = \array_replace_recursive(static::$_config, $config);
static::formatConfig();
static::$_loaded = true;
}
/**
* This deprecated method will certainly be removed in the future
*
* @deprecated
* @param string $config_path
* @param array $exclude_file
* @return void
*/
public static function reload(string $config_path, array $exclude_file = [])
{
static::load($config_path, $exclude_file);
}
/**
* @return void
*/
protected static function formatConfig()
{
$config = static::$_config;
// Merge log config
foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['log'] ?? [] as $key => $item) {
$config['log']["plugin.$firm.$key"] = $item;
}
}
foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['log'] ?? [] as $key => $item) {
$config['log']["plugin.$firm.$name.$key"] = $item;
}
$config = include $file;
foreach ($explode as $section) {
$tmp = [];
$tmp[$section] = $config;
$config = $tmp;
}
static::$_config = array_replace_recursive(static::$_config, $config);
}
// Merge database config
foreach (static::$_config['plugin'] ?? [] as $firm => $projects) {
foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['database']['connections'] ?? [] as $key => $connection) {
$config['database']['connections']["plugin.$firm.$key"] = $connection;
}
}
foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['database']['connections'] ?? [] as $key => $connection) {
static::$_config['database']['connections']["plugin.$firm.$name.$key"] = $connection;
$config['database']['connections']["plugin.$firm.$name.$key"] = $connection;
}
}
}
if (!empty(static::$_config['database']['connections'])) {
static::$_config['database']['default'] = static::$_config['database']['default'] ?? key(static::$_config['database']['connections']);
if (!empty($config['database']['connections'])) {
$config['database']['default'] = $config['database']['default'] ?? key($config['database']['connections']);
}
// Merge thinkorm config
foreach (static::$_config['plugin'] ?? [] as $firm => $projects) {
foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['thinkorm']['connections'] ?? [] as $key => $connection) {
$config['thinkorm']['connections']["plugin.$firm.$key"] = $connection;
}
}
foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['thinkorm']['connections'] ?? [] as $key => $connection) {
static::$_config['thinkorm']['connections']["plugin.$firm.$name.$key"] = $connection;
$config['thinkorm']['connections']["plugin.$firm.$name.$key"] = $connection;
}
}
}
if (!empty(static::$_config['thinkorm']['connections'])) {
static::$_config['thinkorm']['default'] = static::$_config['thinkorm']['default'] ?? key(static::$_config['thinkorm']['connections']);
if (!empty($config['thinkorm']['connections'])) {
$config['thinkorm']['default'] = $config['thinkorm']['default'] ?? \key($config['thinkorm']['connections']);
}
// Merge redis config
foreach (static::$_config['plugin'] ?? [] as $firm => $projects) {
foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['redis'] ?? [] as $key => $connection) {
$config['redis']["plugin.$firm.$key"] = $connection;
}
}
foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['redis'] ?? [] as $key => $connection) {
static::$_config['redis']["plugin.$firm.$name.$key"] = $connection;
$config['redis']["plugin.$firm.$name.$key"] = $connection;
}
}
}
static::$_config = $config;
}
static::$_loaded = true;
/**
* @param string $config_path
* @param array $exclude_file
* @return array
*/
public static function loadFromDir(string $config_path, array $exclude_file = [])
{
$all_config = [];
$dir_iterator = new \RecursiveDirectoryIterator($config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
/** var SplFileInfo $file */
if (\is_dir($file) || $file->getExtension() != 'php' || \in_array($file->getBaseName('.php'), $exclude_file)) {
continue;
}
$app_config_file = $file->getPath() . '/app.php';
if (!\is_file($app_config_file)) {
continue;
}
$relative_path = \str_replace($config_path . DIRECTORY_SEPARATOR, '', substr($file, 0, -4));
$explode = \array_reverse(\explode(DIRECTORY_SEPARATOR, $relative_path));
if (\count($explode) >= 2) {
$app_config = include $app_config_file;
if (empty($app_config['enable'])) {
continue;
}
}
$config = include $file;
foreach ($explode as $section) {
$tmp = [];
$tmp[$section] = $config;
$config = $tmp;
}
$all_config = \array_replace_recursive($all_config, $config);
}
return $all_config;
}
/**
* @param null $key
* @param null $default
* @return array|mixed|null
* @param string|null $key
* @param mixed $default
* @return array|mixed|void|null
*/
public static function get($key = null, $default = null)
public static function get(string $key = null, $default = null)
{
if ($key === null) {
return static::$_config;
......@@ -134,11 +220,11 @@ class Config
}
/**
* @param $key
* @param $default
* @return array|mixed|void|null
* @param string $key
* @param mixed $default
* @return array|mixed|null
*/
protected static function read($key, $default = null)
protected static function read(string $key, $default = null)
{
$path = static::$_configPath;
if ($path === '') {
......@@ -147,11 +233,11 @@ class Config
$keys = $key_array = \explode('.', $key);
foreach ($key_array as $index => $section) {
unset($keys[$index]);
if (is_file($file = "$path/$section.php")) {
if (\is_file($file = "$path/$section.php")) {
$config = include $file;
return static::find($keys, $config, $default);
}
if (!is_dir($path = "$path/$section")) {
if (!\is_dir($path = "$path/$section")) {
return $default;
}
}
......@@ -159,14 +245,14 @@ class Config
}
/**
* @param $key_array
* @param $stack
* @param $default
* @param array $key_array
* @param mixed $stack
* @param mixed $default
* @return array|mixed
*/
protected static function find($key_array, $stack, $default)
protected static function find(array $key_array, $stack, $default)
{
if (!is_array($stack)) {
if (!\is_array($stack)) {
return $default;
}
$value = $stack;
......@@ -179,15 +265,4 @@ class Config
return $value;
}
/**
* @param $config_path
* @param array $exclude_file
*/
public static function reload($config_path, $exclude_file = [])
{
static::$_config = [];
static::load($config_path, $exclude_file);
}
}
<?php
namespace Webman;
use Psr\Container\ContainerInterface;
......@@ -21,10 +22,10 @@ class Container implements ContainerInterface
* @return mixed
* @throws NotFoundException
*/
public function get($name)
public function get(string $name)
{
if (!isset($this->_instances[$name])) {
if (!class_exists($name)) {
if (!\class_exists($name)) {
throw new NotFoundException("Class '$name' not found");
}
$this->_instances[$name] = new $name();
......@@ -36,20 +37,20 @@ class Container implements ContainerInterface
* @param string $name
* @return bool
*/
public function has($name): bool
public function has(string $name): bool
{
return \array_key_exists($name, $this->_instances);
}
/**
* @param $name
* @param string $name
* @param array $constructor
* @return mixed
* @throws NotFoundException
*/
public function make($name, array $constructor = [])
public function make(string $name, array $constructor = [])
{
if (!class_exists($name)) {
if (!\class_exists($name)) {
throw new NotFoundException("Class '$name' not found");
}
return new $name(... array_values($constructor));
......
......@@ -11,16 +11,17 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Exception;
use Throwable;
use Psr\Log\LoggerInterface;
use Throwable;
use Webman\Http\Request;
use Webman\Http\Response;
/**
* Class Handler
* @package support\exception
* @package Support\Exception
*/
class ExceptionHandler implements ExceptionHandlerInterface
{
......@@ -37,9 +38,7 @@ class ExceptionHandler implements ExceptionHandlerInterface
/**
* @var array
*/
public $dontReport = [
];
public $dontReport = [];
/**
* ExceptionHandler constructor.
......@@ -61,8 +60,11 @@ class ExceptionHandler implements ExceptionHandlerInterface
if ($this->shouldntReport($exception)) {
return;
}
$this->_logger->error($exception->getMessage(), ['exception' => (string)$exception]);
$logs = '';
if ($request = \request()) {
$logs = $request->getRealIp() . ' ' . $request->method() . ' ' . \trim($request->fullUrl(), '/');
}
$this->_logger->error($logs . PHP_EOL . $exception);
}
/**
......@@ -70,16 +72,16 @@ class ExceptionHandler implements ExceptionHandlerInterface
* @param Throwable $exception
* @return Response
*/
public function render(Request $request, Throwable $exception) : Response
public function render(Request $request, Throwable $exception): Response
{
$code = $exception->getCode();
if ($request->expectsJson()) {
$json = ['code' => $code ? $code : 500, 'msg' => $exception->getMessage()];
$json = ['code' => $code ? $code : 500, 'msg' => $this->_debug ? $exception->getMessage() : 'Server internal error'];
$this->_debug && $json['traces'] = (string)$exception;
return new Response(200, ['Content-Type' => 'application/json'],
json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
\json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
$error = $this->_debug ? nl2br((string)$exception) : 'Server internal error';
$error = $this->_debug ? \nl2br((string)$exception) : 'Server internal error';
return new Response(500, [], $error);
}
......@@ -87,7 +89,8 @@ class ExceptionHandler implements ExceptionHandlerInterface
* @param Throwable $e
* @return bool
*/
protected function shouldntReport(Throwable $e) {
protected function shouldntReport(Throwable $e)
{
foreach ($this->dontReport as $type) {
if ($e instanceof $type) {
return true;
......
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Exception;
use Throwable;
......@@ -30,5 +31,5 @@ interface ExceptionHandlerInterface
* @param Throwable $e
* @return Response
*/
public function render(Request $request, Throwable $e) : Response;
public function render(Request $request, Throwable $e): Response;
}
\ No newline at end of file
......@@ -11,12 +11,15 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Exception;
use RuntimeException;
/**
* Class FileException
* @package Webman\Exception
*/
class FileException extends \RuntimeException
class FileException extends RuntimeException
{
}
\ No newline at end of file
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
use Webman\Exception\FileException;
......@@ -19,25 +20,25 @@ class File extends \SplFileInfo
{
/**
* @param $destination
* @param string $destination
* @return File
*/
public function move($destination)
public function move(string $destination)
{
set_error_handler(function ($type, $msg) use (&$error) {
\set_error_handler(function ($type, $msg) use (&$error) {
$error = $msg;
});
$path = pathinfo($destination, PATHINFO_DIRNAME);
if (!is_dir($path) && !mkdir($path, 0777, true)) {
restore_error_handler();
throw new FileException(sprintf('Unable to create the "%s" directory (%s)', $path, strip_tags($error)));
$path = \pathinfo($destination, PATHINFO_DIRNAME);
if (!\is_dir($path) && !\mkdir($path, 0777, true)) {
\restore_error_handler();
throw new FileException(\sprintf('Unable to create the "%s" directory (%s)', $path, \strip_tags($error)));
}
if (!rename($this->getPathname(), $destination)) {
restore_error_handler();
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $destination, strip_tags($error)));
\restore_error_handler();
throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $destination, \strip_tags($error)));
}
restore_error_handler();
@chmod($destination, 0666 & ~umask());
\restore_error_handler();
@\chmod($destination, 0666 & ~\umask());
return new self($destination);
}
......
......@@ -13,15 +13,13 @@
*/
namespace Webman;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector;
use Workerman\Protocols\Http\Session\FileSessionHandler as SessionHandler;
/**
* Class FileSessionHandler
* This deprecated class will certainly be removed in the future.
* Please use Webman\Session\FileSessionHandler
* @deprecated
* @package Webman
*/
class FileSessionHandler extends SessionHandler
class FileSessionHandler extends Session\FileSessionHandler
{
}
......@@ -11,11 +11,11 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Http;
use Webman\App;
use Webman\Route\Route;
use Webman\Http\UploadFile;
/**
* Class Request
......@@ -23,6 +23,11 @@ use Webman\Http\UploadFile;
*/
class Request extends \Workerman\Protocols\Http\Request
{
/**
* @var string
*/
public $plugin = null;
/**
* @var string
*/
......@@ -97,7 +102,7 @@ class Request extends \Workerman\Protocols\Http\Request
/**
* @param string|null $name
* @return null|array|UploadFile
* @return null|UploadFile[]|UploadFile
*/
public function file($name = null)
{
......@@ -125,10 +130,10 @@ class Request extends \Workerman\Protocols\Http\Request
}
/**
* @param $file
* @param array $file
* @return UploadFile
*/
protected function parseFile($file)
protected function parseFile(array $file)
{
return new UploadFile($file['tmp_name'], $file['name'], $file['type'], $file['error']);
}
......@@ -137,7 +142,7 @@ class Request extends \Workerman\Protocols\Http\Request
* @param array $files
* @return array
*/
protected function parseFiles($files)
protected function parseFiles(array $files)
{
$upload_files = [];
foreach ($files as $key => $file) {
......@@ -186,7 +191,7 @@ class Request extends \Workerman\Protocols\Http\Request
* @param bool $safe_mode
* @return string
*/
public function getRealIp($safe_mode = true)
public function getRealIp(bool $safe_mode = true)
{
$remote_ip = $this->getRemoteIp();
if ($safe_mode && !static::isIntranetIp($remote_ip)) {
......@@ -242,25 +247,25 @@ class Request extends \Workerman\Protocols\Http\Request
*/
public function acceptJson()
{
return false !== strpos($this->header('accept', ''), 'json');
return false !== \strpos($this->header('accept', ''), 'json');
}
/**
* @param string $ip
* @return bool
*/
public static function isIntranetIp($ip)
public static function isIntranetIp(string $ip)
{
// Not validate ip .
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
if (!\filter_var($ip, \FILTER_VALIDATE_IP)) {
return false;
}
// Is intranet ip ? For IPv4, the result of false may not be accurate, so we need to check it manually later .
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
if (!\filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE)) {
return true;
}
// Manual check only for IPv4 .
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
if (!\filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
return false;
}
// Manual check .
......@@ -274,7 +279,7 @@ class Request extends \Workerman\Protocols\Http\Request
3405803776 => 3405804031, // 203.0.113.0 - 203.0.113.255
3758096384 => 4026531839, // 224.0.0.0 - 239.255.255.255
];
$ip_long = ip2long($ip);
$ip_long = \ip2long($ip);
foreach ($reserved_ips as $ip_start => $ip_end) {
if (($ip_long >= $ip_start) && ($ip_long <= $ip_end)) {
return true;
......
......@@ -11,9 +11,11 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Http;
use Webman\App;
use Throwable;
/**
* Class Response
......@@ -21,11 +23,16 @@ use Webman\App;
*/
class Response extends \Workerman\Protocols\Http\Response
{
/**
* @var Throwable
*/
protected $_exception = null;
/**
* @param string $file
* @return $this
*/
public function file($file)
public function file(string $file)
{
if ($this->notModifiedSince($file)) {
return $this->withStatus(304);
......@@ -38,7 +45,7 @@ class Response extends \Workerman\Protocols\Http\Response
* @param string $download_name
* @return $this
*/
public function download($file, $download_name = '')
public function download(string $file, string $download_name = '')
{
$this->withFile($file);
if ($download_name) {
......@@ -48,10 +55,10 @@ class Response extends \Workerman\Protocols\Http\Response
}
/**
* @param $file
* @param string $file
* @return bool
*/
protected function notModifiedSince($file)
protected function notModifiedSince(string $file)
{
$if_modified_since = App::request()->header('if-modified-since');
if ($if_modified_since === null || !($mtime = \filemtime($file))) {
......@@ -59,4 +66,16 @@ class Response extends \Workerman\Protocols\Http\Response
}
return $if_modified_since === \gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
}
/**
* @param Throwable $exception
* @return Throwable
*/
public function exception($exception = null)
{
if ($exception) {
$this->_exception = $exception;
}
return $this->_exception;
}
}
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Http;
use Webman\File;
......@@ -38,12 +39,13 @@ class UploadFile extends File
/**
* UploadFile constructor.
* @param $file_name
* @param $upload_name
* @param $upload_mime_type
* @param $upload_error_code
*
* @param string $file_name
* @param string $upload_name
* @param string $upload_mime_type
* @param int $upload_error_code
*/
public function __construct($file_name, $upload_name, $upload_mime_type, $upload_error_code)
public function __construct(string $file_name, string $upload_name, string $upload_mime_type, int $upload_error_code)
{
$this->_uploadName = $upload_name;
$this->_uploadMimeType = $upload_mime_type;
......@@ -72,7 +74,7 @@ class UploadFile extends File
*/
public function getUploadExtension()
{
return pathinfo($this->_uploadName, PATHINFO_EXTENSION);
return \pathinfo($this->_uploadName, PATHINFO_EXTENSION);
}
/**
......
<?php
namespace Webman;
class Install
......@@ -10,8 +11,9 @@ class Install
*/
protected static $pathRelation = [
'start.php' => 'start.php',
'windows.php' => 'windows.php',
'support/bootstrap.php' => 'support/bootstrap.php',
'support/Plugin.php' => 'support/Plugin.php',
'support/helpers.php' => 'support/helpers.php',
];
/**
......@@ -40,14 +42,13 @@ class Install
{
foreach (static::$pathRelation as $source => $dest) {
if ($pos = strrpos($dest, '/')) {
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
$parent_dir = base_path() . '/' . substr($dest, 0, $pos);
if (!is_dir($parent_dir)) {
mkdir($parent_dir, 0777, true);
}
}
copy_dir(__DIR__ . "/$source", base_path()."/$dest", true);
echo "Create $dest
";
copy_dir(__DIR__ . "/$source", base_path() . "/$dest", true);
echo "Create $dest\r\n";
}
}
......
<?php
namespace Webman;
use Psr\Container\ContainerInterface;
use Webman\App;
namespace Webman;
/**
* This file is part of webman.
......@@ -16,13 +14,8 @@ use Webman\App;
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
class Middleware
{
/**
* @var ContainerInterface
*/
protected static $_container = null;
/**
* @var array
......@@ -30,17 +23,22 @@ class Middleware
protected static $_instances = [];
/**
* @param $all_middlewares
* @param array $all_middlewares
* @param string $plugin
* @return void
*/
public static function load($all_middlewares)
public static function load($all_middlewares, string $plugin = '')
{
if (!\is_array($all_middlewares)) {
return;
}
foreach ($all_middlewares as $app_name => $middlewares) {
if (!\is_array($middlewares)) {
throw new \RuntimeException('Bad middleware config');
}
foreach ($middlewares as $class_name) {
if (\method_exists($class_name, 'process')) {
static::$_instances[$app_name][] = [static::container()->get($class_name), 'process'];
static::$_instances[$plugin][$app_name][] = [$class_name, 'process'];
} else {
// @todo Log
echo "middleware $class_name::process not exsits\n";
......@@ -50,42 +48,27 @@ class Middleware
}
/**
* @param $app_name
* @param string $plugin
* @param string $app_name
* @param bool $with_global_middleware
* @return array
* @return array|mixed
*/
public static function getMiddleware($app_name, $with_global_middleware = true)
public static function getMiddleware(string $plugin, string $app_name, bool $with_global_middleware = true)
{
$global_middleware = $with_global_middleware && isset(static::$_instances['']) ? static::$_instances[''] : [];
$global_middleware = $with_global_middleware && isset(static::$_instances[$plugin]['']) ? static::$_instances[$plugin][''] : [];
if ($app_name === '') {
return \array_reverse($global_middleware);
}
$app_middleware = static::$_instances[$app_name] ?? [];
$app_middleware = static::$_instances[$plugin][$app_name] ?? [];
return \array_reverse(\array_merge($global_middleware, $app_middleware));
}
/**
* @param $app_name
* @return bool
* @deprecated
* @return void
*/
public static function hasMiddleware($app_name)
public static function container($_)
{
return isset(static::$_instances[$app_name]);
}
/**
* @param $container
* @return ContainerInterface
*/
public static function container($container = null)
{
if ($container) {
static::$_container = $container;
}
if (!static::$_container) {
static::$_container = App::container();
}
return static::$_container;
}
}
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
use Webman\Http\Request;
......
......@@ -11,11 +11,11 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector;
use Psr\Container\ContainerInterface;
use Webman\Route\Route as RouteObject;
use function FastRoute\simpleDispatcher;
......@@ -25,11 +25,6 @@ use function FastRoute\simpleDispatcher;
*/
class Route
{
/**
* @var ContainerInterface
*/
protected static $_container = null;
/**
* @var Route
*/
......@@ -45,11 +40,6 @@ class Route
*/
protected static $_collector = null;
/**
* @var bool
*/
protected static $_hasRoute = false;
/**
* @var null|callable
*/
......@@ -68,7 +58,7 @@ class Route
/**
* @var bool
*/
protected static $_disableDefaultRoute = false;
protected static $_disableDefaultRoute = [];
/**
* @var RouteObject[]
......@@ -81,103 +71,107 @@ class Route
protected $_routes = [];
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function get($path, $callback)
public static function get(string $path, $callback)
{
return static::addRoute('GET', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function post($path, $callback)
public static function post(string $path, $callback)
{
return static::addRoute('POST', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function put($path, $callback)
public static function put(string $path, $callback)
{
return static::addRoute('PUT', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function patch($path, $callback)
public static function patch(string $path, $callback)
{
return static::addRoute('PATCH', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function delete($path, $callback)
public static function delete(string $path, $callback)
{
return static::addRoute('DELETE', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function head($path, $callback)
public static function head(string $path, $callback)
{
return static::addRoute('HEAD', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function options($path, $callback)
public static function options(string $path, $callback)
{
return static::addRoute('OPTIONS', $path, $callback);
}
/**
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function any($path, $callback)
public static function any(string $path, $callback)
{
return static::addRoute(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $path, $callback);
}
/**
* @param $method
* @param $path
* @param $callback
* @param string $path
* @param callable $callback
* @return RouteObject
*/
public static function add($method, $path, $callback)
public static function add($method, string $path, $callback)
{
return static::addRoute($method, $path, $callback);
}
/**
* @param $path
* @param $callback
* @return Route
* @param string|callable $path
* @param callable|null $callback
* @return static
*/
public static function group($path, $callback)
public static function group($path, callable $callback = null)
{
if ($callback === null) {
$callback = $path;
$path = '';
}
$previous_group_prefix = static::$_groupPrefix;
static::$_groupPrefix = $previous_group_prefix . $path;
$instance = static::$_instance = new static;
......@@ -196,37 +190,37 @@ class Route
public static function resource(string $name, string $controller, array $options = [])
{
$name = trim($name, '/');
if (is_array($options) && !empty($options)) {
$diff_options = array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']);
if (\is_array($options) && !empty($options)) {
$diff_options = \array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']);
if (!empty($diff_options)) {
foreach ($diff_options as $action) {
static::any("/{$name}/{$action}[/{id}]", [$controller, $action])->name("{$name}.{$action}");
}
}
// 注册路由 由于顺序不同会导致路由无效 因此不适用循环注册
if (in_array('index', $options)) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
if (in_array('create', $options)) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
if (in_array('store', $options)) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
if (in_array('update', $options)) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
if (in_array('show', $options)) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
if (in_array('edit', $options)) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
if (in_array('destroy', $options)) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
if (in_array('recovery', $options)) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
if (\in_array('index', $options)) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
if (\in_array('create', $options)) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
if (\in_array('store', $options)) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
if (\in_array('update', $options)) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
if (\in_array('show', $options)) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
if (\in_array('edit', $options)) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
if (\in_array('destroy', $options)) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
if (\in_array('recovery', $options)) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
} else {
//为空时自动注册所有常用路由
if (method_exists($controller, 'index')) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
if (method_exists($controller, 'create')) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
if (method_exists($controller, 'store')) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
if (method_exists($controller, 'update')) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
if (method_exists($controller, 'show')) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
if (method_exists($controller, 'edit')) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
if (method_exists($controller, 'destroy')) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
if (method_exists($controller, 'recovery')) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
if (\method_exists($controller, 'index')) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
if (\method_exists($controller, 'create')) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
if (\method_exists($controller, 'store')) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
if (\method_exists($controller, 'update')) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
if (\method_exists($controller, 'show')) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
if (\method_exists($controller, 'edit')) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
if (\method_exists($controller, 'destroy')) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
if (\method_exists($controller, 'recovery')) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
}
}
/**
* @return array
* @return RouteObject[]
*/
public static function getRoutes()
{
......@@ -235,18 +229,20 @@ class Route
/**
* disableDefaultRoute.
*
* @return void
*/
public static function disableDefaultRoute()
public static function disableDefaultRoute($plugin = '')
{
static::$_disableDefaultRoute = true;
static::$_disableDefaultRoute[$plugin] = true;
}
/**
* @return bool
*/
public static function hasDisableDefaultRoute()
public static function hasDisableDefaultRoute($plugin = '')
{
return static::$_disableDefaultRoute === true;
return static::$_disableDefaultRoute[$plugin] ?? false;
}
/**
......@@ -272,7 +268,7 @@ class Route
* @param $name
* @param RouteObject $instance
*/
public static function setByName($name, RouteObject $instance)
public static function setByName(string $name, RouteObject $instance)
{
static::$_nameList[$name] = $instance;
}
......@@ -281,57 +277,58 @@ class Route
* @param $name
* @return null|RouteObject
*/
public static function getByName($name)
public static function getByName(string $name)
{
return static::$_nameList[$name] ?? null;
}
/**
* @param $method
* @param $path
* @param string $method
* @param string $path
* @return array
*/
public static function dispatch($method, $path)
public static function dispatch($method, string $path)
{
return static::$_dispatcher->dispatch($method, $path);
}
/**
* @param $path
* @param $callback
* @return array|bool|callable
* @param string $path
* @param callable $callback
* @return callable|false|string[]
*/
public static function convertToCallable($path, $callback)
public static function convertToCallable(string $path, $callback)
{
if (\is_string($callback) && \strpos($callback, '@')) {
$callback = \explode('@', $callback, 2);
}
if (\is_array($callback)) {
$callback = \array_values($callback);
if (isset($callback[1]) && \is_string($callback[0]) && \class_exists($callback[0])) {
$callback = [static::container()->get($callback[0]), $callback[1]];
}
}
if (!\is_array($callback)) {
if (!\is_callable($callback)) {
echo "Route set to $path is not callable\n";
$call_str = \is_scalar($callback) ? $callback : 'Closure';
echo "Route $path $call_str is not callable\n";
return false;
}
} else {
$callback = \array_values($callback);
if (!isset($callback[1]) || !\class_exists($callback[0]) || !\method_exists($callback[0], $callback[1])) {
echo "Route $path " . \json_encode($callback) . " is not callable\n";
return false;
}
}
return $callback;
}
/**
* @param $methods
* @param $path
* @param $callback
* @param array $methods
* @param string $path
* @param callable $callback
* @return RouteObject
*/
protected static function addRoute($methods, $path, $callback)
protected static function addRoute($methods, string $path, $callback)
{
static::$_hasRoute = true;
$route = new RouteObject($methods, static::$_groupPrefix . $path, $callback);
static::$_allRoutes[] = $route;
......@@ -345,21 +342,31 @@ class Route
}
/**
* @return bool
* @param array $paths
* @return void
*/
public static function load($config_path)
public static function load($paths)
{
if (!is_dir($config_path)) {
$config_path = pathinfo($config_path, PATHINFO_DIRNAME);
if (!\is_array($paths)) {
return;
}
static::$_dispatcher = simpleDispatcher(function (RouteCollector $route) use ($config_path) {
static::$_dispatcher = simpleDispatcher(function (RouteCollector $route) use ($paths) {
Route::setCollector($route);
foreach ($paths as $config_path) {
$route_config_file = $config_path . '/route.php';
if (\is_file($route_config_file)) {
require_once $route_config_file;
}
foreach (glob($config_path.'/plugin/*/*/route.php') as $file) {
$app_config_file = pathinfo($file, PATHINFO_DIRNAME).'/app.php';
if (!is_dir($plugin_config_path = $config_path . '/plugin')) {
return;
}
$dir_iterator = new \RecursiveDirectoryIterator($plugin_config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
if ($file->getBaseName('.php') !== 'route') {
continue;
}
$app_config_file = pathinfo($file, PATHINFO_DIRNAME) . '/app.php';
if (!is_file($app_config_file)) {
continue;
}
......@@ -369,46 +376,43 @@ class Route
}
require_once $file;
}
}
});
return static::$_hasRoute;
}
/**
* @param $route
* @param RouteCollector $route
* @return void
*/
public static function setCollector($route)
public static function setCollector(RouteCollector $route)
{
static::$_collector = $route;
}
/**
* @param callable $callback
* @return void
*/
public static function fallback(callable $callback) {
if (is_callable($callback)) {
public static function fallback(callable $callback)
{
static::$_fallback = $callback;
}
}
/**
* @return callable|null
*/
public static function getFallback() {
return is_callable(static::$_fallback) ? static::$_fallback : null;
public static function getFallback()
{
return static::$_fallback;
}
/**
* @param $container
* @return ContainerInterface
* @deprecated
* @return void
*/
public static function container($container = null)
public static function container()
{
if ($container) {
static::$_container = $container;
}
if (!static::$_container) {
static::$_container = App::container();
}
return static::$_container;
}
}
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Route;
use FastRoute\Dispatcher\GroupCountBased;
......@@ -48,14 +49,21 @@ class Route
*/
protected $_middlewares = [];
/**
* @var array
*/
protected $_params = [];
/**
* Route constructor.
* @param $methods
* @param $path
*
* @param array $methods
* @param string $path
* @param callable $callback
*/
public function __construct($methods, $path, $callback)
public function __construct($methods, string $path, $callback)
{
$this->_methods = (array) $methods;
$this->_methods = (array)$methods;
$this->_path = $path;
$this->_callback = $callback;
}
......@@ -69,10 +77,10 @@ class Route
}
/**
* @param $name
* @param string $name
* @return $this
*/
public function name($name)
public function name(string $name)
{
$this->_name = $name;
Router::setByName($name, $this);
......@@ -80,7 +88,7 @@ class Route
}
/**
* @param null $middleware
* @param mixed $middleware
* @return $this|array
*/
public function middleware($middleware = null)
......@@ -88,7 +96,7 @@ class Route
if ($middleware === null) {
return $this->_middlewares;
}
$this->_middlewares = array_merge($this->_middlewares, (array)$middleware);
$this->_middlewares = \array_merge($this->_middlewares, (array)$middleware);
return $this;
}
......@@ -124,6 +132,29 @@ class Route
return $this->_middlewares;
}
/**
* @param string|null $name
* @param $default
* @return array|mixed|null
*/
public function param(string $name = null, $default = null)
{
if ($name === null) {
return $this->_params;
}
return $this->_params[$name] ?? $default;
}
/**
* @param array $params
* @return $this
*/
public function setParams(array $params)
{
$this->_params = \array_merge($this->_params, $params);
return $this;
}
/**
* @param $parameters
* @return string
......@@ -133,8 +164,8 @@ class Route
if (empty($parameters)) {
return $this->_path;
}
$path = str_replace(['[', ']'], '', $this->_path);
return preg_replace_callback('/\{(.*?)(?:\:[^\}]*?)*?\}/', function ($matches) use (&$parameters) {
$path = \str_replace(['[', ']'], '', $this->_path);
$path = \preg_replace_callback('/\{(.*?)(?:\:[^\}]*?)*?\}/', function ($matches) use (&$parameters) {
if (!$parameters) {
return $matches[0];
}
......@@ -151,6 +182,7 @@ class Route
}
return $matches[0];
}, $path);
return \count($parameters) > 0 ? $path . '?' . http_build_query($parameters) : $path;
}
}
......@@ -11,17 +11,18 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
namespace Webman\Session;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector;
use Workerman\Protocols\Http\Session\RedisSessionHandler as SessionHandler;
use Workerman\Protocols\Http\Session\FileSessionHandler as FileHandler;
/**
* Class FileSessionHandler
* @package Webman
*/
class RedisSessionHandler extends SessionHandler
class FileSessionHandler extends FileHandler
{
}
<?php
/**
* This file is part of webman.
*
* 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 Webman\Session;
use Workerman\Protocols\Http\Session\RedisClusterSessionHandler as RedisClusterHandler;
class RedisClusterSessionHandler extends RedisClusterHandler
{
}
<?php
/**
* This file is part of webman.
*
* 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 Webman\Session;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector;
use Workerman\Protocols\Http\Session\RedisSessionHandler as RedisHandler;
/**
* Class FileSessionHandler
* @package Webman
*/
class RedisSessionHandler extends RedisHandler
{
}
<?php
namespace Webman;
/**
* This file is part of webman.
*
......@@ -13,33 +12,27 @@ namespace Webman;
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
class RedisClusterSessionHandler extends RedisSessionHandler
/**
* Class Util
* @package Webman
*/
class Util
{
public function __construct($config)
{
$this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime');
$timeout = $config['timeout'] ?? 2;
$read_timeout = $config['read_timeout'] ?? $timeout;
$persistent = $config['persistent'] ?? false;
$auth = $config['auth'] ?? '';
$args = [null, $config['host'], $timeout, $read_timeout, $persistent];
if ($auth) {
$args[] = $auth;
}
$this->_redis = new \RedisCluster(...$args);
if (empty($config['prefix'])) {
$config['prefix'] = 'redis_session_';
}
$this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']);
}
/**
* {@inheritdoc}
* @param string $path
* @return array
*/
public function read($session_id)
public static function scanDir(string $base_path, $with_base_path = true): array
{
return $this->_redis->get($session_id);
if (!is_dir($base_path)) {
return [];
}
$paths = \array_diff(\scandir($base_path), array('.', '..')) ?: [];
return $with_base_path ? \array_map(function($path) use ($base_path) {
return $base_path . DIRECTORY_SEPARATOR . $path;
}, $paths) : $paths;
}
}
......@@ -11,6 +11,7 @@
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman;
interface View
......@@ -21,5 +22,5 @@ interface View
* @param null $app
* @return string
*/
static function render($template, $vars, $app = null);
static function render(string $template, array $vars, string $app = null);
}
#!/usr/bin/env php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Protocols\Http;
use Workerman\Connection\TcpConnection;
use Webman\App;
use Webman\Config;
use Webman\Route;
use Webman\Middleware;
use Dotenv\Dotenv;
use support\Request;
use support\Log;
use support\Container;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
Config::load(config_path(), ['route', 'container']);
if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($timezone);
}
$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
if ( !file_exists($runtime_logs_path) || !is_dir($runtime_logs_path) ) {
if (!mkdir($runtime_logs_path,0777,true)) {
throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
}
}
$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
if ( !file_exists($runtime_views_path) || !is_dir($runtime_views_path) ) {
if (!mkdir($runtime_views_path,0777,true)) {
throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
}
}
Worker::$onMasterReload = function () {
if (function_exists('opcache_get_status')) {
if ($status = opcache_get_status()) {
if (isset($status['scripts']) && $scripts = $status['scripts']) {
foreach (array_keys($scripts) as $file) {
opcache_invalidate($file, true);
}
}
}
}
};
$config = config('server');
Worker::$pidFile = $config['pid_file'];
Worker::$stdoutFile = $config['stdout_file'];
Worker::$logFile = $config['log_file'];
Worker::$eventLoopClass = $config['event_loop'] ?? '';
TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10 * 1024 * 1024;
if (property_exists(Worker::class, 'statusFile')) {
Worker::$statusFile = $config['status_file'] ?? '';
}
if (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
foreach ($property_map as $property) {
if (isset($config[$property])) {
$worker->$property = $config[$property];
}
}
$worker->onWorkerStart = function ($worker) {
require_once base_path() . '/support/bootstrap.php';
$app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());
Http::requestClass(config('app.request_class', config('server.request_class', Request::class)));
$worker->onMessage = [$app, 'onMessage'];
};
}
// Windows does not support custom processes.
if (\DIRECTORY_SEPARATOR === '/') {
foreach (config('process', []) as $process_name => $config) {
worker_start($process_name, $config);
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
foreach ($project['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$name.$process_name", $config);
}
}
}
}
Worker::runAll();
Support\App::run();
<?php
namespace support;
use Dotenv\Dotenv;
use Webman\Config;
use Webman\Util;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http;
use Workerman\Worker;
class App
{
/**
* @return void
*/
public static function run()
{
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (class_exists(Dotenv::class) && file_exists(base_path() . '/.env')) {
if (method_exists(Dotenv::class, 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
static::loadAllConfig(['route', 'container']);
$error_reporting = config('app.error_reporting');
if (isset($error_reporting)) {
error_reporting($error_reporting);
}
if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($timezone);
}
$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
if (!file_exists($runtime_logs_path) || !is_dir($runtime_logs_path)) {
if (!mkdir($runtime_logs_path, 0777, true)) {
throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
}
}
$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
if (!file_exists($runtime_views_path) || !is_dir($runtime_views_path)) {
if (!mkdir($runtime_views_path, 0777, true)) {
throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
}
}
Worker::$onMasterReload = function () {
if (function_exists('opcache_get_status')) {
if ($status = \opcache_get_status()) {
if (isset($status['scripts']) && $scripts = $status['scripts']) {
foreach (array_keys($scripts) as $file) {
\opcache_invalidate($file, true);
}
}
}
}
};
$config = config('server');
Worker::$pidFile = $config['pid_file'];
Worker::$stdoutFile = $config['stdout_file'];
Worker::$logFile = $config['log_file'];
Worker::$eventLoopClass = $config['event_loop'] ?? '';
TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10 * 1024 * 1024;
if (property_exists(Worker::class, 'statusFile')) {
Worker::$statusFile = $config['status_file'] ?? '';
}
if (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
foreach ($property_map as $property) {
if (isset($config[$property])) {
$worker->$property = $config[$property];
}
}
$worker->onWorkerStart = function ($worker) {
require_once \base_path() . '/support/bootstrap.php';
$app = new \Webman\App(config('app.request_class', Request::class), Log::channel('default'), app_path(), public_path());
$worker->onMessage = [$app, 'onMessage'];
[$app, 'onWorkerStart']($worker);
};
}
// Windows does not support custom processes.
if (\DIRECTORY_SEPARATOR === '/') {
foreach (config('process', []) as $process_name => $config) {
worker_start($process_name, $config);
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$name.$process_name", $config);
}
}
foreach ($projects['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$process_name", $config);
}
}
}
Worker::runAll();
}
/**
* @param array $excludes
* @return void
*/
public static function loadAllConfig(array $excludes = [])
{
Config::load(config_path(), $excludes);
$directory = base_path() . '/plugin';
foreach (Util::scanDir($directory, false) as $name) {
$dir = "$directory/$name/config";
if (\is_dir($dir)) {
Config::load($dir, $excludes, "plugin.$name");
}
}
}
}
......@@ -7,7 +7,7 @@ use Symfony\Component\Cache\Psr16Cache;
/**
* Class Cache
* @package support\bootstrap
* @package Support\Bootstrap
*
* Strings methods
* @method static mixed get($key, $default = null)
......
......@@ -15,39 +15,33 @@
namespace support;
use Psr\Container\ContainerInterface;
use Webman\Config;
/**
* Class Container
* @package support
* @package Support
* @method static mixed get($name)
* @method static mixed make($name, array $parameters)
* @method static bool has($name)
*/
class Container
{
/**
* @var ContainerInterface
*/
protected static $_instance = null;
/**
* @return ContainerInterface
*/
public static function instance()
public static function instance(string $plugin = '')
{
if (!static::$_instance) {
static::$_instance = include config_path() . '/container.php';
}
return static::$_instance;
return Config::get($plugin ? "plugin.$plugin.container" : 'container');
}
/**
* @param $name
* @param $arguments
* @param string $name
* @param array $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
public static function __callStatic(string $name, array $arguments)
{
return static::instance()->{$name}(... $arguments);
$plugin = \Webman\App::getPluginByClass($name);
return static::instance($plugin)->{$name}(... $arguments);
}
}
......@@ -18,7 +18,7 @@ use Illuminate\Database\Capsule\Manager;
/**
* Class Db
* @package support
* @package Support
* @method static array select(string $query, $bindings = [], $useReadPdo = true)
* @method static int insert(string $query, $bindings = [])
* @method static int update(string $query, $bindings = [])
......
......@@ -21,7 +21,7 @@ use Monolog\Logger;
/**
* Class Log
* @package support
* @package Support
*
* @method static void log($level, $message, array $context = [])
* @method static void debug($message, array $context = [])
......@@ -44,20 +44,21 @@ class Log
* @param string $name
* @return Logger
*/
public static function channel($name = 'default')
public static function channel(string $name = 'default')
{
if (!static::$_instance) {
$configs = config('log', []);
foreach ($configs as $channel => $config) {
if (!isset(static::$_instance[$name])) {
$config = \config('log', [])[$name];
$handlers = self::handlers($config);
$processors = self::processors($config);
static::$_instance[$channel] = new Logger($channel,$handlers,$processors);
}
static::$_instance[$name] = new Logger($name, $handlers, $processors);
}
return static::$_instance[$name];
}
/**
* @param array $config
* @return array
*/
protected static function handlers(array $config): array
{
$handlerConfigs = $config['handlers'] ?? [[]];
......@@ -74,7 +75,13 @@ class Log
return $handlers;
}
protected static function handler($class, $constructor, $formatterConfig): HandlerInterface
/**
* @param string $class
* @param array $constructor
* @param array $formatterConfig
* @return HandlerInterface
*/
protected static function handler(string $class, array $constructor, array $formatterConfig): HandlerInterface
{
/** @var HandlerInterface $handler */
$handler = new $class(... \array_values($constructor));
......@@ -92,29 +99,33 @@ class Log
return $handler;
}
/**
* @param array $config
* @return array
*/
protected static function processors(array $config): array
{
$result = [];
if (! isset($config['processors']) && isset($config['processor'])) {
if (!isset($config['processors']) && isset($config['processor'])) {
$config['processors'] = [$config['processor']];
}
foreach ($config['processors'] ?? [] as $value) {
if (is_array($value) && isset($value['class'])) {
if (\is_array($value) && isset($value['class'])) {
$value = new $value['class'](... \array_values($value['constructor'] ?? []));;
}
$result[] = $value;
}
return $result;
}
/**
* @param $name
* @param $arguments
* @param string $name
* @param array $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
public static function __callStatic(string $name, array $arguments)
{
return static::channel('default')->{$name}(... $arguments);
}
......
......@@ -16,6 +16,236 @@ namespace support;
use Illuminate\Database\Eloquent\Model as BaseModel;
/**
* @method static \Illuminate\Database\Eloquent\Model make($attributes = [])
* @method static \Illuminate\Database\Eloquent\Builder withGlobalScope($identifier, $scope)
* @method static \Illuminate\Database\Eloquent\Builder withoutGlobalScope($scope)
* @method static \Illuminate\Database\Eloquent\Builder withoutGlobalScopes($scopes = null)
* @method static array removedScopes()
* @method static \Illuminate\Database\Eloquent\Builder whereKey($id)
* @method static \Illuminate\Database\Eloquent\Builder whereKeyNot($id)
* @method static \Illuminate\Database\Eloquent\Builder where($column, $operator = null, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Eloquent\Model|null firstWhere($column, $operator = null, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Eloquent\Builder orWhere($column, $operator = null, $value = null)
* @method static \Illuminate\Database\Eloquent\Builder latest($column = null)
* @method static \Illuminate\Database\Eloquent\Builder oldest($column = null)
* @method static \Illuminate\Database\Eloquent\Collection hydrate($items)
* @method static \Illuminate\Database\Eloquent\Collection fromQuery($query, $bindings = [])
* @method static \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection[]|null find($id, $columns = [])
* @method static \Illuminate\Database\Eloquent\Collection findMany($ids, $columns = [])
* @method static \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection[] findOrFail($id, $columns = [])
* @method static \Illuminate\Database\Eloquent\Model findOrNew($id, $columns = [])
* @method static \Illuminate\Database\Eloquent\Model firstOrNew($attributes = [], $values = [])
* @method static \Illuminate\Database\Eloquent\Model firstOrCreate($attributes = [], $values = [])
* @method static \Illuminate\Database\Eloquent\Model updateOrCreate($attributes, $values = [])
* @method static \Illuminate\Database\Eloquent\Model firstOrFail($columns = [])
* @method static \Illuminate\Database\Eloquent\Model|mixed firstOr($columns = [], $callback = null)
* @method static \Illuminate\Database\Eloquent\Model sole($columns = [])
* @method static mixed value($column)
* @method static \Illuminate\Database\Eloquent\Collection[] get($columns = [])
* @method static \Illuminate\Database\Eloquent\Model[][] getModels($columns = [])
* @method static array eagerLoadRelations($models)
* @method static \Illuminate\Support\LazyCollection cursor()
* @method static \Illuminate\Support\Collection pluck($column, $key = null)
* @method static \Illuminate\Contracts\Pagination\LengthAwarePaginator paginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
* @method static \Illuminate\Contracts\Pagination\Paginator simplePaginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
* @method static \Illuminate\Contracts\Pagination\CursorPaginator cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null)
* @method static \Illuminate\Database\Eloquent\Model|$this create($attributes = [])
* @method static \Illuminate\Database\Eloquent\Model|$this forceCreate($attributes)
* @method static int upsert($values, $uniqueBy, $update = null)
* @method static void onDelete($callback)
* @method static static|mixed scopes($scopes)
* @method static static applyScopes()
* @method static \Illuminate\Database\Eloquent\Builder without($relations)
* @method static \Illuminate\Database\Eloquent\Builder withOnly($relations)
* @method static \Illuminate\Database\Eloquent\Model newModelInstance($attributes = [])
* @method static \Illuminate\Database\Eloquent\Builder withCasts($casts)
* @method static \Illuminate\Database\Query\Builder getQuery()
* @method static \Illuminate\Database\Eloquent\Builder setQuery($query)
* @method static \Illuminate\Database\Query\Builder toBase()
* @method static array getEagerLoads()
* @method static \Illuminate\Database\Eloquent\Builder setEagerLoads($eagerLoad)
* @method static \Illuminate\Database\Eloquent\Model getModel()
* @method static \Illuminate\Database\Eloquent\Builder setModel($model)
* @method static \Closure getMacro($name)
* @method static bool hasMacro($name)
* @method static \Closure getGlobalMacro($name)
* @method static bool hasGlobalMacro($name)
* @method static static clone()
* @method static \Illuminate\Database\Eloquent\Builder has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orHas($relation, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder doesntHave($relation, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orDoesntHave($relation)
* @method static \Illuminate\Database\Eloquent\Builder whereHas($relation, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder orWhereHas($relation, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder whereDoesntHave($relation, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orWhereDoesntHave($relation, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orHasMorph($relation, $types, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder doesntHaveMorph($relation, $types, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orDoesntHaveMorph($relation, $types)
* @method static \Illuminate\Database\Eloquent\Builder whereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder orWhereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder whereDoesntHaveMorph($relation, $types, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orWhereDoesntHaveMorph($relation, $types, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder withAggregate($relations, $column, $function = null)
* @method static \Illuminate\Database\Eloquent\Builder withCount($relations)
* @method static \Illuminate\Database\Eloquent\Builder withMax($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withMin($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withSum($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withAvg($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withExists($relation)
* @method static \Illuminate\Database\Eloquent\Builder mergeConstraintsFrom($from)
* @method static \Illuminate\Support\Collection explain()
* @method static bool chunk($count, $callback)
* @method static \Illuminate\Support\Collection chunkMap($callback, $count = 1000)
* @method static bool each($callback, $count = 1000)
* @method static bool chunkById($count, $callback, $column = null, $alias = null)
* @method static bool eachById($callback, $count = 1000, $column = null, $alias = null)
* @method static \Illuminate\Support\LazyCollection lazy($chunkSize = 1000)
* @method static \Illuminate\Support\LazyCollection lazyById($chunkSize = 1000, $column = null, $alias = null)
* @method static \Illuminate\Database\Eloquent\Model|object|null first($columns = [])
* @method static \Illuminate\Database\Eloquent\Model|object|null baseSole($columns = [])
* @method static \Illuminate\Database\Eloquent\Builder tap($callback)
* @method static mixed when($value, $callback, $default = null)
* @method static mixed unless($value, $callback, $default = null)
* @method static \Illuminate\Database\Query\Builder select($columns = [])
* @method static \Illuminate\Database\Query\Builder selectSub($query, $as)
* @method static \Illuminate\Database\Query\Builder selectRaw($expression, $bindings = [])
* @method static \Illuminate\Database\Query\Builder fromSub($query, $as)
* @method static \Illuminate\Database\Query\Builder fromRaw($expression, $bindings = [])
* @method static \Illuminate\Database\Query\Builder addSelect($column)
* @method static \Illuminate\Database\Query\Builder distinct()
* @method static \Illuminate\Database\Query\Builder from($table, $as = null)
* @method static \Illuminate\Database\Query\Builder join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
* @method static \Illuminate\Database\Query\Builder joinWhere($table, $first, $operator, $second, $type = 'inner')
* @method static \Illuminate\Database\Query\Builder joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)
* @method static \Illuminate\Database\Query\Builder leftJoin($table, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder leftJoinWhere($table, $first, $operator, $second)
* @method static \Illuminate\Database\Query\Builder leftJoinSub($query, $as, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder rightJoin($table, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder rightJoinWhere($table, $first, $operator, $second)
* @method static \Illuminate\Database\Query\Builder rightJoinSub($query, $as, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder crossJoin($table, $first = null, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder crossJoinSub($query, $as)
* @method static void mergeWheres($wheres, $bindings)
* @method static array prepareValueAndOperator($value, $operator, $useDefault = false)
* @method static \Illuminate\Database\Query\Builder whereColumn($first, $operator = null, $second = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereColumn($first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder whereRaw($sql, $bindings = [], $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder whereIn($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereIn($column, $values)
* @method static \Illuminate\Database\Query\Builder whereNotIn($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereNotIn($column, $values)
* @method static \Illuminate\Database\Query\Builder whereIntegerInRaw($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereIntegerInRaw($column, $values)
* @method static \Illuminate\Database\Query\Builder whereIntegerNotInRaw($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereIntegerNotInRaw($column, $values)
* @method static \Illuminate\Database\Query\Builder whereNull($columns, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereNull($column)
* @method static \Illuminate\Database\Query\Builder whereNotNull($columns, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder whereBetween($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder whereBetweenColumns($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereBetween($column, $values)
* @method static \Illuminate\Database\Query\Builder orWhereBetweenColumns($column, $values)
* @method static \Illuminate\Database\Query\Builder whereNotBetween($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder whereNotBetweenColumns($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereNotBetween($column, $values)
* @method static \Illuminate\Database\Query\Builder orWhereNotBetweenColumns($column, $values)
* @method static \Illuminate\Database\Query\Builder orWhereNotNull($column)
* @method static \Illuminate\Database\Query\Builder whereDate($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereDate($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereTime($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereTime($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereDay($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereDay($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereMonth($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereMonth($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereYear($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereYear($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereNested($callback, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder forNestedWhere()
* @method static \Illuminate\Database\Query\Builder addNestedWhereQuery($query, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder whereExists($callback, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereExists($callback, $not = false)
* @method static \Illuminate\Database\Query\Builder whereNotExists($callback, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereNotExists($callback)
* @method static \Illuminate\Database\Query\Builder addWhereExistsQuery($query, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder whereRowValues($columns, $operator, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereRowValues($columns, $operator, $values)
* @method static \Illuminate\Database\Query\Builder whereJsonContains($column, $value, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereJsonContains($column, $value)
* @method static \Illuminate\Database\Query\Builder whereJsonDoesntContain($column, $value, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereJsonDoesntContain($column, $value)
* @method static \Illuminate\Database\Query\Builder whereJsonLength($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereJsonLength($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder dynamicWhere($method, $parameters)
* @method static \Illuminate\Database\Query\Builder groupBy(...$groups)
* @method static \Illuminate\Database\Query\Builder groupByRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder having($column, $operator = null, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orHaving($column, $operator = null, $value = null)
* @method static \Illuminate\Database\Query\Builder havingBetween($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder havingRaw($sql, $bindings = [], $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orHavingRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder orderBy($column, $direction = 'asc')
* @method static \Illuminate\Database\Query\Builder orderByDesc($column)
* @method static \Illuminate\Database\Query\Builder inRandomOrder($seed = '')
* @method static \Illuminate\Database\Query\Builder orderByRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder skip($value)
* @method static \Illuminate\Database\Query\Builder offset($value)
* @method static \Illuminate\Database\Query\Builder take($value)
* @method static \Illuminate\Database\Query\Builder limit($value)
* @method static \Illuminate\Database\Query\Builder forPage($page, $perPage = 15)
* @method static \Illuminate\Database\Query\Builder forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id')
* @method static \Illuminate\Database\Query\Builder forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')
* @method static \Illuminate\Database\Query\Builder reorder($column = null, $direction = 'asc')
* @method static \Illuminate\Database\Query\Builder union($query, $all = false)
* @method static \Illuminate\Database\Query\Builder unionAll($query)
* @method static \Illuminate\Database\Query\Builder lock($value = true)
* @method static \Illuminate\Database\Query\Builder lockForUpdate()
* @method static \Illuminate\Database\Query\Builder sharedLock()
* @method static \Illuminate\Database\Query\Builder beforeQuery($callback)
* @method static void applyBeforeQueryCallbacks()
* @method static string toSql()
* @method static int getCountForPagination($columns = [])
* @method static string implode($column, $glue = '')
* @method static bool exists()
* @method static bool doesntExist()
* @method static mixed existsOr($callback)
* @method static mixed doesntExistOr($callback)
* @method static int count($columns = '*')
* @method static mixed min($column)
* @method static mixed max($column)
* @method static mixed sum($column)
* @method static mixed avg($column)
* @method static mixed average($column)
* @method static mixed aggregate($function, $columns = [])
* @method static float|int numericAggregate($function, $columns = [])
* @method static bool insert($values)
* @method static int insertOrIgnore($values)
* @method static int insertGetId($values, $sequence = null)
* @method static int insertUsing($columns, $query)
* @method static bool updateOrInsert($attributes, $values = [])
* @method static void truncate()
* @method static \Illuminate\Database\Query\Expression raw($value)
* @method static array getBindings()
* @method static array getRawBindings()
* @method static \Illuminate\Database\Query\Builder setBindings($bindings, $type = 'where')
* @method static \Illuminate\Database\Query\Builder addBinding($value, $type = 'where')
* @method static \Illuminate\Database\Query\Builder mergeBindings($query)
* @method static array cleanBindings($bindings)
* @method static \Illuminate\Database\Query\Processors\Processor getProcessor()
* @method static \Illuminate\Database\Query\Grammars\Grammar getGrammar()
* @method static \Illuminate\Database\Query\Builder useWritePdo()
* @method static static cloneWithout($properties)
* @method static static cloneWithoutBindings($except)
* @method static \Illuminate\Database\Query\Builder dump()
* @method static void dd()
* @method static void macro($name, $macro)
* @method static void mixin($mixin, $replace = true)
* @method static mixed macroCall($method, $parameters)
*/
class Model extends BaseModel
{
......
......@@ -4,27 +4,40 @@ namespace support;
class Plugin
{
/**
* @param $event
* @return void
*/
public static function install($event)
{
static::findHepler();
$operation = $event->getOperation();
$autoload = method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload();
$autoload = \method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload();
if (!isset($autoload['psr-4'])) {
return;
}
$namespace = key($autoload['psr-4']);
foreach ($autoload['psr-4'] as $namespace => $path) {
$install_function = "\\{$namespace}Install::install";
$plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($install_function)) {
if (\defined($plugin_const) && \is_callable($install_function)) {
$install_function();
}
}
}
/**
* @param $event
* @return void
*/
public static function update($event)
{
static::install($event);
}
/**
* @param $event
* @return void
*/
public static function uninstall($event)
{
static::findHepler();
......@@ -32,19 +45,23 @@ class Plugin
if (!isset($autoload['psr-4'])) {
return;
}
$namespace = key($autoload['psr-4']);
foreach ($autoload['psr-4'] as $namespace => $path) {
$uninstall_function = "\\{$namespace}Install::uninstall";
$plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($uninstall_function)) {
$uninstall_function();
}
}
}
/**
* @return void
*/
protected static function findHepler()
{
// Plugin.php in vendor
$file = __DIR__ . '/../../../../../support/helpers.php';
if (is_file($file)) {
if (\is_file($file)) {
require_once $file;
return;
}
......
......@@ -14,13 +14,16 @@
namespace support;
use Workerman\Timer;
use Illuminate\Events\Dispatcher;
use Illuminate\Redis\Events\CommandExecuted;
use Illuminate\Redis\RedisManager;
use Workerman\Timer;
use Workerman\Worker;
/**
* Class Redis
* @package support
* @package Support
*
* Strings methods
* @method static int append($key, $value)
......@@ -208,14 +211,39 @@ class Redis
*/
protected static $_instance = null;
/**
* need to install phpredis extension
*/
const PHPREDIS_CLIENT = 'phpredis';
/**
* need to install the 'predis/predis' packgage.
* cmd: composer install predis/predis
*/
const PREDIS_CLIENT = 'predis';
/**
* Support client collection
*/
static $_allowClient = [
self::PHPREDIS_CLIENT,
self::PREDIS_CLIENT
];
/**
* @return RedisManager
*/
public static function instance()
{
if (!static::$_instance) {
$config = config('redis');
static::$_instance = new RedisManager('', 'phpredis', $config);
$config = \config('redis');
$client = $config['client'] ?? self::PHPREDIS_CLIENT;
if (!\in_array($client, static::$_allowClient)) {
$client = self::PHPREDIS_CLIENT;
}
static::$_instance = new RedisManager('', $client, $config);
}
return static::$_instance;
}
......@@ -224,26 +252,27 @@ class Redis
* @param string $name
* @return \Illuminate\Redis\Connections\Connection
*/
public static function connection($name = 'default')
public static function connection(string $name = 'default')
{
static $timers = [];
$connection = static::instance()->connection($name);
if (!isset($timers[$name])) {
if (Worker::getAllWorkers()) {
$timers[$name] = Timer::add(55, function () use ($connection) {
$timers[$name] = Worker::getAllWorkers() ? Timer::add(55, function () use ($connection) {
$connection->get('ping');
});
}) : 1;
if (\class_exists(Dispatcher::class)) {
$connection->setEventDispatcher(new Dispatcher());
}
}
return $connection;
}
/**
* @param $name
* @param $arguments
* @param string $name
* @param array $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
public static function __callStatic(string $name, array $arguments)
{
return static::connection('default')->{$name}(... $arguments);
}
......
......@@ -16,7 +16,7 @@ namespace support;
/**
* Class Request
* @package support
* @package Support
*/
class Request extends \Webman\Http\Request
{
......
......@@ -16,7 +16,7 @@ namespace support;
/**
* Class Response
* @package support
* @package Support
*/
class Response extends \Webman\Http\Response
{
......
......@@ -19,7 +19,7 @@ use Webman\Exception\NotFoundException;
/**
* Class Translation
* @package support
* @package Support
* @method static string trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
* @method static void setLocale(string $locale)
* @method static string getLocale()
......@@ -28,24 +28,24 @@ class Translation
{
/**
* @var Translator
* @var Translator[]
*/
protected static $_instance;
protected static $_instance = [];
/**
* @return Translator
* @throws NotFoundException
*/
public static function instance()
public static function instance(string $plugin = '')
{
if (!static::$_instance) {
$config = config('translation', []);
if (!isset(static::$_instance[$plugin])) {
$config = \config($plugin ? "plugin.$plugin.translation" : 'translation', []);
// Phar support. Compatible with the 'realpath' function in the phar file.
if (!$translations_path = \get_realpath($config['path'])) {
throw new NotFoundException("File {$config['path']} not found");
}
static::$_instance = $translator = new Translator($config['locale']);
static::$_instance[$plugin] = $translator = new Translator($config['locale']);
$translator->setFallbackLocales($config['fallback_locale']);
$classes = [
......@@ -61,26 +61,29 @@ class Translation
foreach ($classes as $class => $opts) {
$translator->addLoader($opts['format'], new $class);
foreach (glob($translations_path . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . '*' . $opts['extension']) as $file) {
$domain = basename($file, $opts['extension']);
$dir_name = pathinfo($file, PATHINFO_DIRNAME);
$locale = substr(strrchr($dir_name, DIRECTORY_SEPARATOR), 1);
foreach (\glob($translations_path . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . '*' . $opts['extension']) as $file) {
$domain = \basename($file, $opts['extension']);
$dir_name = \pathinfo($file, PATHINFO_DIRNAME);
$locale = \substr(strrchr($dir_name, DIRECTORY_SEPARATOR), 1);
if ($domain && $locale) {
$translator->addResource($opts['format'], $file, $locale, $domain);
}
}
}
}
return static::$_instance;
return static::$_instance[$plugin];
}
/**
* @param $name
* @param $arguments
* @param string $name
* @param array $arguments
* @return mixed
* @throws NotFoundException
*/
public static function __callStatic($name, $arguments)
public static function __callStatic(string $name, array $arguments)
{
return static::instance()->{$name}(... $arguments);
$request = \request();
$plugin = $request->plugin ?? '';
return static::instance($plugin)->{$name}(... $arguments);
}
}
......@@ -16,10 +16,16 @@ namespace support;
class View
{
/**
* @param mixed $name
* @param mixed $value
* @return void
*/
public static function assign($name, $value = null)
{
static $handler;
$handler = $handler ?: config('view.handler');
$request = \request();
$plugin = $request->plugin ?? '';
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
$handler::assign($name, $value);
}
}
\ No newline at end of file
......@@ -13,10 +13,12 @@
*/
use Dotenv\Dotenv;
use support\Container;
use support\Log;
use Webman\Bootstrap;
use Webman\Config;
use Webman\Route;
use Webman\Middleware;
use Webman\Util;
$worker = $worker ?? null;
......@@ -24,7 +26,7 @@ if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($timezone);
}
set_error_handler(function ($level, $message, $file = '', $line = 0, $context = []) {
set_error_handler(function ($level, $message, $file = '', $line = 0) {
if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line);
}
......@@ -46,45 +48,85 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
}
}
Config::reload(config_path(), ['route', 'container']);
Support\App::loadAllConfig(['route']);
foreach (config('autoload.files', []) as $file) {
include_once $file;
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['autoload']['files'] ?? [] as $file) {
include_once $file;
}
}
}
foreach (config('autoload.files', []) as $file) {
foreach ($projects['autoload']['files'] ?? [] as $file) {
include_once $file;
}
}
$container = Container::instance();
Route::container($container);
Middleware::container($container);
Middleware::load(config('middleware', []));
Middleware::load(config('middleware', []), '');
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
Middleware::load($project['middleware'] ?? []);
if (!is_array($project) || $name === 'static') {
continue;
}
Middleware::load($project['middleware'] ?? [], '');
}
Middleware::load($projects['middleware'] ?? [], $firm);
if ($static_middlewares = config("plugin.$firm.static.middleware")) {
Middleware::load(['__static__' => $static_middlewares], $firm);
}
}
Middleware::load(['__static__' => config('static.middleware', [])]);
Middleware::load(['__static__' => config('static.middleware', [])], '');
foreach (config('bootstrap', []) as $class_name) {
/** @var \Webman\Bootstrap $class_name */
if (!class_exists($class_name)) {
$log = "Warning: Class $class_name setting in config/bootstrap.php not found\r\n";
echo $log;
Log::error($log);
continue;
}
/** @var Bootstrap $class_name */
$class_name::start($worker);
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['bootstrap'] ?? [] as $class_name) {
/** @var \Webman\Bootstrap $class_name */
if (!class_exists($class_name)) {
$log = "Warning: Class $class_name setting in config/plugin/$firm/$name/bootstrap.php not found\r\n";
echo $log;
Log::error($log);
continue;
}
/** @var Bootstrap $class_name */
$class_name::start($worker);
}
}
foreach ($projects['bootstrap'] ?? [] as $class_name) {
if (!class_exists($class_name)) {
$log = "Warning: Class $class_name setting in plugin/$firm/config/bootstrap.php not found\r\n";
echo $log;
Log::error($log);
continue;
}
/** @var Bootstrap $class_name */
$class_name::start($worker);
}
}
Route::load(config_path());
$directory = base_path() . '/plugin';
$paths = [config_path()];
foreach (Util::scanDir($directory) as $path) {
if (is_dir($path = "$path/config")) {
$paths[] = $path;
}
}
Route::load($paths);
......@@ -14,18 +14,21 @@
namespace support\bootstrap;
use Webman\Bootstrap;
use Illuminate\Container\Container;
use Illuminate\Database\Capsule\Manager as Capsule;
use Illuminate\Database\Connection;
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
use Jenssegers\Mongodb\Connection;
use Workerman\Worker;
use Workerman\Timer;
use Illuminate\Pagination\Paginator;
use Jenssegers\Mongodb\Connection as MongodbConnection;
use support\Db;
use Throwable;
use Webman\Bootstrap;
use Workerman\Timer;
use Workerman\Worker;
/**
* Class Laravel
* @package support\bootstrap
* @package support\Bootstrap
*/
class LaravelDb implements Bootstrap
{
......@@ -36,26 +39,26 @@ class LaravelDb implements Bootstrap
*/
public static function start($worker)
{
if (!class_exists('\Illuminate\Database\Capsule\Manager')) {
if (!class_exists(Capsule::class)) {
return;
}
$connections = config('database.connections');
$config = \config('database', []);
$connections = $config['connections'] ?? [];
if (!$connections) {
return;
}
$capsule = new Capsule;
$configs = config('database');
$capsule->getDatabaseManager()->extend('mongodb', function ($config, $name) {
$config['name'] = $name;
return new Connection($config);
return new MongodbConnection($config);
});
if (isset($configs['default'])) {
$default_config = $connections[$configs['default']];
$default = $config['default'] ?? false;
if ($default) {
$default_config = $connections[$config['default']];
$capsule->addConnection($default_config);
}
......@@ -63,7 +66,7 @@ class LaravelDb implements Bootstrap
$capsule->addConnection($config, $name);
}
if (class_exists('\Illuminate\Events\Dispatcher')) {
if (\class_exists(Dispatcher::class)) {
$capsule->setEventDispatcher(new Dispatcher(new Container));
}
......@@ -73,12 +76,36 @@ class LaravelDb implements Bootstrap
// Heartbeat
if ($worker) {
Timer::add(55, function () use ($connections) {
Timer::add(55, function () use ($default, $connections) {
if (!class_exists(Connection::class, false)) {
return;
}
foreach ($connections as $key => $item) {
if ($item['driver'] == 'mysql') {
try {
if ($key == $default) {
Db::select('select 1');
} else {
Db::connection($key)->select('select 1');
}
} catch (Throwable $e) {
}
}
}
});
}
// Paginator
if (class_exists(Paginator::class)) {
Paginator::queryStringResolver(function () {
return request()->queryString();
});
Paginator::currentPathResolver(function () {
return request()->path();
});
Paginator::currentPageResolver(function ($page_name = 'page') {
$page = (int)request()->input($page_name, 1);
return $page > 0 ? $page : 1;
});
}
}
......
......@@ -21,7 +21,7 @@ use Workerman\Worker;
/**
* Class Session
* @package support
* @package Support
*/
class Session implements Bootstrap
{
......@@ -32,25 +32,28 @@ class Session implements Bootstrap
*/
public static function start($worker)
{
$config = config('session');
$config = \config('session');
if (\property_exists(SessionBase::class, 'name')) {
SessionBase::$name = $config['session_name'];
} else {
Http::sessionName($config['session_name']);
}
SessionBase::handlerClass($config['handler'], $config['config'][$config['type']]);
if (property_exists(SessionBase::class, 'lifetime')) {
$map = [
'auto_update_timestamp' => 'autoUpdateTimestamp',
'cookie_lifetime' => 'cookieLifetime',
'gc_probability' => 'gcProbability',
'cookie_path' => 'cookiePath',
'lifetime' => 'lifetime',
'http_only' => 'httpOnly',
'same_site' => 'sameSite',
'lifetime' => 'lifetime',
'domain' => 'domain',
'secure' => 'secure',
'same_site' => 'sameSite',
];
foreach ($map as $key => $name) {
if (isset($config[$key])) {
if (isset($config[$key]) && \property_exists(SessionBase::class, $name)) {
SessionBase::${$name} = $config[$key];
}
}
}
}
}
......@@ -18,7 +18,7 @@ use Exception;
/**
* Class BusinessException
* @package support\exception
* @package Support\Exception
*/
class BusinessException extends Exception
{
......
......@@ -14,14 +14,14 @@
namespace support\exception;
use Webman\Http\Request;
use Webman\Http\Response;
use Throwable;
use Webman\Exception\ExceptionHandler;
use Webman\Http\Request;
use Webman\Http\Response;
/**
* Class Handler
* @package support\exception
* @package Support\Exception
*/
class Handler extends ExceptionHandler
{
......
......@@ -26,22 +26,22 @@ use Webman\Config;
use Webman\Route;
// Phar support.
if (is_phar()) {
define('BASE_PATH', dirname(__DIR__));
if (\is_phar()) {
\define('BASE_PATH', dirname(__DIR__));
} else {
define('BASE_PATH', realpath(__DIR__ . '/../'));
\define('BASE_PATH', realpath(__DIR__ . '/../'));
}
define('WEBMAN_VERSION', '1.3.0');
\define('WEBMAN_VERSION', '1.4');
/**
* @param $return_phar
* @return false|string
*/
function base_path($return_phar = true)
function base_path(bool $return_phar = true)
{
static $real_path = '';
if (!$real_path) {
$real_path = is_phar() ? dirname(Phar::running(false)) : BASE_PATH;
$real_path = \is_phar() ? \dirname(Phar::running(false)) : BASE_PATH;
}
return $return_phar ? BASE_PATH : $real_path;
}
......@@ -61,7 +61,7 @@ function public_path()
{
static $path = '';
if (!$path) {
$path = get_realpath(config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public'));
$path = \config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public');
}
return $path;
}
......@@ -84,7 +84,7 @@ function runtime_path()
{
static $path = '';
if (!$path) {
$path = get_realpath(config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime'));
$path = \config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime');
}
return $path;
}
......@@ -95,7 +95,7 @@ function runtime_path()
* @param string $body
* @return Response
*/
function response($body = '', $status = 200, $headers = array())
function response($body = '', $status = 200, $headers = [])
{
return new Response($status, $headers, $body);
}
......@@ -107,7 +107,7 @@ function response($body = '', $status = 200, $headers = array())
*/
function json($data, $options = JSON_UNESCAPED_UNICODE)
{
return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options));
return new Response(200, ['Content-Type' => 'application/json'], \json_encode($data, $options));
}
/**
......@@ -129,19 +129,19 @@ function xml($xml)
*/
function jsonp($data, $callback_name = 'callback')
{
if (!is_scalar($data) && null !== $data) {
$data = json_encode($data);
if (!\is_scalar($data) && null !== $data) {
$data = \json_encode($data);
}
return new Response(200, [], "$callback_name($data)");
}
/**
* @param $location
* @param string $location
* @param int $status
* @param array $headers
* @return Response
*/
function redirect($location, $status = 302, $headers = [])
function redirect(string $location, int $status = 302, array $headers = [])
{
$response = new Response($status, ['Location' => $location]);
if (!empty($headers)) {
......@@ -156,55 +156,55 @@ function redirect($location, $status = 302, $headers = [])
* @param null $app
* @return Response
*/
function view($template, $vars = [], $app = null)
function view(string $template, array $vars = [], string $app = null)
{
static $handler;
if (null === $handler) {
$handler = config('view.handler');
}
$request = \request();
$plugin = $request->plugin ?? '';
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
return new Response(200, [], $handler::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
* @throws Throwable
*/
function raw_view($template, $vars = [], $app = null)
function raw_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], Raw::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
*/
function blade_view($template, $vars = [], $app = null)
function blade_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], Blade::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
*/
function think_view($template, $vars = [], $app = null)
function think_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], ThinkPHP::render($template, $vars, $app));
}
/**
* @param $template
* @param string $template
* @param array $vars
* @param null $app
* @param string|null $app
* @return Response
*/
function twig_view($template, $vars = [], $app = null)
function twig_view(string $template, array $vars = [], string $app = null)
{
return new Response(200, [], Twig::render($template, $vars, $app));
}
......@@ -218,21 +218,21 @@ function request()
}
/**
* @param $key
* @param null $default
* @return mixed
* @param string|null $key
* @param $default
* @return array|mixed|null
*/
function config($key = null, $default = null)
function config(string $key = null, $default = null)
{
return Config::get($key, $default);
}
/**
* @param $name
* @param string $name
* @param ...$parameters
* @return string
*/
function route($name, ...$parameters)
function route(string $name, ...$parameters)
{
$route = Route::getByName($name);
if (!$route) {
......@@ -243,8 +243,8 @@ function route($name, ...$parameters)
return $route->url();
}
if (is_array(current($parameters))) {
$parameters = current($parameters);
if (\is_array(\current($parameters))) {
$parameters = \current($parameters);
}
return $route->url($parameters);
......@@ -257,7 +257,7 @@ function route($name, ...$parameters)
*/
function session($key = null, $default = null)
{
$session = request()->session();
$session = \request()->session();
if (null === $key) {
return $session;
}
......@@ -280,7 +280,7 @@ function session($key = null, $default = null)
}
/**
* @param null|string $id
* @param string $id
* @param array $parameters
* @param string|null $domain
* @param string|null $locale
......@@ -311,48 +311,50 @@ function locale(string $locale = null)
*/
function not_found()
{
return new Response(404, [], file_get_contents(public_path() . '/404.html'));
return new Response(404, [], \file_get_contents(public_path() . '/404.html'));
}
/**
* Copy dir.
* @param $source
* @param $dest
*
* @param string $source
* @param string $dest
* @param bool $overwrite
* @return void
*/
function copy_dir($source, $dest, $overwrite = false)
function copy_dir(string $source, string $dest, bool $overwrite = false)
{
if (is_dir($source)) {
if (\is_dir($source)) {
if (!is_dir($dest)) {
mkdir($dest);
\mkdir($dest);
}
$files = scandir($source);
$files = \scandir($source);
foreach ($files as $file) {
if ($file !== "." && $file !== "..") {
copy_dir("$source/$file", "$dest/$file");
\copy_dir("$source/$file", "$dest/$file");
}
}
} else if (file_exists($source) && ($overwrite || !file_exists($dest))) {
copy($source, $dest);
} else if (\file_exists($source) && ($overwrite || !\file_exists($dest))) {
\copy($source, $dest);
}
}
/**
* Remove dir.
* @param $dir
*
* @param string $dir
* @return bool
*/
function remove_dir($dir)
function remove_dir(string $dir)
{
if (is_link($dir) || is_file($dir)) {
return unlink($dir);
if (\is_link($dir) || \is_file($dir)) {
return \unlink($dir);
}
$files = array_diff(scandir($dir), array('.', '..'));
$files = \array_diff(\scandir($dir), array('.', '..'));
foreach ($files as $file) {
(is_dir("$dir/$file") && !is_link($dir)) ? remove_dir("$dir/$file") : unlink("$dir/$file");
(\is_dir("$dir/$file") && !\is_link($dir)) ? \remove_dir("$dir/$file") : \unlink("$dir/$file");
}
return rmdir($dir);
return \rmdir($dir);
}
/**
......@@ -372,12 +374,12 @@ function worker_bind($worker, $class)
'onWebSocketConnect'
];
foreach ($callback_map as $name) {
if (method_exists($class, $name)) {
if (\method_exists($class, $name)) {
$worker->$name = [$class, $name];
}
}
if (method_exists($class, 'onWorkerStart')) {
call_user_func([$class, 'onWorkerStart'], $worker);
if (\method_exists($class, 'onWorkerStart')) {
[$class, 'onWorkerStart']($worker);
}
}
......@@ -406,10 +408,10 @@ function worker_start($process_name, $config)
}
$worker->onWorkerStart = function ($worker) use ($config) {
require_once base_path() . '/support/bootstrap.php';
require_once \base_path() . '/support/bootstrap.php';
foreach ($config['services'] ?? [] as $server) {
if (!class_exists($server['handler'])) {
if (!\class_exists($server['handler'])) {
echo "process error: class {$server['handler']} not exists\r\n";
continue;
}
......@@ -418,18 +420,18 @@ function worker_start($process_name, $config)
echo "listen: {$server['listen']}\n";
}
$instance = Container::make($server['handler'], $server['constructor'] ?? []);
worker_bind($listen, $instance);
\worker_bind($listen, $instance);
$listen->listen();
}
if (isset($config['handler'])) {
if (!class_exists($config['handler'])) {
if (!\class_exists($config['handler'])) {
echo "process error: class {$config['handler']} not exists\r\n";
return;
}
$instance = Container::make($config['handler'], $config['constructor'] ?? []);
worker_bind($worker, $instance);
\worker_bind($worker, $instance);
}
};
......@@ -444,10 +446,10 @@ function worker_start($process_name, $config)
*/
function get_realpath(string $file_path): string
{
if (strpos($file_path, 'phar://') === 0) {
if (\strpos($file_path, 'phar://') === 0) {
return $file_path;
} else {
return realpath($file_path);
return \realpath($file_path);
}
}
......@@ -456,7 +458,7 @@ function get_realpath(string $file_path): string
*/
function is_phar()
{
return class_exists(\Phar::class, false) && Phar::running();
return \class_exists(\Phar::class, false) && Phar::running();
}
/**
......@@ -469,11 +471,11 @@ function cpu_count()
return 1;
}
$count = 4;
if (is_callable('shell_exec')) {
if (strtolower(PHP_OS) === 'darwin') {
$count = (int)shell_exec('sysctl -n machdep.cpu.core_count');
if (\is_callable('shell_exec')) {
if (\strtolower(PHP_OS) === 'darwin') {
$count = (int)\shell_exec('sysctl -n machdep.cpu.core_count');
} else {
$count = (int)shell_exec('nproc');
$count = (int)\shell_exec('nproc');
}
}
return $count > 0 ? $count : 4;
......
......@@ -12,7 +12,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support\view;
namespace support\View;
use Jenssegers\Blade\Blade as BladeView;
use Webman\View;
......@@ -20,7 +20,7 @@ use Webman\View;
/**
* Class Blade
* composer require jenssegers/blade
* @package support\view
* @package Support\View
*/
class Blade implements View
{
......@@ -30,8 +30,8 @@ class Blade implements View
protected static $_vars = [];
/**
* @param $name
* @param null $value
* @param string|array $name
* @param mixed $value
*/
public static function assign($name, $value = null)
{
......@@ -39,17 +39,20 @@ class Blade implements View
}
/**
* @param $template
* @param $vars
* @param string $app
* @return mixed
* @param string $template
* @param array $vars
* @param string|null $app
* @return string
*/
public static function render($template, $vars, $app = null)
public static function render(string $template, array $vars, string $app = null)
{
static $views = [];
$app = $app === null ? \request()->app : $app;
$request = \request();
$plugin = $request->plugin ?? '';
$app = $app === null ? $request->app : $app;
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
if (!isset($views[$app])) {
$view_path = $app === '' ? \app_path() . '/view' : \app_path() . "/$app/view";
$view_path = $app === '' ? "$base_view_path/view" : "$base_view_path/$app/view";
$views[$app] = new BladeView($view_path, \runtime_path() . '/views');
}
$vars = \array_merge(static::$_vars, $vars);
......
......@@ -12,13 +12,14 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support\view;
namespace support\View;
use Webman\View;
use Throwable;
/**
* Class Raw
* @package support\view
* @package Support\View
*/
class Raw implements View
{
......@@ -28,8 +29,8 @@ class Raw implements View
protected static $_vars = [];
/**
* @param $name
* @param null $value
* @param string|array $name
* @param mixed $value
*/
public static function assign($name, $value = null)
{
......@@ -37,29 +38,31 @@ class Raw implements View
}
/**
* @param $template
* @param $vars
* @param null $app
* @return string
* @param string $template
* @param array $vars
* @param string|null $app
* @return false|string
*/
public static function render($template, $vars, $app = null)
public static function render(string $template, array $vars, string $app = null)
{
static $view_suffix;
$view_suffix = $view_suffix ?: \config('view.view_suffix', 'html');
$app = $app === null ? \request()->app : $app;
if ($app === '') {
$view_path = \app_path() . "/view/$template.$view_suffix";
} else {
$view_path = \app_path() . "/$app/view/$template.$view_suffix";
}
\extract(static::$_vars);
\extract($vars);
$request = \request();
$plugin = $request->plugin ?? '';
$config_prefix = $plugin ? "plugin.$plugin." : '';
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
$app = $app === null ? $request->app : $app;
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
$view_path = $app === '' ? "$base_view_path/view/$template.$view_suffix" : "$base_view_path/$app/view/$template.$view_suffix";
\extract(static::$_vars, \EXTR_SKIP);
\extract($vars, \EXTR_SKIP);
\ob_start();
// Try to include php file.
try {
include $view_path;
} catch (\Throwable $e) {
echo $e;
} catch (Throwable $e) {
static::$_vars = [];
\ob_end_clean();
throw $e;
}
static::$_vars = [];
return \ob_get_clean();
......
......@@ -12,14 +12,14 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support\view;
namespace support\View;
use think\Template;
use Webman\View;
/**
* Class Blade
* @package support\view
* @package Support\View
*/
class ThinkPHP implements View
{
......@@ -29,8 +29,8 @@ class ThinkPHP implements View
protected static $_vars = [];
/**
* @param $name
* @param null $value
* @param string|array $name
* @param mixed $value
*/
public static function assign($name, $value = null)
{
......@@ -38,21 +38,26 @@ class ThinkPHP implements View
}
/**
* @param $template
* @param $vars
* @param string $app
* @return mixed
* @param string $template
* @param array $vars
* @param string|null $app
* @return false|string
*/
public static function render($template, $vars, $app = null)
public static function render(string $template, array $vars, string $app = null)
{
$app = $app === null ? \request()->app : $app;
$view_path = $app === '' ? \app_path() . '/view/' : \app_path() . "/$app/view/";
$request = \request();
$plugin = $request->plugin ?? '';
$app = $app === null ? $request->app : $app;
$config_prefix = $plugin ? "plugin.$plugin." : '';
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
$view_path = $app === '' ? "$base_view_path/view/" : "$base_view_path/$app/view/";
$default_options = [
'view_path' => $view_path,
'cache_path' => \runtime_path() . '/views/',
'view_suffix' => config('view.view_suffix', 'html')
'view_suffix' => $view_suffix
];
$options = $default_options + \config('view.options', []);
$options = $default_options + \config("{$config_prefix}view.options", []);
$views = new Template($options);
\ob_start();
$vars = \array_merge(static::$_vars, $vars);
......
......@@ -12,15 +12,15 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support\view;
namespace support\View;
use Twig\Loader\FilesystemLoader;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Webman\View;
/**
* Class Blade
* @package support\view
* @package Support\View
*/
class Twig implements View
{
......@@ -30,8 +30,8 @@ class Twig implements View
protected static $_vars = [];
/**
* @param $name
* @param null $value
* @param string|array $name
* @param mixed $value
*/
public static function assign($name, $value = null)
{
......@@ -39,22 +39,27 @@ class Twig implements View
}
/**
* @param $template
* @param $vars
* @param string $app
* @return mixed
* @param string $template
* @param array $vars
* @param string|null $app
* @return string
*/
public static function render($template, $vars, $app = null)
public static function render(string $template, array $vars, string $app = null)
{
static $views = [], $view_suffix;
$view_suffix = $view_suffix ?: \config('view.view_suffix', 'html');
$app = $app === null ? \request()->app : $app;
if (!isset($views[$app])) {
$view_path = $app === '' ? \app_path() . '/view/' : \app_path() . "/$app/view/";
$views[$app] = new Environment(new FilesystemLoader($view_path), \config('view.options', []));
static $views = [];
$request = \request();
$plugin = $request->plugin ?? '';
$app = $app === null ? $request->app : $app;
$config_prefix = $plugin ? "plugin.$plugin." : '';
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
$key = "{$plugin}-{$request->app}";
if (!isset($views[$key])) {
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
$view_path = $app === '' ? "$base_view_path/view/" : "$base_view_path/$app/view/";
$views[$key] = new Environment(new FilesystemLoader($view_path), \config("{$config_prefix}view.options", []));
}
$vars = \array_merge(static::$_vars, $vars);
$content = $views[$app]->render("$template.$view_suffix", $vars);
$content = $views[$key]->render("$template.$view_suffix", $vars);
static::$_vars = [];
return $content;
}
......
<?php
/**
* Start file for windows
*/
require_once __DIR__ . '/vendor/autoload.php';
use process\Monitor;
use support\App;
use Dotenv\Dotenv;
use Workerman\Worker;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
App::loadAllConfig(['route']);
$error_reporting = config('app.error_reporting');
if (isset($error_reporting)) {
error_reporting($error_reporting);
}
$runtime_process_path = runtime_path() . DIRECTORY_SEPARATOR . '/windows';
if (!is_dir($runtime_process_path)) {
mkdir($runtime_process_path);
}
$process_files = [
__DIR__ . DIRECTORY_SEPARATOR . 'start.php'
];
foreach (config('process', []) as $process_name => $config) {
$process_files[] = write_process_file($runtime_process_path, $process_name, '');
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['process'] ?? [] as $process_name => $config) {
$process_files[] = write_process_file($runtime_process_path, $process_name, "$firm.$name");
}
}
foreach ($projects['process'] ?? [] as $process_name => $config) {
$process_files[] = write_process_file($runtime_process_path, $process_name, $firm);
}
}
function write_process_file($runtime_process_path, $process_name, $firm)
{
$process_param = $firm ? "plugin.$firm.$process_name" : $process_name;
$config_param = $firm ? "config('plugin.$firm.process')['$process_name']" : "config('process')['$process_name']";
$file_content = <<<EOF
<?php
require_once __DIR__ . '/../../vendor/autoload.php';
use Workerman\Worker;
use Webman\Config;
use support\App;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (is_callable('opcache_reset')) {
opcache_reset();
}
App::loadAllConfig(['route']);
worker_start('$process_param', $config_param);
if (DIRECTORY_SEPARATOR != "/") {
Worker::\$logFile = config('server')['log_file'] ?? Worker::\$logFile;
}
Worker::runAll();
EOF;
$process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_param.php";
file_put_contents($process_file, $file_content);
return $process_file;
}
if ($monitor_config = config('process.monitor.constructor')) {
$monitor = new Monitor(...array_values($monitor_config));
}
function popen_processes($process_files)
{
$cmd = "php " . implode(' ', $process_files);
$descriptorspec = [STDIN, STDOUT, STDOUT];
$resource = proc_open($cmd, $descriptorspec, $pipes);
if (!$resource) {
exit("Can not execute $cmd\r\n");
}
return $resource;
}
$resource = popen_processes($process_files);
echo "\r\n";
while (1) {
sleep(1);
if (!empty($monitor) && $monitor->checkAllFilesChange()) {
$status = proc_get_status($resource);
$pid = $status['pid'];
shell_exec("taskkill /F /T /PID $pid");
proc_close($resource);
$resource = popen_processes($process_files);
}
}
#!/usr/bin/env php
<?php
use Webman\Config;
use Webman\Console\Command;
use Webman\Console\Util;
require_once __DIR__ . '/vendor/autoload.php';
if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) {
require_once __DIR__ . '/support/bootstrap.php';
} else {
if (class_exists('Support\App')) {
Support\App::loadAllConfig(['route']);
} else {
Config::reload(config_path(), ['route', 'container']);
}
}
$cli = new Command();
$cli->setName('webman cli');
$cli->installInternalCommands();
if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
$cli->installCommands($command_path);
}
foreach (config('plugin', []) as $firm => $projects) {
if (isset($projects['app'])) {
if ($command_str = Util::guessPath(base_path() . "/plugin/$firm", 'command')) {
$command_path = base_path() . "/plugin/$firm/$command_str";
$cli->installCommands($command_path, "plugin\\$firm\\$command_str");
}
}
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['command'] ?? [] as $command) {
$cli->add(new $command);
}
}
}
$cli->run();
......@@ -5,13 +5,27 @@
require_once __DIR__ . '/vendor/autoload.php';
use process\Monitor;
use support\App;
use Dotenv\Dotenv;
use Workerman\Worker;
use Webman\Config;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
Config::load(config_path(), ['route', 'container']);
if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
App::loadAllConfig(['route']);
$error_reporting = config('app.error_reporting');
if (isset($error_reporting)) {
error_reporting($error_reporting);
}
$runtime_process_path = runtime_path() . DIRECTORY_SEPARATOR . '/windows';
if (!is_dir($runtime_process_path)) {
......@@ -21,41 +35,34 @@ $process_files = [
__DIR__ . DIRECTORY_SEPARATOR . 'start.php'
];
foreach (config('process', []) as $process_name => $config) {
$file_content = <<<EOF
<?php
require_once __DIR__ . '/../../vendor/autoload.php';
use Workerman\Worker;
use Webman\Config;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (is_callable('opcache_reset')) {
opcache_reset();
}
Config::load(config_path(), ['route', 'container']);
worker_start('$process_name', config('process')['$process_name']);
Worker::runAll();
EOF;
$process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_name.php";
$process_files[] = $process_file;
file_put_contents($process_file, $file_content);
$process_files[] = write_process_file($runtime_process_path, $process_name, '');
}
foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['process'] ?? [] as $process_name => $config) {
$process_files[] = write_process_file($runtime_process_path, $process_name, "$firm.$name");
}
}
foreach ($projects['process'] ?? [] as $process_name => $config) {
$process_files[] = write_process_file($runtime_process_path, $process_name, $firm);
}
}
function write_process_file($runtime_process_path, $process_name, $firm)
{
$process_param = $firm ? "plugin.$firm.$process_name" : $process_name;
$config_param = $firm ? "config('plugin.$firm.process')['$process_name']" : "config('process')['$process_name']";
$file_content = <<<EOF
<?php
require_once __DIR__ . '/../../vendor/autoload.php';
use Workerman\Worker;
use Webman\Config;
use support\App;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
......@@ -64,20 +71,25 @@ if (is_callable('opcache_reset')) {
opcache_reset();
}
Config::load(config_path(), ['route', 'container']);
App::loadAllConfig(['route']);
worker_start('$process_param', $config_param);
if (DIRECTORY_SEPARATOR != "/") {
Worker::\$logFile = config('server')['log_file'] ?? Worker::\$logFile;
}
worker_start("plugin.$firm.$name.$process_name", config("plugin.$firm.$name.process")['$process_name']);
Worker::runAll();
EOF;
$process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_name.php";
$process_files[] = $process_file;
$process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_param.php";
file_put_contents($process_file, $file_content);
}
}
return $process_file;
}
$monitor = new Monitor(...array_values(config('process.monitor.constructor')));
if ($monitor_config = config('process.monitor.constructor')) {
$monitor = new Monitor(...array_values($monitor_config));
}
function popen_processes($process_files)
{
......@@ -94,7 +106,7 @@ $resource = popen_processes($process_files);
echo "\r\n";
while (1) {
sleep(1);
if ($monitor->checkAllFilesChange()) {
if (!empty($monitor) && $monitor->checkAllFilesChange()) {
$status = proc_get_status($resource);
$pid = $status['pid'];
shell_exec("taskkill /F /T /PID $pid");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment