正在显示
100 个修改的文件
包含
4389 行增加
和
16 行删除
.idea/.gitignore
0 → 100644
.idea/inspectionProfiles/Project_Default.xml
0 → 100644
.idea/jsLinters/jshint.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project version="4"> | ||
3 | + <component name="JSHintConfiguration" version="2.13.0" use-config-file="true" use-custom-config-file="true" custom-config-file-path="$PROJECT_DIR$/public/assets/libs/bootstrap/grunt/.jshintrc"> | ||
4 | + <option bitwise="true" /> | ||
5 | + <option browser="true" /> | ||
6 | + <option curly="true" /> | ||
7 | + <option eqeqeq="true" /> | ||
8 | + <option forin="true" /> | ||
9 | + <option maxerr="50" /> | ||
10 | + <option noarg="true" /> | ||
11 | + <option noempty="true" /> | ||
12 | + <option nonew="true" /> | ||
13 | + <option strict="true" /> | ||
14 | + <option undef="true" /> | ||
15 | + </component> | ||
16 | +</project> |
.idea/modules.xml
0 → 100644
.idea/net_car.iml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<module type="WEB_MODULE" version="4"> | ||
3 | + <component name="NewModuleRootManager"> | ||
4 | + <content url="file://$MODULE_DIR$"> | ||
5 | + <sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" /> | ||
6 | + <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" /> | ||
7 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" /> | ||
8 | + <excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" /> | ||
9 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php73" /> | ||
10 | + <excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" /> | ||
11 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" /> | ||
12 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" /> | ||
13 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" /> | ||
14 | + <excludeFolder url="file://$MODULE_DIR$/vendor/paragonie/random_compat" /> | ||
15 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/psr-http-message-bridge" /> | ||
16 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" /> | ||
17 | + <excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" /> | ||
18 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" /> | ||
19 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" /> | ||
20 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" /> | ||
21 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" /> | ||
22 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" /> | ||
23 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" /> | ||
24 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" /> | ||
25 | + <excludeFolder url="file://$MODULE_DIR$/vendor/maennchen/zipstream-php" /> | ||
26 | + <excludeFolder url="file://$MODULE_DIR$/vendor/txthinking/mailer" /> | ||
27 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" /> | ||
28 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" /> | ||
29 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" /> | ||
30 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" /> | ||
31 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/simple-cache" /> | ||
32 | + <excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-factory" /> | ||
33 | + <excludeFolder url="file://$MODULE_DIR$/vendor/nelexa/zip" /> | ||
34 | + <excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/php-enum" /> | ||
35 | + <excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" /> | ||
36 | + <excludeFolder url="file://$MODULE_DIR$/vendor/topthink/think-captcha" /> | ||
37 | + <excludeFolder url="file://$MODULE_DIR$/vendor/topthink/think-installer" /> | ||
38 | + <excludeFolder url="file://$MODULE_DIR$/vendor/topthink/think-queue" /> | ||
39 | + <excludeFolder url="file://$MODULE_DIR$/vendor/topthink/think-helper" /> | ||
40 | + <excludeFolder url="file://$MODULE_DIR$/vendor/composer" /> | ||
41 | + <excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/wechat" /> | ||
42 | + <excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/pinyin" /> | ||
43 | + <excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/socialite" /> | ||
44 | + <excludeFolder url="file://$MODULE_DIR$/vendor/easywechat-composer/easywechat-composer" /> | ||
45 | + <excludeFolder url="file://$MODULE_DIR$/vendor/ezyang/htmlpurifier" /> | ||
46 | + <excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/matrix" /> | ||
47 | + <excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/complex" /> | ||
48 | + <excludeFolder url="file://$MODULE_DIR$/vendor/phpoffice/phpspreadsheet" /> | ||
49 | + <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" /> | ||
50 | + <excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" /> | ||
51 | + <excludeFolder url="file://$MODULE_DIR$/vendor/pimple/pimple" /> | ||
52 | + <excludeFolder url="file://$MODULE_DIR$/vendor/karsonzhang/fastadmin-addons" /> | ||
53 | + </content> | ||
54 | + <orderEntry type="inheritedJdk" /> | ||
55 | + <orderEntry type="sourceFolder" forTests="false" /> | ||
56 | + </component> | ||
57 | +</module> |
.idea/php.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project version="4"> | ||
3 | + <component name="PhpIncludePathManager"> | ||
4 | + <include_path> | ||
5 | + <path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" /> | ||
6 | + <path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" /> | ||
7 | + <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php73" /> | ||
8 | + <path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" /> | ||
9 | + <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" /> | ||
10 | + <path value="$PROJECT_DIR$/vendor/symfony/service-contracts" /> | ||
11 | + <path value="$PROJECT_DIR$/vendor/symfony/cache" /> | ||
12 | + <path value="$PROJECT_DIR$/vendor/paragonie/random_compat" /> | ||
13 | + <path value="$PROJECT_DIR$/vendor/symfony/psr-http-message-bridge" /> | ||
14 | + <path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" /> | ||
15 | + <path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" /> | ||
16 | + <path value="$PROJECT_DIR$/vendor/symfony/http-foundation" /> | ||
17 | + <path value="$PROJECT_DIR$/vendor/psr/cache" /> | ||
18 | + <path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" /> | ||
19 | + <path value="$PROJECT_DIR$/vendor/psr/log" /> | ||
20 | + <path value="$PROJECT_DIR$/vendor/symfony/var-exporter" /> | ||
21 | + <path value="$PROJECT_DIR$/vendor/psr/http-message" /> | ||
22 | + <path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" /> | ||
23 | + <path value="$PROJECT_DIR$/vendor/maennchen/zipstream-php" /> | ||
24 | + <path value="$PROJECT_DIR$/vendor/txthinking/mailer" /> | ||
25 | + <path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" /> | ||
26 | + <path value="$PROJECT_DIR$/vendor/symfony/finder" /> | ||
27 | + <path value="$PROJECT_DIR$/vendor/psr/container" /> | ||
28 | + <path value="$PROJECT_DIR$/vendor/psr/http-client" /> | ||
29 | + <path value="$PROJECT_DIR$/vendor/psr/simple-cache" /> | ||
30 | + <path value="$PROJECT_DIR$/vendor/psr/http-factory" /> | ||
31 | + <path value="$PROJECT_DIR$/vendor/nelexa/zip" /> | ||
32 | + <path value="$PROJECT_DIR$/vendor/myclabs/php-enum" /> | ||
33 | + <path value="$PROJECT_DIR$/vendor/monolog/monolog" /> | ||
34 | + <path value="$PROJECT_DIR$/vendor/topthink/think-captcha" /> | ||
35 | + <path value="$PROJECT_DIR$/vendor/topthink/think-installer" /> | ||
36 | + <path value="$PROJECT_DIR$/vendor/topthink/think-queue" /> | ||
37 | + <path value="$PROJECT_DIR$/vendor/topthink/think-helper" /> | ||
38 | + <path value="$PROJECT_DIR$/vendor/composer" /> | ||
39 | + <path value="$PROJECT_DIR$/vendor/overtrue/wechat" /> | ||
40 | + <path value="$PROJECT_DIR$/vendor/overtrue/pinyin" /> | ||
41 | + <path value="$PROJECT_DIR$/vendor/overtrue/socialite" /> | ||
42 | + <path value="$PROJECT_DIR$/vendor/easywechat-composer/easywechat-composer" /> | ||
43 | + <path value="$PROJECT_DIR$/vendor/ezyang/htmlpurifier" /> | ||
44 | + <path value="$PROJECT_DIR$/vendor/markbaker/matrix" /> | ||
45 | + <path value="$PROJECT_DIR$/vendor/markbaker/complex" /> | ||
46 | + <path value="$PROJECT_DIR$/vendor/phpoffice/phpspreadsheet" /> | ||
47 | + <path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" /> | ||
48 | + <path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" /> | ||
49 | + <path value="$PROJECT_DIR$/vendor/pimple/pimple" /> | ||
50 | + <path value="$PROJECT_DIR$/vendor/karsonzhang/fastadmin-addons" /> | ||
51 | + </include_path> | ||
52 | + </component> | ||
53 | + <component name="PhpProjectSharedConfiguration" php_language_level="7.2" /> | ||
54 | +</project> |
addons/.htaccess
0 → 100644
1 | +deny from all |
addons/command/.addonrc
0 → 100644
1 | +{"files":["application\\admin\\controller\\Command.php","application\\admin\\lang\\zh-cn\\command.php","application\\admin\\model\\Command.php","application\\admin\\validate\\Command.php","application\\admin\\view\\command\\add.html","application\\admin\\view\\command\\detail.html","application\\admin\\view\\command\\index.html","public\\assets\\js\\backend\\command.js"],"license":"regular","licenseto":"15629","licensekey":"t3xqhifIVFUO9y10 \/A0tfljqlYH+SOyMs1bg+A==","domains":["netcar.com"],"licensecodes":[],"validations":["9c3b042fdd8c2e4e21e4da30dcc79ba1"],"menus":["command","command\/index","command\/add","command\/detail","command\/command","command\/execute","command\/del","command\/multi"]} |
addons/command/Command.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\command; | ||
4 | + | ||
5 | +use app\common\library\Menu; | ||
6 | +use think\Addons; | ||
7 | + | ||
8 | +/** | ||
9 | + * 在线命令插件 | ||
10 | + */ | ||
11 | +class Command extends Addons | ||
12 | +{ | ||
13 | + | ||
14 | + /** | ||
15 | + * 插件安装方法 | ||
16 | + * @return bool | ||
17 | + */ | ||
18 | + public function install() | ||
19 | + { | ||
20 | + $menu = [ | ||
21 | + [ | ||
22 | + 'name' => 'command', | ||
23 | + 'title' => '在线命令管理', | ||
24 | + 'icon' => 'fa fa-terminal', | ||
25 | + 'sublist' => [ | ||
26 | + ['name' => 'command/index', 'title' => '查看'], | ||
27 | + ['name' => 'command/add', 'title' => '添加'], | ||
28 | + ['name' => 'command/detail', 'title' => '详情'], | ||
29 | + ['name' => 'command/command', 'title' => '生成并执行命令'], | ||
30 | + ['name' => 'command/execute', 'title' => '再次执行命令'], | ||
31 | + ['name' => 'command/del', 'title' => '删除'], | ||
32 | + ['name' => 'command/multi', 'title' => '批量更新'], | ||
33 | + ] | ||
34 | + ] | ||
35 | + ]; | ||
36 | + Menu::create($menu); | ||
37 | + return true; | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * 插件卸载方法 | ||
42 | + * @return bool | ||
43 | + */ | ||
44 | + public function uninstall() | ||
45 | + { | ||
46 | + Menu::delete('command'); | ||
47 | + return true; | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * 插件启用方法 | ||
52 | + * @return bool | ||
53 | + */ | ||
54 | + public function enable() | ||
55 | + { | ||
56 | + Menu::enable('command'); | ||
57 | + return true; | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * 插件禁用方法 | ||
62 | + * @return bool | ||
63 | + */ | ||
64 | + public function disable() | ||
65 | + { | ||
66 | + Menu::disable('command'); | ||
67 | + return true; | ||
68 | + } | ||
69 | + | ||
70 | +} |
addons/command/config.php
0 → 100644
addons/command/controller/Index.php
0 → 100644
addons/command/info.ini
0 → 100644
addons/command/install.sql
0 → 100644
1 | +CREATE TABLE IF NOT EXISTS `__PREFIX__command` ( | ||
2 | + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', | ||
3 | + `type` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '类型', | ||
4 | + `params` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '参数', | ||
5 | + `command` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '命令', | ||
6 | + `content` text COMMENT '返回结果', | ||
7 | + `executetime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '执行时间', | ||
8 | + `createtime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '创建时间', | ||
9 | + `updatetime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '更新时间', | ||
10 | + `status` enum('successed','failured') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'failured' COMMENT '状态', | ||
11 | + PRIMARY KEY (`id`) USING BTREE | ||
12 | +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '在线命令表'; |
addons/command/library/Output.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\command\library; | ||
4 | + | ||
5 | +/** | ||
6 | + * Class Output | ||
7 | + */ | ||
8 | +class Output extends \think\console\Output | ||
9 | +{ | ||
10 | + | ||
11 | + protected $message = []; | ||
12 | + | ||
13 | + public function __construct($driver = 'console') | ||
14 | + { | ||
15 | + parent::__construct($driver); | ||
16 | + } | ||
17 | + | ||
18 | + protected function block($style, $message) | ||
19 | + { | ||
20 | + $this->message[] = $message; | ||
21 | + } | ||
22 | + | ||
23 | + public function getMessage() | ||
24 | + { | ||
25 | + return $this->message; | ||
26 | + } | ||
27 | + | ||
28 | +} |
addons/epay/.addonrc
0 → 100644
1 | +{"files":["application\\admin\\controller\\Epay.php","public\\assets\\addons\\epay\\css\\common.css","public\\assets\\addons\\epay\\images\\alipay.png","public\\assets\\addons\\epay\\images\\expired.png","public\\assets\\addons\\epay\\images\\logo-alipay.png","public\\assets\\addons\\epay\\images\\logo-wechat.png","public\\assets\\addons\\epay\\images\\paid.png","public\\assets\\addons\\epay\\images\\scan.png","public\\assets\\addons\\epay\\images\\screenshot-alipay.png","public\\assets\\addons\\epay\\images\\screenshot-wechat.png","public\\assets\\addons\\epay\\images\\wechat.png","public\\assets\\addons\\epay\\js\\common.js","public\\assets\\addons\\epay\\js\\jquery.qrcode.min.js","public\\assets\\addons\\epay\\less\\common.less"],"license":"regular","licenseto":"15629","licensekey":"jDldGfubs2Z1LF0e lqiyCf\/v9miOo5GwX7kPXA==","domains":["netcar.com"],"licensecodes":[],"validations":["9c3b042fdd8c2e4e21e4da30dcc79ba1"]} |
addons/epay/Epay.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay; | ||
4 | + | ||
5 | +use addons\epay\library\Service; | ||
6 | +use think\Addons; | ||
7 | +use think\Config; | ||
8 | +use think\Loader; | ||
9 | + | ||
10 | +/** | ||
11 | + * 微信支付宝整合插件 | ||
12 | + */ | ||
13 | +class Epay extends Addons | ||
14 | +{ | ||
15 | + | ||
16 | + /** | ||
17 | + * 插件安装方法 | ||
18 | + * @return bool | ||
19 | + */ | ||
20 | + public function install() | ||
21 | + { | ||
22 | + return true; | ||
23 | + } | ||
24 | + | ||
25 | + /** | ||
26 | + * 插件卸载方法 | ||
27 | + * @return bool | ||
28 | + */ | ||
29 | + public function uninstall() | ||
30 | + { | ||
31 | + return true; | ||
32 | + } | ||
33 | + | ||
34 | + /** | ||
35 | + * 插件启用方法 | ||
36 | + * @return bool | ||
37 | + */ | ||
38 | + public function enable() | ||
39 | + { | ||
40 | + return true; | ||
41 | + } | ||
42 | + | ||
43 | + /** | ||
44 | + * 插件禁用方法 | ||
45 | + * @return bool | ||
46 | + */ | ||
47 | + public function disable() | ||
48 | + { | ||
49 | + return true; | ||
50 | + } | ||
51 | + | ||
52 | + // 支持自定义加载 | ||
53 | + public function epayConfigInit() | ||
54 | + { | ||
55 | + $this->actionBegin(); | ||
56 | + } | ||
57 | + | ||
58 | + // 插件方法加载开始 | ||
59 | + public function addonActionBegin() | ||
60 | + { | ||
61 | + $this->actionBegin(); | ||
62 | + } | ||
63 | + | ||
64 | + // 模块控制器方法加载开始 | ||
65 | + public function actionBegin() | ||
66 | + { | ||
67 | + //添加命名空间 | ||
68 | + if (!class_exists('\Yansongda\Pay\Pay')) { | ||
69 | + | ||
70 | + //SDK版本 | ||
71 | + $version = Service::getSdkVersion(); | ||
72 | + | ||
73 | + $libraryDir = ADDON_PATH . 'epay' . DS . 'library' . DS; | ||
74 | + Loader::addNamespace('Yansongda\Pay', $libraryDir . $version . DS . 'Yansongda' . DS . 'Pay' . DS); | ||
75 | + | ||
76 | + $checkArr = [ | ||
77 | + '\Hyperf\Context\Context' => 'context', | ||
78 | + '\Hyperf\Contract\Castable' => 'contract', | ||
79 | + '\Hyperf\Engine\Constant' => 'engine', | ||
80 | + '\Hyperf\Macroable\Macroable' => 'macroable', | ||
81 | + '\Hyperf\Pimple\Container' => 'pimple', | ||
82 | + '\Hyperf\Utils\Arr' => 'utils', | ||
83 | + ]; | ||
84 | + foreach ($checkArr as $index => $item) { | ||
85 | + if (!class_exists($index)) { | ||
86 | + Loader::addNamespace(substr($index, 1, strrpos($index, '\\') - 1), $libraryDir . 'hyperf' . DS . $item . DS . 'src' . DS); | ||
87 | + } | ||
88 | + } | ||
89 | + | ||
90 | + if (!class_exists('\Yansongda\Supports\Logger')) { | ||
91 | + Loader::addNamespace('Yansongda\Supports', $libraryDir . $version . DS . 'Yansongda' . DS . 'Supports' . DS); | ||
92 | + } | ||
93 | + | ||
94 | + // V3需载入辅助函数 | ||
95 | + if ($version == Service::SDK_VERSION_V3) { | ||
96 | + require_once $libraryDir . $version . DS . 'Yansongda' . DS . 'Pay' . DS . 'Functions.php'; | ||
97 | + } | ||
98 | + } | ||
99 | + } | ||
100 | +} |
addons/epay/certs/alipayCertPublicKey.crt
0 → 100644
addons/epay/certs/alipayRootCert.crt
0 → 100644
addons/epay/certs/apiclient_cert.pem
0 → 100644
1 | +-----BEGIN CERTIFICATE----- | ||
2 | +MIID8DCCAtigAwIBAgIUI9c+NLMTUooCydaSivNg0qlO4pcwDQYJKoZIhvcNAQEL | ||
3 | +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT | ||
4 | +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg | ||
5 | +Q0EwHhcNMjExMjEwMDMxMDQyWhcNMjYxMjA5MDMxMDQyWjCBgTETMBEGA1UEAwwK | ||
6 | +MTU1NzI4MzU3MTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQL | ||
7 | +DCTmt7HlnLPmnoHpgJ/liJvmg7Pnp5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYM | ||
8 | +AkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC | ||
9 | +AQoCggEBAJX49o4WWgRLNyhTzSctwer8/GQM934b0gIERFdoEN5ciPBWcTTIvuzr | ||
10 | +z+H4puHR4icmHcyEAnOJlWc1d/nhOLZTMYGnk+DGhO+eKs4RovwqIZRbMzN2jTuF | ||
11 | +pecl6YvQoF3InqcKjJjPWfUQvKevSdnMM0/tatZwB4liHBtLL4Lm4yEtHnoMm8kI | ||
12 | +/qSG9qz3anSDNyGglV0HQm+yeAVdphRnccKHSGDl+ZXS28fYeRV+nXtM8FHme0Zt | ||
13 | +1jtOikMWetiQ5l8RUxAZFHdhHTeH0r2hDpNfEANt5oqyUQZ6b7BilyzHd8faC34J | ||
14 | +vegofWjg7CwXHix7p3KwkCubsIlRYKsCAwEAAaOBgTB/MAkGA1UdEwQCMAAwCwYD | ||
15 | +VR0PBAQDAgTwMGUGA1UdHwReMFwwWqBYoFaGVGh0dHA6Ly9ldmNhLml0cnVzLmNv | ||
16 | +bS5jbi9wdWJsaWMvaXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1 | ||
17 | +NDk4NDZDMDFDM0U4RUJEMjANBgkqhkiG9w0BAQsFAAOCAQEAuuQY/gKETCEos68v | ||
18 | +rPq8C/v50PjZxGawXWfpuudrbvi4ZiH8x+Sd+JRWXn+8mQX9Y+qYWcaeb2UIrQm1 | ||
19 | +FYP9H2nanncT75H4NpPCmCnNtgqI9/nyxwfLgViwvnTiaPQs4PEDpHJnyJeexgCV | ||
20 | +j5EzkPFC7izcdhLQ4ruE/1sa8c8ww3yKfdUcZz+zQzb+J37bwcZtoCm5lHm9azAP | ||
21 | +mwAMlZiIP9C8VEk0UsMC4SfDOIufjgLmTsoOg4VkIyCQ8tZBsmY7IG5W+CmQl478 | ||
22 | +duxt2bOa4V8FEspoRJ059i8inK29Bj1hWKK69CmgMI6qUToHgwRtd6g2LTbt8Mwy | ||
23 | +K5gWAg== | ||
24 | +-----END CERTIFICATE----- |
addons/epay/certs/apiclient_key.pem
0 → 100644
1 | +-----BEGIN PRIVATE KEY----- | ||
2 | +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCV+PaOFloESzco | ||
3 | +U80nLcHq/PxkDPd+G9ICBERXaBDeXIjwVnE0yL7s68/h+Kbh0eInJh3MhAJziZVn | ||
4 | +NXf54Ti2UzGBp5PgxoTvnirOEaL8KiGUWzMzdo07haXnJemL0KBdyJ6nCoyYz1n1 | ||
5 | +ELynr0nZzDNP7WrWcAeJYhwbSy+C5uMhLR56DJvJCP6khvas92p0gzchoJVdB0Jv | ||
6 | +sngFXaYUZ3HCh0hg5fmV0tvH2HkVfp17TPBR5ntGbdY7TopDFnrYkOZfEVMQGRR3 | ||
7 | +YR03h9K9oQ6TXxADbeaKslEGem+wYpcsx3fH2gt+Cb3oKH1o4OwsFx4se6dysJAr | ||
8 | +m7CJUWCrAgMBAAECggEAeJjGyuM2Z5WEOS2KHyMweKIO4vV6XzJH4c9ElXTde7G1 | ||
9 | +fG5GgkebIDFP7UpiB90ampiQBdFxly7fsSrR22I8lIC5oqT6yRlZ9MWfbi3IfjXy | ||
10 | +4rWjqpJ+Z4rFKebWstOE4WVeDrzw6kBy+hoHWmAeZsFJ0c/8xYs4xETcjSYcgomk | ||
11 | +oJwjegWz5YwuiwT8wm9WFFJK9CQ1T8V3xDqDKUnmtT/bak7qpfu3Gkf4ddd7iWzU | ||
12 | +MqrLFZrsYZoFjBq5Bq/sPDFB4jox8/5v/Cztwin3+H4nJoHN4tWk1PuUXaj4UPvW | ||
13 | +iVNeTjUjttVVA2N3hdIV7Wabp9UulES+aOoA9UB04QKBgQDFQ8AOO37EiEKzHqch | ||
14 | +rp7gwO5zQxyEZJ8/xrrpc/vTmTrJLqWkiMq51+y0Wd1H4IUt6s4uR01fEytcnwmK | ||
15 | +7pmYePy2rPymoxRKYTpbPiueNTQhc7Ch3Ipt4Nuuu724nxccacjnPVOUZhd3WDtQ | ||
16 | +sh6L5TiKtG/EZgEpzFz1p06kVwKBgQDCoG3hDlc2MfzHQwP0b26qwT02tmU9+Nb2 | ||
17 | +UDJCmDxrBD7wieH3N5Pep/dbOSFAFiLQvXF/aVUmta/B9c4YXpFZnob2nFFkyyOq | ||
18 | +OhMLqOsRrn/agYKwlR8WIwakCOFBNevJFNPRm2TSPkc1SOefbT628L/ytOFIc5f5 | ||
19 | +C/GFyEIRzQKBgQCqM7SoEwljxTXXmqEV3LbUsWKMLOGUEcWdn3hyKVKk1db08ryU | ||
20 | +5DoWc4mWatsUQ1JltezD3V2SpNWLCuWO7CO2fN1/OG6d0KOXMaDKTTARR1J9cnZ6 | ||
21 | +kfEWsSaa8v3VJ98m8tcXPcC5kAS7QnObQrQ8fEB23Qx6ZpCmYd/rTLn77QKBgELz | ||
22 | +DNkuJbHu4BVraCDddCQo9PWtKIZ44vk3/RILbD0j6MK1q5Vu+N7OyLgInvd8pd1I | ||
23 | +TZKWmUQHm74M4Chh334Emkia3STe/BXChGquYK5kaHaxtlMn+NmUkuQ6acIU2lcB | ||
24 | +YxvnaHcqFTSvL34YBkrH5j+HGTfjC5QQF7T9fjzBAoGASGGE4EbPGfvzs3wTcpkY | ||
25 | +99iiUHI2sIUaVByhCvUnh8IUzENsf3lDnV92l4MszIL7wzVALNW5sbqOVlnF7/FM | ||
26 | +0cxK6XDbS8xlbndin2Kmale23esilo9dVU6URTxbUE1f5MdgNgG3duQELVnN/our | ||
27 | +b7P/crZDjuCZ5IdVJHZy3+c= | ||
28 | +-----END PRIVATE KEY----- |
addons/epay/certs/appCertPublicKey.crt
0 → 100644
addons/epay/config.html
0 → 100644
1 | +<form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <div class="panel panel-default panel-intro"> | ||
4 | + <div class="panel-heading"> | ||
5 | + <ul class="nav nav-tabs nav-group"> | ||
6 | + <li class="active"><a href="#wechat" data-toggle="tab">微信支付</a></li> | ||
7 | + <li><a href="#alipay" data-toggle="tab">支付宝</a></li> | ||
8 | + </ul> | ||
9 | + </div> | ||
10 | + | ||
11 | + <div class="panel-body"> | ||
12 | + <div id="myTabContent" class="tab-content"> | ||
13 | + {foreach $addon.config as $item} | ||
14 | + {if $item.name=='version'} | ||
15 | + <input type="hidden" value="{$item.value}" name="row[version]"/> | ||
16 | + | ||
17 | + {elseif $item.name=='wechat'/} | ||
18 | + <div class="tab-pane fade active in" id="wechat"> | ||
19 | + <table class="table table-striped table-config"> | ||
20 | + <tbody> | ||
21 | + <tr> | ||
22 | + <td width="20%">APP的app_id</td> | ||
23 | + <td> | ||
24 | + <div class="row"> | ||
25 | + <div class="col-sm-8 col-xs-12"> | ||
26 | + <input type="text" name="row[wechat][appid]" value="{$item.value.appid|default=''}" class="form-control" data-rule="" data-tip="APP应用中支付时使用"/> | ||
27 | + </div> | ||
28 | + <div class="col-sm-4"></div> | ||
29 | + </div> | ||
30 | + </td> | ||
31 | + </tr> | ||
32 | + <tr> | ||
33 | + <td>公众号的app_id</td> | ||
34 | + <td> | ||
35 | + <div class="row"> | ||
36 | + <div class="col-sm-8 col-xs-12"> | ||
37 | + <input type="text" name="row[wechat][app_id]" value="{$item.value.app_id|default=''}" class="form-control" data-rule="" data-tip="公众号中支付时使用"/> | ||
38 | + </div> | ||
39 | + <div class="col-sm-4"></div> | ||
40 | + </div> | ||
41 | + </td> | ||
42 | + </tr> | ||
43 | + <tr> | ||
44 | + <td>公众号的app_secret</td> | ||
45 | + <td> | ||
46 | + <div class="row"> | ||
47 | + <div class="col-sm-8 col-xs-12"> | ||
48 | + <input type="text" name="row[wechat][app_secret]" value="{$item.value.app_secret|default=''}" class="form-control" data-rule="" data-tip="公众号中支付时使用"/> | ||
49 | + </div> | ||
50 | + <div class="col-sm-4"></div> | ||
51 | + </div> | ||
52 | + </td> | ||
53 | + </tr> | ||
54 | + <tr> | ||
55 | + <td>小程序的app_id</td> | ||
56 | + <td> | ||
57 | + <div class="row"> | ||
58 | + <div class="col-sm-8 col-xs-12"> | ||
59 | + <input type="text" name="row[wechat][miniapp_id]" value="{$item.value.miniapp_id|default=''}" class="form-control" data-rule="" data-tip="仅在小程序支付时使用"/> | ||
60 | + </div> | ||
61 | + <div class="col-sm-4"></div> | ||
62 | + </div> | ||
63 | + </td> | ||
64 | + </tr> | ||
65 | + <tr> | ||
66 | + <td>微信支付商户号</td> | ||
67 | + <td> | ||
68 | + <div class="row"> | ||
69 | + <div class="col-sm-8 col-xs-12"> | ||
70 | + <input type="text" name="row[wechat][mch_id]" value="{$item.value.mch_id|default=''}" class="form-control" data-rule="" data-tip=""/> | ||
71 | + </div> | ||
72 | + <div class="col-sm-4"></div> | ||
73 | + </div> | ||
74 | + </td> | ||
75 | + </tr> | ||
76 | + <tr> | ||
77 | + <td>微信支付商户API密钥V2</td> | ||
78 | + <td> | ||
79 | + <div class="row"> | ||
80 | + <div class="col-sm-8 col-xs-12"> | ||
81 | + <input type="text" name="row[wechat][key]" value="{$item.value.key|default=''}" class="form-control" data-rule="" data-tip=""/> | ||
82 | + </div> | ||
83 | + <div class="col-sm-4"></div> | ||
84 | + </div> | ||
85 | + </td> | ||
86 | + </tr> | ||
87 | + <tr> | ||
88 | + <td>微信支付商户API密钥V3</td> | ||
89 | + <td> | ||
90 | + <div class="row"> | ||
91 | + <div class="col-sm-8 col-xs-12"> | ||
92 | + <input type="text" name="row[wechat][key_v3]" value="{$item.value.key_v3|default=''}" class="form-control" data-rule="" data-tip=""/> | ||
93 | + </div> | ||
94 | + <div class="col-sm-4"></div> | ||
95 | + </div> | ||
96 | + </td> | ||
97 | + </tr> | ||
98 | + <tr> | ||
99 | + <td>支付模式</td> | ||
100 | + <td> | ||
101 | + <div class="row"> | ||
102 | + <div class="col-sm-8 col-xs-12"> | ||
103 | + {:Form::radios('row[wechat][mode]',['normal'=>'正式环境','dev'=>'沙箱环境','service'=>'服务商模式'],$item.value.mode??'normal')} | ||
104 | + <div style="margin-top:5px;" data-type="dev" class="text-muted {if ($item.value.mode??'')!=='dev'}hidden{/if}"> | ||
105 | + <i class="fa fa-info-circle"></i> 沙箱环境:<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1&index=2" target="_blank">微信支付验收指引</a> | ||
106 | + </div> | ||
107 | + </div> | ||
108 | + <div class="col-sm-4"></div> | ||
109 | + </div> | ||
110 | + </td> | ||
111 | + </tr> | ||
112 | + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}"> | ||
113 | + <td>子商户商户号ID</td> | ||
114 | + <td> | ||
115 | + <div class="row"> | ||
116 | + <div class="col-sm-8 col-xs-12"> | ||
117 | + <input type="text" name="row[wechat][sub_mch_id]" value="{$item.value.sub_mch_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/> | ||
118 | + </div> | ||
119 | + <div class="col-sm-4"></div> | ||
120 | + </div> | ||
121 | + </td> | ||
122 | + </tr> | ||
123 | + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}"> | ||
124 | + <td>子商户APP的app_id</td> | ||
125 | + <td> | ||
126 | + <div class="row"> | ||
127 | + <div class="col-sm-8 col-xs-12"> | ||
128 | + <input type="text" name="row[wechat][sub_appid]" value="{$item.value.sub_appid|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/> | ||
129 | + </div> | ||
130 | + <div class="col-sm-4"></div> | ||
131 | + </div> | ||
132 | + </td> | ||
133 | + </tr> | ||
134 | + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}"> | ||
135 | + <td>子商户公众号的app_id</td> | ||
136 | + <td> | ||
137 | + <div class="row"> | ||
138 | + <div class="col-sm-8 col-xs-12"> | ||
139 | + <input type="text" name="row[wechat][sub_app_id]" value="{$item.value.sub_app_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/> | ||
140 | + </div> | ||
141 | + <div class="col-sm-4"></div> | ||
142 | + </div> | ||
143 | + </td> | ||
144 | + </tr> | ||
145 | + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}"> | ||
146 | + <td>子商户小程序的app_id</td> | ||
147 | + <td> | ||
148 | + <div class="row"> | ||
149 | + <div class="col-sm-8 col-xs-12"> | ||
150 | + <input type="text" name="row[wechat][sub_miniapp_id]" value="{$item.value.sub_miniapp_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/> | ||
151 | + </div> | ||
152 | + <div class="col-sm-4"></div> | ||
153 | + </div> | ||
154 | + </td> | ||
155 | + </tr> | ||
156 | + <tr> | ||
157 | + <td>回调通知地址</td> | ||
158 | + <td> | ||
159 | + <div class="row"> | ||
160 | + <div class="col-sm-8 col-xs-12"> | ||
161 | + <input type="text" name="row[wechat][notify_url]" value="{$item.value.notify_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/> | ||
162 | + </div> | ||
163 | + <div class="col-sm-4"></div> | ||
164 | + </div> | ||
165 | + </td> | ||
166 | + </tr> | ||
167 | + <tr> | ||
168 | + <td>微信支付API证书cert</td> | ||
169 | + <td> | ||
170 | + <div class="row"> | ||
171 | + <div class="col-sm-8 col-xs-12"> | ||
172 | + <div class="input-group"> | ||
173 | + <input id="c-cert_client" class="form-control" size="50" name="row[wechat][cert_client]" type="text" value="{$item.value.cert_client|htmlentities}" data-tip="可选, 仅在退款、红包等情况时需要用到"> | ||
174 | + <div class="input-group-addon no-border no-padding"> | ||
175 | + <span><button type="button" id="faupload-cert_client" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"cert_client"}' data-mimetype="pem" data-input-id="c-cert_client" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> | ||
176 | + </div> | ||
177 | + <span class="msg-box n-right" for="c-cert_client"></span> | ||
178 | + </div> | ||
179 | + <div style="margin-top:5px;"><a href="https://pay.weixin.qq.com" target="_blank"><i class="fa fa-question-circle"></i> 如何获取微信支付API证书?</a></div> | ||
180 | + </div> | ||
181 | + <div class="col-sm-4"></div> | ||
182 | + </div> | ||
183 | + </td> | ||
184 | + </tr> | ||
185 | + <tr> | ||
186 | + <td>微信支付API证书key</td> | ||
187 | + <td> | ||
188 | + <div class="row"> | ||
189 | + <div class="col-sm-8 col-xs-12"> | ||
190 | + <div class="input-group"> | ||
191 | + <input id="c-cert_key" class="form-control" size="50" name="row[wechat][cert_key]" type="text" value="{$item.value.cert_key|htmlentities}" data-tip="可选, 仅在退款、红包等情况时需要用到"> | ||
192 | + <div class="input-group-addon no-border no-padding"> | ||
193 | + <span><button type="button" id="faupload-cert_key" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"cert_key"}' data-mimetype="pem" data-input-id="c-cert_key" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> | ||
194 | + </div> | ||
195 | + <span class="msg-box n-right" for="c-cert_key"></span> | ||
196 | + </div> | ||
197 | + <div style="margin-top:5px;"><a href="https://pay.weixin.qq.com" target="_blank"><i class="fa fa-question-circle"></i> 如何获取微信支付API证书?</a></div> | ||
198 | + </div> | ||
199 | + <div class="col-sm-4"></div> | ||
200 | + </div> | ||
201 | + </td> | ||
202 | + </tr> | ||
203 | + | ||
204 | + <tr> | ||
205 | + <td>记录日志</td> | ||
206 | + <td> | ||
207 | + <div class="row"> | ||
208 | + <div class="col-sm-8 col-xs-12"> | ||
209 | + {:Form::radios('row[wechat][log]',['1'=>'开启','0'=>'关闭'],$item.value.log)} | ||
210 | + </div> | ||
211 | + <div class="col-sm-4"></div> | ||
212 | + </div> | ||
213 | + </td> | ||
214 | + </tr> | ||
215 | + </tbody> | ||
216 | + </table> | ||
217 | + </div> | ||
218 | + {elseif $item.name=='alipay'} | ||
219 | + <div class="tab-pane fade" id="alipay"> | ||
220 | + <table class="table table-striped table-config"> | ||
221 | + <tbody> | ||
222 | + <tr> | ||
223 | + <td>支付模式</td> | ||
224 | + <td> | ||
225 | + <div class="row"> | ||
226 | + <div class="col-sm-12 col-xs-12"> | ||
227 | + {:Form::radios('row[alipay][mode]',['normal'=>'正式环境','dev'=>'沙箱环境', 'service'=>'服务商模式'],$item.value.mode??'normal')} | ||
228 | + | ||
229 | + <div style="margin-top:5px;" data-mode="dev" class="text-muted {if ($item.value.mode??'')!=='dev'}hidden{/if}"> | ||
230 | + <i class="fa fa-info-circle"></i> 如果使用沙箱环境,务必使用沙箱的app_id和沙箱配置,以及使用沙箱账号进行测试。<br> | ||
231 | + 沙箱环境:<a href="https://openhome.alipay.com/develop/sandbox/app" target="_blank">https://openhome.alipay.com/develop/sandbox/app</a> | ||
232 | + </div> | ||
233 | + </div> | ||
234 | + </div> | ||
235 | + </td> | ||
236 | + </tr> | ||
237 | + <tr class="text-muted {if ($item.value.mode??'')!=='service'}hidden{/if}" data-mode="service"> | ||
238 | + <td width="20%">服务商ID(pid)</td> | ||
239 | + <td> | ||
240 | + <div class="row"> | ||
241 | + <div class="col-sm-8 col-xs-12"> | ||
242 | + <input type="text" name="row[alipay][pid]" value="{$item.value.pid|default=''}" class="form-control" data-rule="" data-tip=""/> | ||
243 | + </div> | ||
244 | + <div class="col-sm-4"></div> | ||
245 | + </div> | ||
246 | + </td> | ||
247 | + </tr> | ||
248 | + <tr> | ||
249 | + <td width="20%">应用ID(app_id)</td> | ||
250 | + <td> | ||
251 | + <div class="row"> | ||
252 | + <div class="col-sm-8 col-xs-12"> | ||
253 | + <input type="text" name="row[alipay][app_id]" value="{$item.value.app_id|default=''}" class="form-control" data-rule="" data-tip=""/> | ||
254 | + </div> | ||
255 | + <div class="col-sm-4"></div> | ||
256 | + </div> | ||
257 | + </td> | ||
258 | + </tr> | ||
259 | + <tr> | ||
260 | + <td>回调通知地址</td> | ||
261 | + <td> | ||
262 | + <div class="row"> | ||
263 | + <div class="col-sm-8 col-xs-12"> | ||
264 | + <input type="text" name="row[alipay][notify_url]" value="{$item.value.notify_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/> | ||
265 | + </div> | ||
266 | + <div class="col-sm-4"></div> | ||
267 | + </div> | ||
268 | + </td> | ||
269 | + </tr> | ||
270 | + <tr> | ||
271 | + <td>支付跳转地址</td> | ||
272 | + <td> | ||
273 | + <div class="row"> | ||
274 | + <div class="col-sm-8 col-xs-12"> | ||
275 | + <input type="text" name="row[alipay][return_url]" value="{$item.value.return_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/> | ||
276 | + </div> | ||
277 | + <div class="col-sm-4"></div> | ||
278 | + </div> | ||
279 | + </td> | ||
280 | + </tr> | ||
281 | + <tr> | ||
282 | + <td>应用私钥(private_key)</td> | ||
283 | + <td> | ||
284 | + <div class="row"> | ||
285 | + <div class="col-sm-8 col-xs-12"> | ||
286 | + <input type="text" name="row[alipay][private_key]" value="{$item.value.private_key|default=''}" class="form-control" data-rule=""/> | ||
287 | + <div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/helpcenter/207/201602469554" target="_blank"><i class="fa fa-question-circle"></i> 如何获取应用私钥?</a></div> | ||
288 | + </div> | ||
289 | + <div class="col-sm-4"></div> | ||
290 | + </div> | ||
291 | + </td> | ||
292 | + </tr> | ||
293 | + <tr> | ||
294 | + <td>签名方式</td> | ||
295 | + <td> | ||
296 | + <div> | ||
297 | + <div class="radio"> | ||
298 | + <label for="row[alipay][signtype]-publickey"><input id="row[alipay][signtype]-publickey" name="row[alipay][signtype]" {if isset($item.value.signtype)&&$item.value.signtype=='publickey'}checked{/if} type="radio" value="publickey"> 普通公钥</label> | ||
299 | + <label for="row[alipay][signtype]-cert"><input id="row[alipay][signtype]-cert" {if isset($item.value.signtype)&&$item.value.signtype=='cert'}checked{/if} name="row[alipay][signtype]" type="radio" value="cert"> 公钥证书</label> | ||
300 | + </div> | ||
301 | + </div> | ||
302 | + <div style="margin-top:5px;" class="text-muted"> | ||
303 | + <i class="fa fa-info-circle"></i> 如果要使用转账、提现功能,则必须使用公钥证书 | ||
304 | + </div> | ||
305 | + </td> | ||
306 | + </tr> | ||
307 | + <tr> | ||
308 | + <td> | ||
309 | + <span data-signtype="publickey" class="{if ($item.value.signtype??'')==='cert'}hidden{/if}">支付宝公钥</span> | ||
310 | + <span data-signtype="cert" class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}">支付宝公钥证书路径</span> | ||
311 | + (alipay_public_key) | ||
312 | + </td> | ||
313 | + <td> | ||
314 | + <div class="row"> | ||
315 | + <div class="col-sm-8 col-xs-12"> | ||
316 | + <div class="input-group"> | ||
317 | + <input id="c-ali_public_key" class="form-control" size="50" name="row[alipay][ali_public_key]" type="text" value="{$item.value.ali_public_key|default=''|htmlentities}" placeholder="普通公钥请直接粘贴,公钥证书请点击右侧的上传"> | ||
318 | + <div class="input-group-addon no-border no-padding {if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert"> | ||
319 | + <span><button type="button" id="faupload-ali_public_key" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"ali_public_key"}' data-mimetype="crt" data-input-id="c-ali_public_key" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> | ||
320 | + </div> | ||
321 | + <span class="msg-box n-right" for="c-ali_public_key"></span> | ||
322 | + </div> | ||
323 | + <div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/FAQ/aba5803b-ad15-4474-aed6-92e43ea253ea" target="_blank"><i class="fa fa-question-circle"></i> 如何获取支付宝公钥?</a></div> | ||
324 | + </div> | ||
325 | + <div class="col-sm-4"></div> | ||
326 | + </div> | ||
327 | + </td> | ||
328 | + </tr> | ||
329 | + <tr> | ||
330 | + <td> | ||
331 | + <span data-signtype="publickey" class="{if ($item.value.signtype??'')==='cert'}hidden{/if}">应用公钥</span> | ||
332 | + <span data-signtype="cert" class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}">应用公钥证书路径</span> | ||
333 | + (app_cert_public_key) | ||
334 | + </td> | ||
335 | + <td> | ||
336 | + <div class="row"> | ||
337 | + <div class="col-sm-8 col-xs-12"> | ||
338 | + <div class="input-group"> | ||
339 | + <input id="c-app_cert_public_key" class="form-control" size="50" name="row[alipay][app_cert_public_key]" type="text" value="{$item.value.app_cert_public_key|default=''|htmlentities}"> | ||
340 | + <div class="input-group-addon no-border no-padding {if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert"> | ||
341 | + <span><button type="button" id="faupload-app_cert_public_key" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"app_cert_public_key"}' data-mimetype="crt" data-input-id="c-app_cert_public_key" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> | ||
342 | + </div> | ||
343 | + <span class="msg-box n-right" for="c-app_cert_public_key"></span> | ||
344 | + </div> | ||
345 | + <div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/FAQ/aba5803b-ad15-4474-aed6-92e43ea253ea" target="_blank"><i class="fa fa-question-circle"></i> 如何获取应用公钥?</a></div> | ||
346 | + </div> | ||
347 | + <div class="col-sm-4"></div> | ||
348 | + </div> | ||
349 | + </td> | ||
350 | + </tr> | ||
351 | + <tr class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert"> | ||
352 | + <td>支付宝根证书路径(alipay_root_cert)</td> | ||
353 | + <td> | ||
354 | + <div class="row"> | ||
355 | + <div class="col-sm-8 col-xs-12"> | ||
356 | + <div class="input-group"> | ||
357 | + <input id="c-alipay_root_cert" class="form-control" size="50" name="row[alipay][alipay_root_cert]" type="text" value="{$item.value.alipay_root_cert|default=''|htmlentities}"> | ||
358 | + <div class="input-group-addon no-border no-padding"> | ||
359 | + <span><button type="button" id="faupload-alipay_root_cert" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"alipay_root_cert"}' data-mimetype="crt" data-input-id="c-alipay_root_cert" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> | ||
360 | + </div> | ||
361 | + <span class="msg-box n-right" for="c-alipay_root_cert"></span> | ||
362 | + </div> | ||
363 | + <div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/helpcenter/271/201602474998" target="_blank"><i class="fa fa-question-circle"></i> 如何获取支付宝根证书?</a></div> | ||
364 | + </div> | ||
365 | + <div class="col-sm-4"></div> | ||
366 | + </div> | ||
367 | + </td> | ||
368 | + </tr> | ||
369 | + | ||
370 | + <tr> | ||
371 | + <td>记录日志</td> | ||
372 | + <td> | ||
373 | + <div class="row"> | ||
374 | + <div class="col-sm-8 col-xs-12"> | ||
375 | + {:Form::radios('row[alipay][log]',['1'=>'开启','0'=>'关闭'],$item.value.log)} | ||
376 | + </div> | ||
377 | + <div class="col-sm-4"></div> | ||
378 | + </div> | ||
379 | + </td> | ||
380 | + </tr> | ||
381 | + | ||
382 | + <tr> | ||
383 | + <td>PC端使用扫码支付</td> | ||
384 | + <td> | ||
385 | + <div class="row"> | ||
386 | + <div class="col-sm-8 col-xs-12"> | ||
387 | + {:Form::radios('row[alipay][scanpay]',['1'=>'开启','0'=>'关闭'],$item.value.scanpay??0)} | ||
388 | + </div> | ||
389 | + <div class="col-sm-4"></div> | ||
390 | + </div> | ||
391 | + </td> | ||
392 | + </tr> | ||
393 | + </tbody> | ||
394 | + </table> | ||
395 | + </div> | ||
396 | + {/if} | ||
397 | + {/foreach} | ||
398 | + <div class="form-group layer-footer"> | ||
399 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
400 | + <div class="col-xs-12 col-sm-8"> | ||
401 | + <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button> | ||
402 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
403 | + </div> | ||
404 | + </div> | ||
405 | + </div> | ||
406 | + </div> | ||
407 | + </div> | ||
408 | +</form> | ||
409 | +<script> | ||
410 | + require.callback = function () { | ||
411 | + define('backend/addon', ['backend', 'form'], function (Backend, Form) { | ||
412 | + var Controller = { | ||
413 | + config: function () { | ||
414 | + $(document).on("click", ".nav-group li a[data-toggle='tab']", function () { | ||
415 | + if ($(this).attr("href") == "#all") { | ||
416 | + $(".tab-pane").addClass("active in"); | ||
417 | + } | ||
418 | + | ||
419 | + return; | ||
420 | + }); | ||
421 | + | ||
422 | + $(document).on("click", "input[name='row[wechat][mode]']", function () { | ||
423 | + $("#wechat [data-type]").addClass("hidden"); | ||
424 | + $("#wechat [data-type='" + $(this).val() + "']").removeClass("hidden"); | ||
425 | + }); | ||
426 | + $(document).on("click", "input[name='row[alipay][mode]']", function () { | ||
427 | + $("#alipay [data-mode]").addClass("hidden"); | ||
428 | + $("#alipay [data-mode='" + $(this).val() + "']").removeClass("hidden"); | ||
429 | + }); | ||
430 | + $(document).on("click", "input[name='row[alipay][signtype]']", function () { | ||
431 | + $("#alipay [data-signtype]").addClass("hidden"); | ||
432 | + $("#alipay [data-signtype='" + $(this).val() + "']").removeClass("hidden"); | ||
433 | + }); | ||
434 | + | ||
435 | + Form.api.bindevent($("form[role=form]")); | ||
436 | + } | ||
437 | + }; | ||
438 | + return Controller; | ||
439 | + }); | ||
440 | + }; | ||
441 | +</script> |
addons/epay/config.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + [ | ||
5 | + 'name' => 'version', | ||
6 | + 'title' => 'API版本(请勿修改该值)', | ||
7 | + 'type' => 'radio', | ||
8 | + 'content' => [], | ||
9 | + 'value' => 'v2', | ||
10 | + 'rule' => '', | ||
11 | + 'msg' => '', | ||
12 | + 'tip' => 'V2版本只支持微信支付V2密钥,V3版本只支持微信支付V3密钥,请勿修改该值!!!', | ||
13 | + 'ok' => '', | ||
14 | + 'extend' => '', | ||
15 | + ], | ||
16 | + [ | ||
17 | + 'name' => 'wechat', | ||
18 | + 'title' => '微信', | ||
19 | + 'type' => 'array', | ||
20 | + 'content' => [], | ||
21 | + 'value' => [ | ||
22 | + 'appid' => '', | ||
23 | + 'app_id' => '', | ||
24 | + 'app_secret' => '', | ||
25 | + 'miniapp_id' => '', | ||
26 | + 'mch_id' => '', | ||
27 | + 'key' => '', | ||
28 | + 'key_v3' => '', | ||
29 | + 'mode' => 'normal', | ||
30 | + 'sub_mch_id' => '', | ||
31 | + 'sub_appid' => '', | ||
32 | + 'sub_app_id' => '', | ||
33 | + 'sub_miniapp_id' => '', | ||
34 | + 'notify_url' => '', | ||
35 | + 'cert_client' => '/addons/epay/certs/apiclient_cert.pem', | ||
36 | + 'cert_key' => '/addons/epay/certs/apiclient_key.pem', | ||
37 | + 'log' => '1', | ||
38 | + ], | ||
39 | + 'rule' => 'required', | ||
40 | + 'msg' => '', | ||
41 | + 'tip' => '微信参数配置', | ||
42 | + 'ok' => '', | ||
43 | + 'extend' => '', | ||
44 | + ], | ||
45 | + [ | ||
46 | + 'name' => 'alipay', | ||
47 | + 'title' => '支付宝', | ||
48 | + 'type' => 'array', | ||
49 | + 'content' => [], | ||
50 | + 'value' => [ | ||
51 | + 'app_id' => '', | ||
52 | + 'mode' => 'normal', | ||
53 | + 'notify_url' => '/addons/epay/api/notifyx/type/alipay', | ||
54 | + 'return_url' => '/addons/epay/api/returnx/type/alipay', | ||
55 | + 'private_key' => '', | ||
56 | + 'signtype' => 'cert', | ||
57 | + 'pid' => '', | ||
58 | + 'ali_public_key' => '', | ||
59 | + 'app_cert_public_key' => '', | ||
60 | + 'alipay_root_cert' => '', | ||
61 | + 'log' => '1', | ||
62 | + 'scanpay' => '0', | ||
63 | + ], | ||
64 | + 'rule' => 'required', | ||
65 | + 'msg' => '', | ||
66 | + 'tip' => '支付宝参数配置', | ||
67 | + 'ok' => '', | ||
68 | + 'extend' => '', | ||
69 | + ] | ||
70 | +]; |
addons/epay/controller/Api.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\controller; | ||
4 | + | ||
5 | +use addons\epay\library\Service; | ||
6 | +use addons\epay\library\Wechat; | ||
7 | +use addons\third\model\Third; | ||
8 | +use app\common\library\Auth; | ||
9 | +use Exception; | ||
10 | +use think\addons\Controller; | ||
11 | +use think\Response; | ||
12 | +use think\Session; | ||
13 | +use Yansongda\Pay\Exceptions\GatewayException; | ||
14 | +use Yansongda\Pay\Pay; | ||
15 | + | ||
16 | +/** | ||
17 | + * API接口控制器 | ||
18 | + * | ||
19 | + * @package addons\epay\controller | ||
20 | + */ | ||
21 | +class Api extends Controller | ||
22 | +{ | ||
23 | + | ||
24 | + protected $layout = 'default'; | ||
25 | + protected $config = []; | ||
26 | + | ||
27 | + /** | ||
28 | + * 默认方法 | ||
29 | + */ | ||
30 | + public function index() | ||
31 | + { | ||
32 | + return; | ||
33 | + } | ||
34 | + | ||
35 | + /** | ||
36 | + * 外部提交 | ||
37 | + */ | ||
38 | + public function submit() | ||
39 | + { | ||
40 | + $this->request->filter('trim'); | ||
41 | + $out_trade_no = $this->request->request("out_trade_no"); | ||
42 | + $title = $this->request->request("title"); | ||
43 | + $amount = $this->request->request('amount'); | ||
44 | + $type = $this->request->request('type', $this->request->request('paytype')); | ||
45 | + $method = $this->request->request('method', 'web'); | ||
46 | + $openid = $this->request->request('openid', ''); | ||
47 | + $auth_code = $this->request->request('auth_code', ''); | ||
48 | + $notifyurl = $this->request->request('notifyurl', ''); | ||
49 | + $returnurl = $this->request->request('returnurl', ''); | ||
50 | + | ||
51 | + if (!$amount || $amount < 0) { | ||
52 | + $this->error("支付金额必须大于0"); | ||
53 | + } | ||
54 | + | ||
55 | + if (!$type || !in_array($type, ['alipay', 'wechat'])) { | ||
56 | + $this->error("支付类型错误"); | ||
57 | + } | ||
58 | + | ||
59 | + $params = [ | ||
60 | + 'type' => $type, | ||
61 | + 'out_trade_no' => $out_trade_no, | ||
62 | + 'title' => $title, | ||
63 | + 'amount' => $amount, | ||
64 | + 'method' => $method, | ||
65 | + 'openid' => $openid, | ||
66 | + 'auth_code' => $auth_code, | ||
67 | + 'notifyurl' => $notifyurl, | ||
68 | + 'returnurl' => $returnurl, | ||
69 | + ]; | ||
70 | + return Service::submitOrder($params); | ||
71 | + } | ||
72 | + | ||
73 | + /** | ||
74 | + * 微信支付(公众号支付&PC扫码支付) | ||
75 | + */ | ||
76 | + public function wechat() | ||
77 | + { | ||
78 | + $config = Service::getConfig('wechat'); | ||
79 | + | ||
80 | + $isWechat = stripos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false; | ||
81 | + $isMobile = $this->request->isMobile(); | ||
82 | + $this->view->assign("isWechat", $isWechat); | ||
83 | + $this->view->assign("isMobile", $isMobile); | ||
84 | + | ||
85 | + //发起PC支付(Scan支付)(PC扫码模式) | ||
86 | + if ($this->request->isAjax()) { | ||
87 | + $pay = Pay::wechat($config); | ||
88 | + $orderid = $this->request->post("orderid"); | ||
89 | + try { | ||
90 | + $result = Service::isVersionV3() ? $pay->find(['out_trade_no' => $orderid]) : $pay->find($orderid, 'scan'); | ||
91 | + $this->success("", "", ['status' => $result['trade_state'] ?? 'NOTPAY']); | ||
92 | + } catch (GatewayException $e) { | ||
93 | + $this->error("查询失败(1001)"); | ||
94 | + } | ||
95 | + } | ||
96 | + | ||
97 | + $orderData = Session::get("wechatorderdata"); | ||
98 | + if (!$orderData) { | ||
99 | + $this->error("请求参数错误"); | ||
100 | + } | ||
101 | + if ($isWechat && $isMobile) { | ||
102 | + //发起公众号(jsapi支付),openid必须 | ||
103 | + | ||
104 | + //如果没有openid,则自动去获取openid | ||
105 | + if (!isset($orderData['openid']) || !$orderData['openid']) { | ||
106 | + $orderData['openid'] = Service::getOpenid(); | ||
107 | + } | ||
108 | + | ||
109 | + $orderData['method'] = 'mp'; | ||
110 | + $type = 'jsapi'; | ||
111 | + $payData = Service::submitOrder($orderData); | ||
112 | + if (!isset($payData['paySign'])) { | ||
113 | + $this->error("创建订单失败,请返回重试", ""); | ||
114 | + } | ||
115 | + } else { | ||
116 | + $orderData['method'] = 'scan'; | ||
117 | + $type = 'pc'; | ||
118 | + $payData = Service::submitOrder($orderData); | ||
119 | + if (!isset($payData['code_url'])) { | ||
120 | + $this->error("创建订单失败,请返回重试", ""); | ||
121 | + } | ||
122 | + } | ||
123 | + $this->view->assign("orderData", $orderData); | ||
124 | + $this->view->assign("payData", $payData); | ||
125 | + $this->view->assign("type", $type); | ||
126 | + | ||
127 | + $this->view->assign("title", "微信支付"); | ||
128 | + return $this->view->fetch(); | ||
129 | + } | ||
130 | + | ||
131 | + /** | ||
132 | + * 支付宝支付(PC扫码支付) | ||
133 | + */ | ||
134 | + public function alipay() | ||
135 | + { | ||
136 | + $config = Service::getConfig('alipay'); | ||
137 | + | ||
138 | + $isWechat = stripos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false; | ||
139 | + $isMobile = $this->request->isMobile(); | ||
140 | + $this->view->assign("isWechat", $isWechat); | ||
141 | + $this->view->assign("isMobile", $isMobile); | ||
142 | + | ||
143 | + if ($this->request->isAjax()) { | ||
144 | + $orderid = $this->request->post("orderid"); | ||
145 | + $pay = Pay::alipay($config); | ||
146 | + try { | ||
147 | + $result = $pay->find(['out_biz_no' => $orderid]); | ||
148 | + if ($result['code'] == '10000' && $result['trade_status'] == 'TRADE_SUCCESS') { | ||
149 | + $this->success("", "", ['status' => $result['trade_status']]); | ||
150 | + } else { | ||
151 | + $this->error("查询失败"); | ||
152 | + } | ||
153 | + } catch (GatewayException $e) { | ||
154 | + $this->error("查询失败(1001)"); | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + //发起PC支付(Scan支付)(PC扫码模式) | ||
159 | + $orderData = Session::get("alipayorderdata"); | ||
160 | + if (!$orderData) { | ||
161 | + $this->error("请求参数错误"); | ||
162 | + } | ||
163 | + | ||
164 | + $orderData['method'] = 'scan'; | ||
165 | + $payData = Service::submitOrder($orderData); | ||
166 | + if (!isset($payData['qr_code'])) { | ||
167 | + $this->error("创建订单失败,请返回重试"); | ||
168 | + } | ||
169 | + | ||
170 | + $type = 'pc'; | ||
171 | + $this->view->assign("orderData", $orderData); | ||
172 | + $this->view->assign("payData", $payData); | ||
173 | + $this->view->assign("type", $type); | ||
174 | + $this->view->assign("title", "支付宝支付"); | ||
175 | + return $this->view->fetch(); | ||
176 | + } | ||
177 | + | ||
178 | + /** | ||
179 | + * 支付成功回调 | ||
180 | + */ | ||
181 | + public function notifyx() | ||
182 | + { | ||
183 | + $paytype = $this->request->param('paytype'); | ||
184 | + $pay = Service::checkNotify($paytype); | ||
185 | + if (!$pay) { | ||
186 | + return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']); | ||
187 | + } | ||
188 | + | ||
189 | + // 获取回调数据,V3和V2的回调接收不同 | ||
190 | + $data = Service::isVersionV3() ? $pay->callback() : $pay->verify(); | ||
191 | + | ||
192 | + try { | ||
193 | + //微信支付V3返回和V2不同 | ||
194 | + if (Service::isVersionV3() && $paytype === 'wechat') { | ||
195 | + $data = $data['resource']['ciphertext']; | ||
196 | + $data['total_fee'] = $data['amount']['total']; | ||
197 | + } | ||
198 | + | ||
199 | + \think\Log::record($data); | ||
200 | + //获取支付金额、订单号 | ||
201 | + $payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100; | ||
202 | + $out_trade_no = $data['out_trade_no']; | ||
203 | + | ||
204 | + \think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}"); | ||
205 | + | ||
206 | + //你可以在此编写订单逻辑 | ||
207 | + } catch (Exception $e) { | ||
208 | + \think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error"); | ||
209 | + } | ||
210 | + | ||
211 | + //下面这句必须要执行,且在此之前不能有任何输出 | ||
212 | + if (Service::isVersionV3()) { | ||
213 | + return $pay->success()->getBody()->getContents(); | ||
214 | + } else { | ||
215 | + return $pay->success()->send(); | ||
216 | + } | ||
217 | + } | ||
218 | + | ||
219 | + /** | ||
220 | + * 支付成功返回 | ||
221 | + */ | ||
222 | + public function returnx() | ||
223 | + { | ||
224 | + $paytype = $this->request->param('paytype'); | ||
225 | + if (Service::checkReturn($paytype)) { | ||
226 | + echo '签名错误'; | ||
227 | + return; | ||
228 | + } | ||
229 | + | ||
230 | + //你可以在这里定义你的提示信息,但切记不可在此编写逻辑 | ||
231 | + $this->success("恭喜你!支付成功!", addon_url("epay/index/index")); | ||
232 | + } | ||
233 | + | ||
234 | +} |
addons/epay/controller/Index.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\controller; | ||
4 | + | ||
5 | +use addons\epay\library\Service; | ||
6 | +use fast\Random; | ||
7 | +use think\addons\Controller; | ||
8 | +use Exception; | ||
9 | + | ||
10 | +/** | ||
11 | + * 微信支付宝整合插件首页 | ||
12 | + * | ||
13 | + * 此控制器仅用于开发展示说明和测试,请自行添加一个新的控制器进行处理返回和回调事件,同时删除此控制器文件 | ||
14 | + * | ||
15 | + * Class Index | ||
16 | + * @package addons\epay\controller | ||
17 | + */ | ||
18 | +class Index extends Controller | ||
19 | +{ | ||
20 | + protected $layout = 'default'; | ||
21 | + | ||
22 | + protected $config = []; | ||
23 | + | ||
24 | + public function _initialize() | ||
25 | + { | ||
26 | + parent::_initialize(); | ||
27 | + if (!config("app_debug")) { | ||
28 | + $this->error("仅在开发环境下查看"); | ||
29 | + } | ||
30 | + } | ||
31 | + | ||
32 | + public function index() | ||
33 | + { | ||
34 | + $this->view->assign("title", "微信支付宝整合"); | ||
35 | + return $this->view->fetch(); | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * 体验,仅供开发测试 | ||
40 | + */ | ||
41 | + public function experience() | ||
42 | + { | ||
43 | + $amount = $this->request->post('amount'); | ||
44 | + $type = $this->request->post('type'); | ||
45 | + $method = $this->request->post('method'); | ||
46 | + $openid = $this->request->post('openid', ""); | ||
47 | + | ||
48 | + if (!$amount || $amount < 0) { | ||
49 | + $this->error("支付金额必须大于0"); | ||
50 | + } | ||
51 | + | ||
52 | + if (!$type || !in_array($type, ['alipay', 'wechat'])) { | ||
53 | + $this->error("支付类型不能为空"); | ||
54 | + } | ||
55 | + | ||
56 | + if (in_array($method, ['miniapp', 'mp']) && !$openid) { | ||
57 | + $this->error("openid不能为空"); | ||
58 | + } | ||
59 | + | ||
60 | + //订单号 | ||
61 | + $out_trade_no = date("YmdHis") . mt_rand(100000, 999999); | ||
62 | + | ||
63 | + //订单标题 | ||
64 | + $title = '测试订单'; | ||
65 | + | ||
66 | + //回调链接 | ||
67 | + $notifyurl = $this->request->root(true) . '/addons/epay/index/notifyx/paytype/' . $type; | ||
68 | + $returnurl = $this->request->root(true) . '/addons/epay/index/returnx/paytype/' . $type . '/out_trade_no/' . $out_trade_no; | ||
69 | + | ||
70 | + $response = Service::submitOrder($amount, $out_trade_no, $type, $title, $notifyurl, $returnurl, $method, $openid); | ||
71 | + | ||
72 | + return $response; | ||
73 | + } | ||
74 | + | ||
75 | + /** | ||
76 | + * 支付成功,仅供开发测试 | ||
77 | + */ | ||
78 | + public function notifyx() | ||
79 | + { | ||
80 | + $paytype = $this->request->param('paytype'); | ||
81 | + $pay = Service::checkNotify($paytype); | ||
82 | + if (!$pay) { | ||
83 | + return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']); | ||
84 | + } | ||
85 | + | ||
86 | + // 获取回调数据,V3和V2的回调接收不同 | ||
87 | + $data = Service::isVersionV3() ? $pay->callback() : $pay->verify(); | ||
88 | + | ||
89 | + try { | ||
90 | + //微信支付V3返回和V2不同 | ||
91 | + if (Service::isVersionV3() && $paytype === 'wechat') { | ||
92 | + $data = $data['resource']['ciphertext']; | ||
93 | + $data['total_fee'] = $data['amount']['total']; | ||
94 | + } | ||
95 | + | ||
96 | + \think\Log::record($data); | ||
97 | + //获取支付金额、订单号 | ||
98 | + $payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100; | ||
99 | + $out_trade_no = $data['out_trade_no']; | ||
100 | + | ||
101 | + \think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}"); | ||
102 | + | ||
103 | + //你可以在此编写订单逻辑 | ||
104 | + } catch (Exception $e) { | ||
105 | + \think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error"); | ||
106 | + } | ||
107 | + | ||
108 | + //下面这句必须要执行,且在此之前不能有任何输出 | ||
109 | + if (Service::isVersionV3()) { | ||
110 | + return $pay->success()->getBody()->getContents(); | ||
111 | + } else { | ||
112 | + return $pay->success()->send(); | ||
113 | + } | ||
114 | + } | ||
115 | + | ||
116 | + /** | ||
117 | + * 支付返回,仅供开发测试 | ||
118 | + */ | ||
119 | + public function returnx() | ||
120 | + { | ||
121 | + $paytype = $this->request->param('paytype'); | ||
122 | + $out_trade_no = $this->request->param('out_trade_no'); | ||
123 | + $pay = Service::checkReturn($paytype); | ||
124 | + if (!$pay) { | ||
125 | + $this->error('签名错误', ''); | ||
126 | + } | ||
127 | + | ||
128 | + //你可以在这里定义你的提示信息,但切记不可在此编写逻辑 | ||
129 | + $this->success("请返回网站查看支付结果", addon_url("epay/index/index")); | ||
130 | + } | ||
131 | +} |
addons/epay/info.ini
0 → 100644
addons/epay/library/Collection.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\library; | ||
4 | + | ||
5 | +class Collection extends \Yansongda\Supports\Collection | ||
6 | +{ | ||
7 | + | ||
8 | + /** | ||
9 | + * 创建 Collection 实例 | ||
10 | + * @access public | ||
11 | + * @param array $items 数据 | ||
12 | + * @return static | ||
13 | + */ | ||
14 | + public static function make($items = []) | ||
15 | + { | ||
16 | + return new static($items); | ||
17 | + } | ||
18 | +} |
addons/epay/library/OrderException.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\library; | ||
4 | + | ||
5 | +use think\Exception; | ||
6 | + | ||
7 | +class OrderException extends Exception | ||
8 | +{ | ||
9 | + public function __construct($message = "", $code = 0, $data = []) | ||
10 | + { | ||
11 | + $this->message = $message; | ||
12 | + $this->code = $code; | ||
13 | + $this->data = $data; | ||
14 | + } | ||
15 | + | ||
16 | +} |
addons/epay/library/RedirectResponse.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\library; | ||
4 | + | ||
5 | +class RedirectResponse extends \Symfony\Component\HttpFoundation\RedirectResponse implements \JsonSerializable, \Serializable | ||
6 | +{ | ||
7 | + public function __toString() | ||
8 | + { | ||
9 | + return $this->getContent(); | ||
10 | + } | ||
11 | + | ||
12 | + public function setTargetUrl($url) | ||
13 | + { | ||
14 | + if ('' === ($url ?? '')) { | ||
15 | + throw new \InvalidArgumentException('无法跳转到空页面'); | ||
16 | + } | ||
17 | + | ||
18 | + $this->targetUrl = $url; | ||
19 | + | ||
20 | + $this->setContent( | ||
21 | + sprintf('<!DOCTYPE html> | ||
22 | +<html> | ||
23 | + <head> | ||
24 | + <meta charset="UTF-8" /> | ||
25 | + <meta http-equiv="refresh" content="0;url=\'%1$s\'" /> | ||
26 | + | ||
27 | + <title>正在跳转支付 %1$s</title> | ||
28 | + </head> | ||
29 | + <body> | ||
30 | + <div id="redirect" style="display:none;">正在跳转支付 <a href="%1$s">%1$s</a></div> | ||
31 | + <script type="text/javascript"> | ||
32 | + setTimeout(function(){ | ||
33 | + document.getElementById("redirect").style.display = "block"; | ||
34 | + }, 1000); | ||
35 | + </script> | ||
36 | + </body> | ||
37 | +</html>', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8'))); | ||
38 | + | ||
39 | + $this->headers->set('Location', $url); | ||
40 | + | ||
41 | + return $this; | ||
42 | + } | ||
43 | + | ||
44 | + public function jsonSerialize() | ||
45 | + { | ||
46 | + return $this->getContent(); | ||
47 | + } | ||
48 | + | ||
49 | + public function serialize() | ||
50 | + { | ||
51 | + return serialize($this->content); | ||
52 | + } | ||
53 | + | ||
54 | + public function unserialize($serialized) | ||
55 | + { | ||
56 | + return $this->content = unserialize($serialized); | ||
57 | + } | ||
58 | +} |
addons/epay/library/Response.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\library; | ||
4 | + | ||
5 | +class Response extends \Symfony\Component\HttpFoundation\Response implements \JsonSerializable, \Serializable | ||
6 | +{ | ||
7 | + public function __toString() | ||
8 | + { | ||
9 | + return $this->getContent(); | ||
10 | + } | ||
11 | + | ||
12 | + public function jsonSerialize() | ||
13 | + { | ||
14 | + return $this->getContent(); | ||
15 | + } | ||
16 | + | ||
17 | + public function serialize() | ||
18 | + { | ||
19 | + return serialize($this->content); | ||
20 | + } | ||
21 | + | ||
22 | + public function unserialize($serialized) | ||
23 | + { | ||
24 | + return $this->content = unserialize($serialized); | ||
25 | + } | ||
26 | +} |
addons/epay/library/Service.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\library; | ||
4 | + | ||
5 | +use addons\third\model\Third; | ||
6 | +use app\common\library\Auth; | ||
7 | +use Exception; | ||
8 | +use think\Hook; | ||
9 | +use think\Session; | ||
10 | +use Yansongda\Pay\Pay; | ||
11 | +use Yansongda\Supports\Str; | ||
12 | + | ||
13 | +/** | ||
14 | + * 订单服务类 | ||
15 | + * | ||
16 | + * @package addons\epay\library | ||
17 | + */ | ||
18 | +class Service | ||
19 | +{ | ||
20 | + | ||
21 | + public const SDK_VERSION_V2 = 'v2'; | ||
22 | + | ||
23 | + public const SDK_VERSION_V3 = 'v3'; | ||
24 | + | ||
25 | + /** | ||
26 | + * 提交订单 | ||
27 | + * @param array|float $amount 订单金额 | ||
28 | + * @param string $orderid 订单号 | ||
29 | + * @param string $type 支付类型,可选alipay或wechat | ||
30 | + * @param string $title 订单标题 | ||
31 | + * @param string $notifyurl 通知回调URL | ||
32 | + * @param string $returnurl 跳转返回URL | ||
33 | + * @param string $method 支付方法 | ||
34 | + * @param string $openid Openid | ||
35 | + * @param array $custom 自定义微信支付宝相关配置 | ||
36 | + * @return Response|RedirectResponse|Collection | ||
37 | + * @throws Exception | ||
38 | + */ | ||
39 | + public static function submitOrder($amount, $orderid = null, $type = null, $title = null, $notifyurl = null, $returnurl = null, $method = null, $openid = '', $custom = []) | ||
40 | + { | ||
41 | + $version = self::getSdkVersion(); | ||
42 | + $request = request(); | ||
43 | + $addonConfig = get_addon_config('epay'); | ||
44 | + | ||
45 | + if (!is_array($amount)) { | ||
46 | + $params = [ | ||
47 | + 'amount' => $amount, | ||
48 | + 'orderid' => $orderid, | ||
49 | + 'type' => $type, | ||
50 | + 'title' => $title, | ||
51 | + 'notifyurl' => $notifyurl, | ||
52 | + 'returnurl' => $returnurl, | ||
53 | + 'method' => $method, | ||
54 | + 'openid' => $openid, | ||
55 | + 'custom' => $custom, | ||
56 | + ]; | ||
57 | + } else { | ||
58 | + $params = $amount; | ||
59 | + } | ||
60 | + $type = isset($params['type']) && in_array($params['type'], ['alipay', 'wechat']) ? $params['type'] : 'wechat'; | ||
61 | + $method = $params['method'] ?? 'web'; | ||
62 | + $orderid = $params['orderid'] ?? date("YmdHis") . mt_rand(100000, 999999); | ||
63 | + $amount = $params['amount'] ?? 1; | ||
64 | + $title = $params['title'] ?? "支付"; | ||
65 | + $auth_code = $params['auth_code'] ?? ''; | ||
66 | + $openid = $params['openid'] ?? ''; | ||
67 | + | ||
68 | + //自定义微信支付宝相关配置 | ||
69 | + $custom = $params['custom'] ?? []; | ||
70 | + | ||
71 | + //未定义则使用默认回调和跳转 | ||
72 | + $notifyurl = !empty($params['notifyurl']) ? $params['notifyurl'] : $request->root(true) . '/addons/epay/index/notifyx/paytype/' . $type; | ||
73 | + $returnurl = !empty($params['returnurl']) ? $params['returnurl'] : $request->root(true) . '/addons/epay/index/returnx/paytype/' . $type . '/out_trade_no/' . $orderid; | ||
74 | + | ||
75 | + $html = ''; | ||
76 | + $config = Service::getConfig($type, array_merge($custom, ['notify_url' => $notifyurl, 'return_url' => $returnurl])); | ||
77 | + | ||
78 | + //判断是否移动端或微信内浏览器 | ||
79 | + $isMobile = $request->isMobile(); | ||
80 | + $isWechat = strpos($request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false; | ||
81 | + | ||
82 | + $result = null; | ||
83 | + if ($type == 'alipay') { | ||
84 | + //如果是PC支付,判断当前环境,进行跳转 | ||
85 | + if ($method == 'web') { | ||
86 | + //如果是微信环境或后台配置PC使用扫码支付 | ||
87 | + if ($isWechat || $addonConfig['alipay']['scanpay']) { | ||
88 | + Session::set("alipayorderdata", $params); | ||
89 | + $url = addon_url('epay/api/alipay', [], true, true); | ||
90 | + return new RedirectResponse($url); | ||
91 | + } elseif ($isMobile) { | ||
92 | + $method = 'wap'; | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + //创建支付对象 | ||
97 | + $pay = Pay::alipay($config); | ||
98 | + $params = [ | ||
99 | + 'out_trade_no' => $orderid,//你的订单号 | ||
100 | + 'total_amount' => $amount,//单位元 | ||
101 | + 'subject' => $title, | ||
102 | + ]; | ||
103 | + | ||
104 | + switch ($method) { | ||
105 | + case 'web': | ||
106 | + //电脑支付 | ||
107 | + $result = $pay->web($params); | ||
108 | + break; | ||
109 | + case 'wap': | ||
110 | + //手机网页支付 | ||
111 | + $result = $pay->wap($params); | ||
112 | + break; | ||
113 | + case 'app': | ||
114 | + //APP支付 | ||
115 | + $result = $pay->app($params); | ||
116 | + break; | ||
117 | + case 'scan': | ||
118 | + //扫码支付 | ||
119 | + $result = $pay->scan($params); | ||
120 | + break; | ||
121 | + case 'pos': | ||
122 | + //刷卡支付必须要有auth_code | ||
123 | + $params['auth_code'] = $auth_code; | ||
124 | + $result = $pay->pos($params); | ||
125 | + break; | ||
126 | + case 'mini': | ||
127 | + case 'miniapp': | ||
128 | + //小程序支付 | ||
129 | + //小程序支付,直接返回字符串 | ||
130 | + //小程序支付必须要有buyer_id,这里使用openid | ||
131 | + $params['buyer_id'] = $openid; | ||
132 | + $result = $pay->mini($params); | ||
133 | + break; | ||
134 | + default: | ||
135 | + } | ||
136 | + } else { | ||
137 | + //如果是PC支付,判断当前环境,进行跳转 | ||
138 | + if ($method == 'web') { | ||
139 | + //如果是移动端,但不是微信环境 | ||
140 | + if ($isMobile && !$isWechat) { | ||
141 | + $method = 'wap'; | ||
142 | + } else { | ||
143 | + Session::set("wechatorderdata", $params); | ||
144 | + $url = addon_url('epay/api/wechat', [], true, true); | ||
145 | + return new RedirectResponse($url); | ||
146 | + } | ||
147 | + } | ||
148 | + | ||
149 | + //单位分 | ||
150 | + $total_fee = function_exists('bcmul') ? bcmul($amount, 100) : $amount * 100; | ||
151 | + $total_fee = (int)$total_fee; | ||
152 | + $ip = $request->ip(); | ||
153 | + //微信服务商模式时需传递sub_openid参数 | ||
154 | + $openidName = $addonConfig['wechat']['mode'] == 'service' ? 'sub_openid' : 'openid'; | ||
155 | + | ||
156 | + //创建支付对象 | ||
157 | + $pay = Pay::wechat($config); | ||
158 | + | ||
159 | + if (self::isVersionV3()) { | ||
160 | + //V3支付 | ||
161 | + $params = [ | ||
162 | + 'out_trade_no' => $orderid, | ||
163 | + 'description' => $title, | ||
164 | + 'amount' => [ | ||
165 | + 'total' => $total_fee, | ||
166 | + ] | ||
167 | + ]; | ||
168 | + switch ($method) { | ||
169 | + case 'mp': | ||
170 | + //公众号支付 | ||
171 | + //公众号支付必须有openid | ||
172 | + $params['payer'] = [$openidName => $openid]; | ||
173 | + $result = $pay->mp($params); | ||
174 | + break; | ||
175 | + case 'wap': | ||
176 | + //手机网页支付,跳转 | ||
177 | + $params['scene_info'] = [ | ||
178 | + 'payer_client_ip' => $ip, | ||
179 | + 'h5_info' => [ | ||
180 | + 'type' => 'Wap', | ||
181 | + ] | ||
182 | + ]; | ||
183 | + $result = $pay->wap($params); | ||
184 | + break; | ||
185 | + case 'app': | ||
186 | + //APP支付,直接返回字符串 | ||
187 | + $result = $pay->app($params); | ||
188 | + break; | ||
189 | + case 'scan': | ||
190 | + //扫码支付,直接返回字符串 | ||
191 | + $result = $pay->scan($params); | ||
192 | + break; | ||
193 | + case 'pos': | ||
194 | + //刷卡支付,直接返回字符串 | ||
195 | + //刷卡支付必须要有auth_code | ||
196 | + $params['auth_code'] = $auth_code; | ||
197 | + $result = $pay->pos($params); | ||
198 | + break; | ||
199 | + case 'mini': | ||
200 | + case 'miniapp': | ||
201 | + //小程序支付,直接返回字符串 | ||
202 | + //小程序支付必须要有openid | ||
203 | + $params['payer'] = [$openidName => $openid]; | ||
204 | + $result = $pay->mini($params); | ||
205 | + break; | ||
206 | + default: | ||
207 | + } | ||
208 | + } else { | ||
209 | + //V2支付 | ||
210 | + $params = [ | ||
211 | + 'out_trade_no' => $orderid, | ||
212 | + 'body' => $title, | ||
213 | + 'total_fee' => $total_fee, | ||
214 | + ]; | ||
215 | + switch ($method) { | ||
216 | + case 'mp': | ||
217 | + //公众号支付 | ||
218 | + //公众号支付必须有openid | ||
219 | + $params[$openidName] = $openid; | ||
220 | + $result = $pay->mp($params); | ||
221 | + break; | ||
222 | + case 'wap': | ||
223 | + //手机网页支付,跳转 | ||
224 | + $params['spbill_create_ip'] = $ip; | ||
225 | + $result = $pay->wap($params); | ||
226 | + break; | ||
227 | + case 'app': | ||
228 | + //APP支付,直接返回字符串 | ||
229 | + $result = $pay->app($params); | ||
230 | + break; | ||
231 | + case 'scan': | ||
232 | + //扫码支付,直接返回字符串 | ||
233 | + $result = $pay->scan($params); | ||
234 | + break; | ||
235 | + case 'pos': | ||
236 | + //刷卡支付,直接返回字符串 | ||
237 | + //刷卡支付必须要有auth_code | ||
238 | + $params['auth_code'] = $auth_code; | ||
239 | + $result = $pay->pos($params); | ||
240 | + break; | ||
241 | + case 'mini': | ||
242 | + case 'miniapp': | ||
243 | + //小程序支付,直接返回字符串 | ||
244 | + //小程序支付必须要有openid | ||
245 | + $params[$openidName] = $openid; | ||
246 | + $result = $pay->miniapp($params); | ||
247 | + break; | ||
248 | + default: | ||
249 | + } | ||
250 | + } | ||
251 | + } | ||
252 | + | ||
253 | + //使用重写的Response类、RedirectResponse、Collection类 | ||
254 | + if ($result instanceof \Symfony\Component\HttpFoundation\RedirectResponse) { | ||
255 | + $result = new RedirectResponse($result->getTargetUrl()); | ||
256 | + } elseif ($result instanceof \Symfony\Component\HttpFoundation\Response) { | ||
257 | + $result = new Response($result->getContent()); | ||
258 | + } elseif ($result instanceof \Yansongda\Supports\Collection) { | ||
259 | + $result = Collection::make($result->all()); | ||
260 | + } elseif ($result instanceof \GuzzleHttp\Psr7\Response) { | ||
261 | + $result = new Response($result->getBody()); | ||
262 | + } | ||
263 | + | ||
264 | + return $result; | ||
265 | + } | ||
266 | + | ||
267 | + /** | ||
268 | + * 验证回调是否成功 | ||
269 | + * @param string $type 支付类型 | ||
270 | + * @param array $custom 自定义配置信息 | ||
271 | + * @return bool|\Yansongda\Pay\Gateways\Alipay|\Yansongda\Pay\Gateways\Wechat|\Yansongda\Pay\Provider\Wechat|\Yansongda\Pay\Provider\Alipay | ||
272 | + */ | ||
273 | + public static function checkNotify($type, $custom = []) | ||
274 | + { | ||
275 | + $type = strtolower($type); | ||
276 | + if (!in_array($type, ['wechat', 'alipay'])) { | ||
277 | + return false; | ||
278 | + } | ||
279 | + | ||
280 | + $version = self::getSdkVersion(); | ||
281 | + | ||
282 | + try { | ||
283 | + $config = self::getConfig($type, $custom); | ||
284 | + $pay = $type == 'wechat' ? Pay::wechat($config) : Pay::alipay($config); | ||
285 | + | ||
286 | + $data = Service::isVersionV3() ? $pay->callback() : $pay->verify(); | ||
287 | + if ($type == 'alipay') { | ||
288 | + if (in_array($data['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) { | ||
289 | + return $pay; | ||
290 | + } | ||
291 | + } else { | ||
292 | + return $pay; | ||
293 | + } | ||
294 | + } catch (Exception $e) { | ||
295 | + \think\Log::record("回调请求参数解析错误", "error"); | ||
296 | + return false; | ||
297 | + } | ||
298 | + | ||
299 | + return false; | ||
300 | + } | ||
301 | + | ||
302 | + /** | ||
303 | + * 验证返回是否成功,请勿用于判断是否支付成功的逻辑验证 | ||
304 | + * 已弃用 | ||
305 | + * | ||
306 | + * @param string $type 支付类型 | ||
307 | + * @param array $custom 自定义配置信息 | ||
308 | + * @return bool | ||
309 | + * @deprecated 已弃用,请勿用于逻辑验证 | ||
310 | + */ | ||
311 | + public static function checkReturn($type, $custom = []) | ||
312 | + { | ||
313 | + //由于PC及移动端无法获取请求的参数信息,取消return验证,均返回true | ||
314 | + return true; | ||
315 | + } | ||
316 | + | ||
317 | + /** | ||
318 | + * 获取配置 | ||
319 | + * @param string $type 支付类型 | ||
320 | + * @param array $custom 自定义配置,用于覆盖插件默认配置 | ||
321 | + * @return array | ||
322 | + */ | ||
323 | + public static function getConfig($type = 'wechat', $custom = []) | ||
324 | + { | ||
325 | + $addonConfig = get_addon_config('epay'); | ||
326 | + $config = $addonConfig[$type] ?? $addonConfig['wechat']; | ||
327 | + | ||
328 | + // SDK版本 | ||
329 | + $version = self::getSdkVersion(); | ||
330 | + | ||
331 | + if (isset($config['cert_client']) && substr($config['cert_client'], 0, 8) == '/addons/') { | ||
332 | + $config['cert_client'] = ROOT_PATH . str_replace('/', DS, substr($config['cert_client'], 1)); | ||
333 | + } | ||
334 | + if (isset($config['cert_key']) && substr($config['cert_key'], 0, 8) == '/addons/') { | ||
335 | + $config['cert_key'] = ROOT_PATH . str_replace('/', DS, substr($config['cert_key'], 1)); | ||
336 | + } | ||
337 | + if (isset($config['app_cert_public_key']) && substr($config['app_cert_public_key'], 0, 8) == '/addons/') { | ||
338 | + $config['app_cert_public_key'] = ROOT_PATH . str_replace('/', DS, substr($config['app_cert_public_key'], 1)); | ||
339 | + } | ||
340 | + if (isset($config['alipay_root_cert']) && substr($config['alipay_root_cert'], 0, 8) == '/addons/') { | ||
341 | + $config['alipay_root_cert'] = ROOT_PATH . str_replace('/', DS, substr($config['alipay_root_cert'], 1)); | ||
342 | + } | ||
343 | + if (isset($config['ali_public_key']) && (Str::endsWith($config['ali_public_key'], '.crt') || Str::endsWith($config['ali_public_key'], '.pem'))) { | ||
344 | + $config['ali_public_key'] = ROOT_PATH . str_replace('/', DS, substr($config['ali_public_key'], 1)); | ||
345 | + } | ||
346 | + | ||
347 | + // V3支付 | ||
348 | + if (self::isVersionV3()) { | ||
349 | + if ($type == 'wechat') { | ||
350 | + $config['app_id'] = $config['appid'] ?? ''; | ||
351 | + $config['mp_app_id'] = $config['app_id'] ?? ''; | ||
352 | + $config['mini_app_id'] = $config['miniapp_id'] ?? ''; | ||
353 | + $config['combine_mch_id'] = $config['combine_mch_id'] ?? ''; | ||
354 | + $config['mch_secret_key'] = $config['key_v3'] ?? ''; | ||
355 | + $config['mch_secret_cert'] = $config['cert_key']; | ||
356 | + $config['mch_public_cert_path'] = $config['cert_client']; | ||
357 | + | ||
358 | + $config['sub_mp_app_id'] = $config['sub_appid'] ?? ''; | ||
359 | + $config['sub_app_id'] = $config['sub_app_id'] ?? ''; | ||
360 | + $config['sub_mini_app_id'] = $config['sub_miniapp_id'] ?? ''; | ||
361 | + $config['sub_mch_id'] = $config['sub_mch_id'] ?? ''; | ||
362 | + } elseif ($type == 'alipay') { | ||
363 | + $config['app_secret_cert'] = $config['private_key'] ?? ''; | ||
364 | + $config['app_public_cert_path'] = $config['app_cert_public_key'] ?? ''; | ||
365 | + $config['alipay_public_cert_path'] = $config['ali_public_key'] ?? ''; | ||
366 | + $config['alipay_root_cert_path'] = $config['alipay_root_cert'] ?? ''; | ||
367 | + $config['service_provider_id'] = $config['pid'] ?? ''; | ||
368 | + } | ||
369 | + $modeArr = ['normal' => 0, 'dev' => 1, 'service' => 2]; | ||
370 | + $config['mode'] = $modeArr[$config['mode']] ?? 0; | ||
371 | + } | ||
372 | + | ||
373 | + // 日志 | ||
374 | + if ($config['log']) { | ||
375 | + $config['log'] = [ | ||
376 | + 'enable' => true, | ||
377 | + 'file' => LOG_PATH . 'epaylogs' . DS . $type . '-' . date("Y-m-d") . '.log', | ||
378 | + 'level' => 'debug' | ||
379 | + ]; | ||
380 | + } else { | ||
381 | + $config['log'] = [ | ||
382 | + 'enable' => false, | ||
383 | + ]; | ||
384 | + } | ||
385 | + | ||
386 | + // GuzzleHttp配置,可选 | ||
387 | + $config['http'] = [ | ||
388 | + 'timeout' => 10, | ||
389 | + 'connect_timeout' => 10, | ||
390 | + // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html) | ||
391 | + ]; | ||
392 | + | ||
393 | + $config['notify_url'] = empty($config['notify_url']) ? addon_url('epay/api/notifyx', [], false) . '/type/' . $type : $config['notify_url']; | ||
394 | + $config['notify_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['notify_url']) ? request()->root(true) . $config['notify_url'] : $config['notify_url']; | ||
395 | + $config['return_url'] = empty($config['return_url']) ? addon_url('epay/api/returnx', [], false) . '/type/' . $type : $config['return_url']; | ||
396 | + $config['return_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['return_url']) ? request()->root(true) . $config['return_url'] : $config['return_url']; | ||
397 | + | ||
398 | + //合并自定义配置 | ||
399 | + $config = array_merge($config, $custom); | ||
400 | + | ||
401 | + //v3版本时返回的结构不同 | ||
402 | + if (self::isVersionV3()) { | ||
403 | + $config = [$type => ['default' => $config], 'logger' => $config['log'], 'http' => $config['http'], '_force' => true]; | ||
404 | + | ||
405 | + } | ||
406 | + return $config; | ||
407 | + } | ||
408 | + | ||
409 | + /** | ||
410 | + * 获取微信Openid | ||
411 | + * | ||
412 | + * @param array $custom 自定义配置信息 | ||
413 | + * @return mixed|string | ||
414 | + */ | ||
415 | + public static function getOpenid($custom = []) | ||
416 | + { | ||
417 | + $openid = ''; | ||
418 | + $auth = Auth::instance(); | ||
419 | + if ($auth->isLogin()) { | ||
420 | + $third = get_addon_info('third'); | ||
421 | + if ($third && $third['state']) { | ||
422 | + $thirdInfo = Third::where('user_id', $auth->id)->where('platform', 'wechat')->where('apptype', 'mp')->find(); | ||
423 | + $openid = $thirdInfo ? $thirdInfo['openid'] : ''; | ||
424 | + } | ||
425 | + } | ||
426 | + if (!$openid) { | ||
427 | + $openid = Session::get("openid"); | ||
428 | + | ||
429 | + //如果未传openid,则去读取openid | ||
430 | + if (!$openid) { | ||
431 | + $addonConfig = get_addon_config('epay'); | ||
432 | + $wechat = new Wechat($custom['app_id'] ?? $addonConfig['wechat']['app_id'], $custom['app_secret'] ?? $addonConfig['wechat']['app_secret']); | ||
433 | + $openid = $wechat->getOpenid(); | ||
434 | + } | ||
435 | + } | ||
436 | + return $openid; | ||
437 | + } | ||
438 | + | ||
439 | + /** | ||
440 | + * 获取SDK版本 | ||
441 | + * @return mixed|string | ||
442 | + */ | ||
443 | + public static function getSdkVersion() | ||
444 | + { | ||
445 | + $addonConfig = get_addon_config('epay'); | ||
446 | + return $addonConfig['version'] ?? self::SDK_VERSION_V2; | ||
447 | + } | ||
448 | + | ||
449 | + /** | ||
450 | + * 判断是否V2支付 | ||
451 | + * @return bool | ||
452 | + */ | ||
453 | + public static function isVersionV2() | ||
454 | + { | ||
455 | + return self::getSdkVersion() === self::SDK_VERSION_V2; | ||
456 | + } | ||
457 | + | ||
458 | + /** | ||
459 | + * 判断是否V3支付 | ||
460 | + * @return bool | ||
461 | + */ | ||
462 | + public static function isVersionV3() | ||
463 | + { | ||
464 | + return self::getSdkVersion() === self::SDK_VERSION_V3; | ||
465 | + } | ||
466 | +} |
addons/epay/library/Wechat.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\epay\library; | ||
4 | + | ||
5 | +use fast\Http; | ||
6 | +use think\Cache; | ||
7 | +use think\Session; | ||
8 | + | ||
9 | +/** | ||
10 | + * 微信授权 | ||
11 | + * | ||
12 | + */ | ||
13 | +class Wechat | ||
14 | +{ | ||
15 | + private $app_id = ''; | ||
16 | + private $app_secret = ''; | ||
17 | + private $scope = 'snsapi_userinfo'; | ||
18 | + | ||
19 | + public function __construct($app_id, $app_secret) | ||
20 | + { | ||
21 | + $this->app_id = $app_id; | ||
22 | + $this->app_secret = $app_secret; | ||
23 | + } | ||
24 | + | ||
25 | + /** | ||
26 | + * 获取微信授权链接 | ||
27 | + * | ||
28 | + * @return string | ||
29 | + */ | ||
30 | + public function getAuthorizeUrl() | ||
31 | + { | ||
32 | + $redirect_uri = addon_url('epay/api/wechat', [], true, true); | ||
33 | + $redirect_uri = urlencode($redirect_uri); | ||
34 | + $state = \fast\Random::alnum(); | ||
35 | + Session::set('state', $state); | ||
36 | + return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->app_id}&redirect_uri={$redirect_uri}&response_type=code&scope={$this->scope}&state={$state}#wechat_redirect"; | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * 获取微信openid | ||
41 | + * | ||
42 | + * @return mixed|string | ||
43 | + */ | ||
44 | + public function getOpenid() | ||
45 | + { | ||
46 | + $openid = Session::get('openid'); | ||
47 | + if (!$openid) { | ||
48 | + if (!isset($_GET['code'])) { | ||
49 | + $url = $this->getAuthorizeUrl(); | ||
50 | + | ||
51 | + Header("Location: $url"); | ||
52 | + exit(); | ||
53 | + } else { | ||
54 | + $state = Session::get('state'); | ||
55 | + if ($state == $_GET['state']) { | ||
56 | + $code = $_GET['code']; | ||
57 | + $token = $this->getAccessToken($code); | ||
58 | + if (!isset($token['openid']) && isset($token['errmsg'])) { | ||
59 | + exception($token['errmsg']); | ||
60 | + } | ||
61 | + $openid = $token['openid'] ?? ''; | ||
62 | + if ($openid) { | ||
63 | + Session::set("openid", $openid); | ||
64 | + } | ||
65 | + } | ||
66 | + } | ||
67 | + } | ||
68 | + return $openid; | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * 获取授权token网页授权 | ||
73 | + * | ||
74 | + * @param string $code | ||
75 | + * @return mixed|string | ||
76 | + */ | ||
77 | + public function getAccessToken($code = '') | ||
78 | + { | ||
79 | + $params = [ | ||
80 | + 'appid' => $this->app_id, | ||
81 | + 'secret' => $this->app_secret, | ||
82 | + 'code' => $code, | ||
83 | + 'grant_type' => 'authorization_code' | ||
84 | + ]; | ||
85 | + $ret = Http::sendRequest('https://api.weixin.qq.com/sns/oauth2/access_token', $params, 'GET'); | ||
86 | + if ($ret['ret']) { | ||
87 | + $ar = json_decode($ret['msg'], true); | ||
88 | + return $ar; | ||
89 | + } | ||
90 | + return []; | ||
91 | + } | ||
92 | + | ||
93 | + public function getJsticket($code = '') | ||
94 | + { | ||
95 | + $jsticket = Session::get('jsticket'); | ||
96 | + if (!$jsticket) { | ||
97 | + $token = $this->getAccessToken($code); | ||
98 | + $params = [ | ||
99 | + 'access_token' => 'token', | ||
100 | + 'type' => 'jsapi', | ||
101 | + ]; | ||
102 | + $ret = Http::sendRequest('https://api.weixin.qq.com/cgi-bin/ticket/getticket', $params, 'GET'); | ||
103 | + if ($ret['ret']) { | ||
104 | + $ar = json_decode($ret['msg'], true); | ||
105 | + return $ar; | ||
106 | + } | ||
107 | + } | ||
108 | + return $jsticket; | ||
109 | + } | ||
110 | +} |
addons/epay/library/hyperf/context/LICENSE
0 → 100644
1 | +The MIT License (MIT) | ||
2 | + | ||
3 | +Copyright (c) Hyperf | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | +of this software and associated documentation files (the "Software"), to deal | ||
7 | +in the Software without restriction, including without limitation the rights | ||
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | +copies of the Software, and to permit persons to whom the Software is | ||
10 | +furnished to do so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in all | ||
13 | +copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | +SOFTWARE. |
1 | +{ | ||
2 | + "name": "hyperf/context", | ||
3 | + "description": "A coroutine context library.", | ||
4 | + "license": "MIT", | ||
5 | + "keywords": [ | ||
6 | + "php", | ||
7 | + "swoole", | ||
8 | + "hyperf", | ||
9 | + "context" | ||
10 | + ], | ||
11 | + "homepage": "https://hyperf.io", | ||
12 | + "support": { | ||
13 | + "docs": "https://hyperf.wiki", | ||
14 | + "issues": "https://github.com/hyperf/hyperf/issues", | ||
15 | + "pull-request": "https://github.com/hyperf/hyperf/pulls", | ||
16 | + "source": "https://github.com/hyperf/hyperf" | ||
17 | + }, | ||
18 | + "require": { | ||
19 | + "php": ">=7.2", | ||
20 | + "hyperf/engine": "^1.1" | ||
21 | + }, | ||
22 | + "autoload": { | ||
23 | + "psr-4": { | ||
24 | + "Hyperf\\Context\\": "src/" | ||
25 | + } | ||
26 | + }, | ||
27 | + "autoload-dev": { | ||
28 | + "psr-4": { | ||
29 | + "HyperfTest\\Context\\": "tests/" | ||
30 | + } | ||
31 | + }, | ||
32 | + "config": { | ||
33 | + "sort-packages": true | ||
34 | + }, | ||
35 | + "extra": { | ||
36 | + "branch-alias": { | ||
37 | + "dev-master": "2.2-dev" | ||
38 | + } | ||
39 | + } | ||
40 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Context; | ||
13 | + | ||
14 | +use Hyperf\Engine\Coroutine; | ||
15 | + | ||
16 | +class Context | ||
17 | +{ | ||
18 | + protected static $nonCoContext = []; | ||
19 | + | ||
20 | + public static function set(string $id, $value) | ||
21 | + { | ||
22 | + if (Coroutine::id() > 0) { | ||
23 | + Coroutine::getContextFor()[$id] = $value; | ||
24 | + } else { | ||
25 | + static::$nonCoContext[$id] = $value; | ||
26 | + } | ||
27 | + return $value; | ||
28 | + } | ||
29 | + | ||
30 | + public static function get(string $id, $default = null, $coroutineId = null) | ||
31 | + { | ||
32 | + if (Coroutine::id() > 0) { | ||
33 | + return Coroutine::getContextFor($coroutineId)[$id] ?? $default; | ||
34 | + } | ||
35 | + | ||
36 | + return static::$nonCoContext[$id] ?? $default; | ||
37 | + } | ||
38 | + | ||
39 | + public static function has(string $id, $coroutineId = null) | ||
40 | + { | ||
41 | + if (Coroutine::id() > 0) { | ||
42 | + return isset(Coroutine::getContextFor($coroutineId)[$id]); | ||
43 | + } | ||
44 | + | ||
45 | + return isset(static::$nonCoContext[$id]); | ||
46 | + } | ||
47 | + | ||
48 | + /** | ||
49 | + * Release the context when you are not in coroutine environment. | ||
50 | + */ | ||
51 | + public static function destroy(string $id) | ||
52 | + { | ||
53 | + unset(static::$nonCoContext[$id]); | ||
54 | + } | ||
55 | + | ||
56 | + /** | ||
57 | + * Copy the context from a coroutine to current coroutine. | ||
58 | + * This method will delete the origin values in current coroutine. | ||
59 | + */ | ||
60 | + public static function copy(int $fromCoroutineId, array $keys = []): void | ||
61 | + { | ||
62 | + $from = Coroutine::getContextFor($fromCoroutineId); | ||
63 | + if ($from === null) { | ||
64 | + return; | ||
65 | + } | ||
66 | + | ||
67 | + $current = Coroutine::getContextFor(); | ||
68 | + | ||
69 | + if ($keys) { | ||
70 | + $map = array_intersect_key($from->getArrayCopy(), array_flip($keys)); | ||
71 | + } else { | ||
72 | + $map = $from->getArrayCopy(); | ||
73 | + } | ||
74 | + | ||
75 | + $current->exchangeArray($map); | ||
76 | + } | ||
77 | + | ||
78 | + /** | ||
79 | + * Retrieve the value and override it by closure. | ||
80 | + */ | ||
81 | + public static function override(string $id, \Closure $closure) | ||
82 | + { | ||
83 | + $value = null; | ||
84 | + if (self::has($id)) { | ||
85 | + $value = self::get($id); | ||
86 | + } | ||
87 | + $value = $closure($value); | ||
88 | + self::set($id, $value); | ||
89 | + return $value; | ||
90 | + } | ||
91 | + | ||
92 | + /** | ||
93 | + * Retrieve the value and store it if not exists. | ||
94 | + * @param mixed $value | ||
95 | + */ | ||
96 | + public static function getOrSet(string $id, $value) | ||
97 | + { | ||
98 | + if (! self::has($id)) { | ||
99 | + return self::set($id, value($value)); | ||
100 | + } | ||
101 | + return self::get($id); | ||
102 | + } | ||
103 | + | ||
104 | + public static function getContainer() | ||
105 | + { | ||
106 | + if (Coroutine::id() > 0) { | ||
107 | + return Coroutine::getContextFor(); | ||
108 | + } | ||
109 | + | ||
110 | + return static::$nonCoContext; | ||
111 | + } | ||
112 | +} |
addons/epay/library/hyperf/contract/LICENSE
0 → 100644
1 | +The MIT License (MIT) | ||
2 | + | ||
3 | +Copyright (c) Hyperf | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | +of this software and associated documentation files (the "Software"), to deal | ||
7 | +in the Software without restriction, including without limitation the rights | ||
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | +copies of the Software, and to permit persons to whom the Software is | ||
10 | +furnished to do so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in all | ||
13 | +copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | +SOFTWARE. |
1 | +{ | ||
2 | + "name": "hyperf/contract", | ||
3 | + "description": "The contracts of Hyperf.", | ||
4 | + "license": "MIT", | ||
5 | + "keywords": [ | ||
6 | + "php", | ||
7 | + "swoole", | ||
8 | + "hyperf" | ||
9 | + ], | ||
10 | + "homepage": "https://hyperf.io", | ||
11 | + "support": { | ||
12 | + "docs": "https://hyperf.wiki", | ||
13 | + "issues": "https://github.com/hyperf/hyperf/issues", | ||
14 | + "pull-request": "https://github.com/hyperf/hyperf/pulls", | ||
15 | + "source": "https://github.com/hyperf/hyperf" | ||
16 | + }, | ||
17 | + "require": { | ||
18 | + "php": ">=7.2" | ||
19 | + }, | ||
20 | + "autoload": { | ||
21 | + "psr-4": { | ||
22 | + "Hyperf\\Contract\\": "src/" | ||
23 | + } | ||
24 | + }, | ||
25 | + "config": { | ||
26 | + "sort-packages": true | ||
27 | + }, | ||
28 | + "extra": { | ||
29 | + "branch-alias": { | ||
30 | + "dev-master": "2.2-dev" | ||
31 | + } | ||
32 | + } | ||
33 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface ApplicationInterface | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface Castable | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Get the name of the caster class to use when casting from / to this cast target. | ||
18 | + * | ||
19 | + * @return CastsAttributes|CastsInboundAttributes|string | ||
20 | + */ | ||
21 | + public static function castUsing(); | ||
22 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface CastsAttributes | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Transform the attribute from the underlying model values. | ||
18 | + * | ||
19 | + * @param object $model | ||
20 | + * @param mixed $value | ||
21 | + * @return mixed | ||
22 | + */ | ||
23 | + public function get($model, string $key, $value, array $attributes); | ||
24 | + | ||
25 | + /** | ||
26 | + * Transform the attribute to its underlying model values. | ||
27 | + * | ||
28 | + * @param object $model | ||
29 | + * @param mixed $value | ||
30 | + * @return array|string | ||
31 | + */ | ||
32 | + public function set($model, string $key, $value, array $attributes); | ||
33 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface CastsInboundAttributes | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Transform the attribute to its underlying model values. | ||
18 | + * | ||
19 | + * @param object $model | ||
20 | + * @param mixed $value | ||
21 | + * @return array | ||
22 | + */ | ||
23 | + public function set($model, string $key, $value, array $attributes); | ||
24 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface CompressInterface | ||
15 | +{ | ||
16 | + public function compress(): UnCompressInterface; | ||
17 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface ConfigInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Finds an entry of the container by its identifier and returns it. | ||
18 | + * | ||
19 | + * @param string $key identifier of the entry to look for | ||
20 | + * @param mixed $default default value of the entry when does not found | ||
21 | + * @return mixed entry | ||
22 | + */ | ||
23 | + public function get(string $key, $default = null); | ||
24 | + | ||
25 | + /** | ||
26 | + * Returns true if the container can return an entry for the given identifier. | ||
27 | + * Returns false otherwise. | ||
28 | + * | ||
29 | + * @param string $keys identifier of the entry to look for | ||
30 | + * @return bool | ||
31 | + */ | ||
32 | + public function has(string $keys); | ||
33 | + | ||
34 | + /** | ||
35 | + * Set a value to the container by its identifier. | ||
36 | + * | ||
37 | + * @param string $key identifier of the entry to set | ||
38 | + * @param mixed $value the value that save to container | ||
39 | + */ | ||
40 | + public function set(string $key, $value); | ||
41 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface ConnectionInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Get the real connection from pool. | ||
18 | + */ | ||
19 | + public function getConnection(); | ||
20 | + | ||
21 | + /** | ||
22 | + * Reconnect the connection. | ||
23 | + */ | ||
24 | + public function reconnect(): bool; | ||
25 | + | ||
26 | + /** | ||
27 | + * Check the connection is valid. | ||
28 | + */ | ||
29 | + public function check(): bool; | ||
30 | + | ||
31 | + /** | ||
32 | + * Close the connection. | ||
33 | + */ | ||
34 | + public function close(): bool; | ||
35 | + | ||
36 | + /** | ||
37 | + * Release the connection to pool. | ||
38 | + */ | ||
39 | + public function release(): void; | ||
40 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Psr\Container\ContainerInterface as PsrContainerInterface; | ||
15 | + | ||
16 | +interface ContainerInterface extends PsrContainerInterface | ||
17 | +{ | ||
18 | + /** | ||
19 | + * Build an entry of the container by its name. | ||
20 | + * This method behave like get() except resolves the entry again every time. | ||
21 | + * For example if the entry is a class then a new instance will be created each time. | ||
22 | + * This method makes the container behave like a factory. | ||
23 | + * | ||
24 | + * @param string $name entry name or a class name | ||
25 | + * @param array $parameters Optional parameters to use to build the entry. Use this to force specific parameters | ||
26 | + * to specific values. Parameters not defined in this array will be resolved using | ||
27 | + * the container. | ||
28 | + * @throws InvalidArgumentException the name parameter must be of type string | ||
29 | + * @throws NotFoundException no entry found for the given name | ||
30 | + */ | ||
31 | + public function make(string $name, array $parameters = []); | ||
32 | + | ||
33 | + /** | ||
34 | + * Bind an arbitrary resolved entry to an identifier. | ||
35 | + * Useful for testing 'get'. | ||
36 | + * | ||
37 | + * @param mixed $entry | ||
38 | + */ | ||
39 | + public function set(string $name, $entry); | ||
40 | + | ||
41 | + /** | ||
42 | + * Unbind an arbitrary resolved entry. | ||
43 | + */ | ||
44 | + public function unbind(string $name); | ||
45 | + | ||
46 | + /** | ||
47 | + * Bind an arbitrary definition to an identifier. | ||
48 | + * Useful for testing 'make'. | ||
49 | + * | ||
50 | + * @param array|callable|string $definition | ||
51 | + */ | ||
52 | + public function define(string $name, $definition); | ||
53 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface DispatcherInterface | ||
15 | +{ | ||
16 | + public function dispatch(...$params); | ||
17 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface FrequencyInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Number of hit per time. | ||
18 | + */ | ||
19 | + public function hit(int $number = 1): bool; | ||
20 | + | ||
21 | + /** | ||
22 | + * Hits per second. | ||
23 | + */ | ||
24 | + public function frequency(): float; | ||
25 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface IdGeneratorInterface | ||
15 | +{ | ||
16 | + public function generate(); | ||
17 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface LengthAwarePaginatorInterface extends PaginatorInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Create a range of pagination URLs. | ||
18 | + */ | ||
19 | + public function getUrlRange(int $start, int $end): array; | ||
20 | + | ||
21 | + /** | ||
22 | + * Determine the total number of items in the data store. | ||
23 | + */ | ||
24 | + public function total(): int; | ||
25 | + | ||
26 | + /** | ||
27 | + * Get the page number of the last available page. | ||
28 | + */ | ||
29 | + public function lastPage(): int; | ||
30 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface MiddlewareInitializerInterface | ||
15 | +{ | ||
16 | + public function initCoreMiddleware(string $serverName): void; | ||
17 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface NormalizerInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Normalizes an object into a set of arrays/scalars. | ||
18 | + * | ||
19 | + * @param mixed $object | ||
20 | + * @return null|array|\ArrayObject|bool|float|int|string | ||
21 | + */ | ||
22 | + public function normalize($object); | ||
23 | + | ||
24 | + /** | ||
25 | + * Denormalizes data back into an object of the given class. | ||
26 | + * | ||
27 | + * @param mixed $data Data to restore | ||
28 | + * @param string $class The expected class to instantiate | ||
29 | + * @return mixed|object | ||
30 | + */ | ||
31 | + public function denormalize($data, string $class); | ||
32 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\Http\Response; | ||
15 | +use Swoole\Server; | ||
16 | + | ||
17 | +interface OnCloseInterface | ||
18 | +{ | ||
19 | + /** | ||
20 | + * @param Response|Server $server | ||
21 | + */ | ||
22 | + public function onClose($server, int $fd, int $reactorId): void; | ||
23 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\Http\Request; | ||
15 | +use Swoole\Http\Response; | ||
16 | + | ||
17 | +interface OnHandShakeInterface | ||
18 | +{ | ||
19 | + public function onHandShake(Request $request, Response $response): void; | ||
20 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\Http\Response; | ||
15 | +use Swoole\WebSocket\Frame; | ||
16 | +use Swoole\WebSocket\Server; | ||
17 | + | ||
18 | +interface OnMessageInterface | ||
19 | +{ | ||
20 | + /** | ||
21 | + * @param Response|Server $server | ||
22 | + */ | ||
23 | + public function onMessage($server, Frame $frame): void; | ||
24 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\Http\Request; | ||
15 | +use Swoole\Http\Response; | ||
16 | +use Swoole\WebSocket\Server; | ||
17 | + | ||
18 | +interface OnOpenInterface | ||
19 | +{ | ||
20 | + /** | ||
21 | + * @param Response|Server $server | ||
22 | + */ | ||
23 | + public function onOpen($server, Request $request): void; | ||
24 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\WebSocket\Server; | ||
15 | + | ||
16 | +interface OnPacketInterface | ||
17 | +{ | ||
18 | + /** | ||
19 | + * @param Server $server | ||
20 | + * @param mixed $data | ||
21 | + * @param array $clientInfo | ||
22 | + */ | ||
23 | + public function onPacket($server, $data, $clientInfo): void; | ||
24 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\Coroutine\Server\Connection; | ||
15 | +use Swoole\Server as SwooleServer; | ||
16 | + | ||
17 | +interface OnReceiveInterface | ||
18 | +{ | ||
19 | + /** | ||
20 | + * @param Connection|SwooleServer $server | ||
21 | + */ | ||
22 | + public function onReceive($server, int $fd, int $reactorId, string $data): void; | ||
23 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface OnRequestInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * @param mixed $request swoole request or psr server request | ||
18 | + * @param mixed $response swoole response or swow session | ||
19 | + */ | ||
20 | + public function onRequest($request, $response): void; | ||
21 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface PackerInterface | ||
15 | +{ | ||
16 | + public function pack($data): string; | ||
17 | + | ||
18 | + public function unpack(string $data); | ||
19 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface PaginatorInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Get the URL for a given page. | ||
18 | + */ | ||
19 | + public function url(int $page): string; | ||
20 | + | ||
21 | + /** | ||
22 | + * Add a set of query string values to the paginator. | ||
23 | + * | ||
24 | + * @param array|string $key | ||
25 | + * @return $this | ||
26 | + */ | ||
27 | + public function appends($key, ?string $value = null); | ||
28 | + | ||
29 | + /** | ||
30 | + * Get / set the URL fragment to be appended to URLs. | ||
31 | + * | ||
32 | + * @return $this|string | ||
33 | + */ | ||
34 | + public function fragment(?string $fragment = null); | ||
35 | + | ||
36 | + /** | ||
37 | + * The URL for the next page, or null. | ||
38 | + */ | ||
39 | + public function nextPageUrl(): ?string; | ||
40 | + | ||
41 | + /** | ||
42 | + * Get the URL for the previous page, or null. | ||
43 | + */ | ||
44 | + public function previousPageUrl(): ?string; | ||
45 | + | ||
46 | + /** | ||
47 | + * Get all of the items being paginated. | ||
48 | + */ | ||
49 | + public function items(): array; | ||
50 | + | ||
51 | + /** | ||
52 | + * Get the "index" of the first item being paginated. | ||
53 | + */ | ||
54 | + public function firstItem(): ?int; | ||
55 | + | ||
56 | + /** | ||
57 | + * Get the "index" of the last item being paginated. | ||
58 | + */ | ||
59 | + public function lastItem(): ?int; | ||
60 | + | ||
61 | + /** | ||
62 | + * Determine how many items are being shown per page. | ||
63 | + */ | ||
64 | + public function perPage(): int; | ||
65 | + | ||
66 | + /** | ||
67 | + * Determine the current page being paginated. | ||
68 | + */ | ||
69 | + public function currentPage(): int; | ||
70 | + | ||
71 | + /** | ||
72 | + * Determine if there are enough items to split into multiple pages. | ||
73 | + */ | ||
74 | + public function hasPages(): bool; | ||
75 | + | ||
76 | + /** | ||
77 | + * Determine if there is more items in the data store. | ||
78 | + */ | ||
79 | + public function hasMorePages(): bool; | ||
80 | + | ||
81 | + /** | ||
82 | + * Determine if the list of items is empty or not. | ||
83 | + */ | ||
84 | + public function isEmpty(): bool; | ||
85 | + | ||
86 | + /** | ||
87 | + * Determine if the list of items is not empty. | ||
88 | + */ | ||
89 | + public function isNotEmpty(): bool; | ||
90 | + | ||
91 | + /** | ||
92 | + * Render the paginator using a given view. | ||
93 | + */ | ||
94 | + public function render(?string $view = null, array $data = []): string; | ||
95 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface PoolInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Get a connection from the connection pool. | ||
18 | + */ | ||
19 | + public function get(): ConnectionInterface; | ||
20 | + | ||
21 | + /** | ||
22 | + * Release a connection back to the connection pool. | ||
23 | + */ | ||
24 | + public function release(ConnectionInterface $connection): void; | ||
25 | + | ||
26 | + /** | ||
27 | + * Close and clear the connection pool. | ||
28 | + */ | ||
29 | + public function flush(): void; | ||
30 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface PoolOptionInterface | ||
15 | +{ | ||
16 | + public function getMaxConnections(): int; | ||
17 | + | ||
18 | + public function getMinConnections(): int; | ||
19 | + | ||
20 | + public function getConnectTimeout(): float; | ||
21 | + | ||
22 | + public function getWaitTimeout(): float; | ||
23 | + | ||
24 | + public function getHeartbeat(): float; | ||
25 | + | ||
26 | + public function getMaxIdleTime(): float; | ||
27 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Swoole\Coroutine\Http\Server as CoHttpServer; | ||
15 | +use Swoole\Coroutine\Server as CoServer; | ||
16 | +use Swoole\Server; | ||
17 | + | ||
18 | +interface ProcessInterface | ||
19 | +{ | ||
20 | + /** | ||
21 | + * Create the process object according to process number and bind to server. | ||
22 | + * @param CoHttpServer|CoServer|Server $server | ||
23 | + */ | ||
24 | + public function bind($server): void; | ||
25 | + | ||
26 | + /** | ||
27 | + * Determine if the process should start ? | ||
28 | + * @param CoServer|Server $server | ||
29 | + */ | ||
30 | + public function isEnable($server): bool; | ||
31 | + | ||
32 | + /** | ||
33 | + * The logical of process will place in here. | ||
34 | + */ | ||
35 | + public function handle(): void; | ||
36 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Psr\Http\Message\ResponseInterface; | ||
15 | + | ||
16 | +interface ResponseEmitterInterface | ||
17 | +{ | ||
18 | + /** | ||
19 | + * @param mixed $connection swoole response or swow session | ||
20 | + */ | ||
21 | + public function emit(ResponseInterface $response, $connection, bool $withContent = true); | ||
22 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface SessionInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Starts the session storage. | ||
18 | + * | ||
19 | + * @throws \RuntimeException if session fails to start | ||
20 | + * @return bool True if session started | ||
21 | + */ | ||
22 | + public function start(): bool; | ||
23 | + | ||
24 | + /** | ||
25 | + * Returns the session ID. | ||
26 | + * | ||
27 | + * @return string The session ID | ||
28 | + */ | ||
29 | + public function getId(): string; | ||
30 | + | ||
31 | + /** | ||
32 | + * Sets the session ID. | ||
33 | + */ | ||
34 | + public function setId(string $id); | ||
35 | + | ||
36 | + /** | ||
37 | + * Returns the session name. | ||
38 | + */ | ||
39 | + public function getName(): string; | ||
40 | + | ||
41 | + /** | ||
42 | + * Sets the session name. | ||
43 | + */ | ||
44 | + public function setName(string $name); | ||
45 | + | ||
46 | + /** | ||
47 | + * Invalidates the current session. | ||
48 | + * | ||
49 | + * Clears all session attributes and flashes and regenerates the | ||
50 | + * session and deletes the old session from persistence. | ||
51 | + * | ||
52 | + * @param int $lifetime Sets the cookie lifetime for the session cookie. A null value | ||
53 | + * will leave the system settings unchanged, 0 sets the cookie | ||
54 | + * to expire with browser session. Time is in seconds, and is | ||
55 | + * not a Unix timestamp. | ||
56 | + * | ||
57 | + * @return bool True if session invalidated, false if error | ||
58 | + */ | ||
59 | + public function invalidate(?int $lifetime = null): bool; | ||
60 | + | ||
61 | + /** | ||
62 | + * Migrates the current session to a new session id while maintaining all | ||
63 | + * session attributes. | ||
64 | + * | ||
65 | + * @param bool $destroy Whether to delete the old session or leave it to garbage collection | ||
66 | + * @param int $lifetime Sets the cookie lifetime for the session cookie. A null value | ||
67 | + * will leave the system settings unchanged, 0 sets the cookie | ||
68 | + * to expire with browser session. Time is in seconds, and is | ||
69 | + * not a Unix timestamp. | ||
70 | + * | ||
71 | + * @return bool True if session migrated, false if error | ||
72 | + */ | ||
73 | + public function migrate(bool $destroy = false, ?int $lifetime = null): bool; | ||
74 | + | ||
75 | + /** | ||
76 | + * Force the session to be saved and closed. | ||
77 | + * | ||
78 | + * This method is generally not required for real sessions as | ||
79 | + * the session will be automatically saved at the end of | ||
80 | + * code execution. | ||
81 | + */ | ||
82 | + public function save(): void; | ||
83 | + | ||
84 | + /** | ||
85 | + * Checks if an attribute is defined. | ||
86 | + * | ||
87 | + * @param string $name The attribute name | ||
88 | + * | ||
89 | + * @return bool true if the attribute is defined, false otherwise | ||
90 | + */ | ||
91 | + public function has(string $name): bool; | ||
92 | + | ||
93 | + /** | ||
94 | + * Returns an attribute. | ||
95 | + * | ||
96 | + * @param string $name The attribute name | ||
97 | + * @param mixed $default The default value if not found | ||
98 | + */ | ||
99 | + public function get(string $name, $default = null); | ||
100 | + | ||
101 | + /** | ||
102 | + * Sets an attribute. | ||
103 | + * @param mixed $value | ||
104 | + */ | ||
105 | + public function set(string $name, $value): void; | ||
106 | + | ||
107 | + /** | ||
108 | + * Put a key / value pair or array of key / value pairs in the session. | ||
109 | + * | ||
110 | + * @param array|string $key | ||
111 | + * @param null|mixed $value | ||
112 | + */ | ||
113 | + public function put($key, $value = null): void; | ||
114 | + | ||
115 | + /** | ||
116 | + * Returns attributes. | ||
117 | + */ | ||
118 | + public function all(): array; | ||
119 | + | ||
120 | + /** | ||
121 | + * Sets attributes. | ||
122 | + */ | ||
123 | + public function replace(array $attributes): void; | ||
124 | + | ||
125 | + /** | ||
126 | + * Removes an attribute, returning its value. | ||
127 | + * | ||
128 | + * @return mixed The removed value or null when it does not exist | ||
129 | + */ | ||
130 | + public function remove(string $name); | ||
131 | + | ||
132 | + /** | ||
133 | + * Remove one or many items from the session. | ||
134 | + * | ||
135 | + * @param array|string $keys | ||
136 | + */ | ||
137 | + public function forget($keys): void; | ||
138 | + | ||
139 | + /** | ||
140 | + * Clears all attributes. | ||
141 | + */ | ||
142 | + public function clear(): void; | ||
143 | + | ||
144 | + /** | ||
145 | + * Checks if the session was started. | ||
146 | + */ | ||
147 | + public function isStarted(): bool; | ||
148 | + | ||
149 | + /** | ||
150 | + * Get the previous URL from the session. | ||
151 | + */ | ||
152 | + public function previousUrl(): ?string; | ||
153 | + | ||
154 | + /** | ||
155 | + * Set the "previous" URL in the session. | ||
156 | + */ | ||
157 | + public function setPreviousUrl(string $url): void; | ||
158 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Psr\Log\LoggerInterface; | ||
15 | + | ||
16 | +interface StdoutLoggerInterface extends LoggerInterface | ||
17 | +{ | ||
18 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface Synchronized | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Whether the data has been synchronized. | ||
18 | + */ | ||
19 | + public function isSynchronized(): bool; | ||
20 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface TranslatorInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Get the translation for a given key. | ||
18 | + */ | ||
19 | + public function trans(string $key, array $replace = [], ?string $locale = null); | ||
20 | + | ||
21 | + /** | ||
22 | + * Get a translation according to an integer value. | ||
23 | + * | ||
24 | + * @param array|\Countable|int $number | ||
25 | + */ | ||
26 | + public function transChoice(string $key, $number, array $replace = [], ?string $locale = null): string; | ||
27 | + | ||
28 | + /** | ||
29 | + * Get the default locale being used. | ||
30 | + */ | ||
31 | + public function getLocale(): string; | ||
32 | + | ||
33 | + /** | ||
34 | + * Set the default locale. | ||
35 | + */ | ||
36 | + public function setLocale(string $locale); | ||
37 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface TranslatorLoaderInterface | ||
15 | +{ | ||
16 | + /** | ||
17 | + * Load the messages for the given locale. | ||
18 | + */ | ||
19 | + public function load(string $locale, string $group, ?string $namespace = null): array; | ||
20 | + | ||
21 | + /** | ||
22 | + * Add a new namespace to the loader. | ||
23 | + */ | ||
24 | + public function addNamespace(string $namespace, string $hint); | ||
25 | + | ||
26 | + /** | ||
27 | + * Add a new JSON path to the loader. | ||
28 | + */ | ||
29 | + public function addJsonPath(string $path); | ||
30 | + | ||
31 | + /** | ||
32 | + * Get an array of all the registered namespaces. | ||
33 | + */ | ||
34 | + public function namespaces(): array; | ||
35 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +interface UnCompressInterface | ||
15 | +{ | ||
16 | + public function uncompress(); | ||
17 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Contract; | ||
13 | + | ||
14 | +use Hyperf\Utils\Contracts\MessageBag; | ||
15 | +use Hyperf\Utils\Contracts\MessageProvider; | ||
16 | + | ||
17 | +interface ValidatorInterface extends MessageProvider | ||
18 | +{ | ||
19 | + /** | ||
20 | + * Run the validator's rules against its data. | ||
21 | + */ | ||
22 | + public function validate(): array; | ||
23 | + | ||
24 | + /** | ||
25 | + * Get the attributes and values that were validated. | ||
26 | + */ | ||
27 | + public function validated(): array; | ||
28 | + | ||
29 | + /** | ||
30 | + * Determine if the data fails the validation rules. | ||
31 | + */ | ||
32 | + public function fails(): bool; | ||
33 | + | ||
34 | + /** | ||
35 | + * Get the failed validation rules. | ||
36 | + */ | ||
37 | + public function failed(): array; | ||
38 | + | ||
39 | + /** | ||
40 | + * Add conditions to a given field based on a Closure. | ||
41 | + * | ||
42 | + * @param array|string $attribute | ||
43 | + * @param array|string $rules | ||
44 | + * @return $this | ||
45 | + */ | ||
46 | + public function sometimes($attribute, $rules, callable $callback); | ||
47 | + | ||
48 | + /** | ||
49 | + * Add an after validation callback. | ||
50 | + * | ||
51 | + * @param callable|string $callback | ||
52 | + * @return $this | ||
53 | + */ | ||
54 | + public function after($callback); | ||
55 | + | ||
56 | + /** | ||
57 | + * Get all of the validation error messages. | ||
58 | + */ | ||
59 | + public function errors(): MessageBag; | ||
60 | +} |
addons/epay/library/hyperf/engine/.gitignore
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +$header = <<<'EOF' | ||
4 | +This file is part of Hyperf. | ||
5 | + | ||
6 | +@link https://www.hyperf.io | ||
7 | +@document https://hyperf.wiki | ||
8 | +@contact group@hyperf.io | ||
9 | +@license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
10 | +EOF; | ||
11 | + | ||
12 | +return (new PhpCsFixer\Config()) | ||
13 | + ->setRiskyAllowed(true) | ||
14 | + ->setRules([ | ||
15 | + '@PSR2' => true, | ||
16 | + '@Symfony' => true, | ||
17 | + '@DoctrineAnnotation' => true, | ||
18 | + '@PhpCsFixer' => true, | ||
19 | + 'header_comment' => [ | ||
20 | + 'comment_type' => 'PHPDoc', | ||
21 | + 'header' => $header, | ||
22 | + 'separate' => 'none', | ||
23 | + 'location' => 'after_declare_strict', | ||
24 | + ], | ||
25 | + 'array_syntax' => [ | ||
26 | + 'syntax' => 'short' | ||
27 | + ], | ||
28 | + 'list_syntax' => [ | ||
29 | + 'syntax' => 'short' | ||
30 | + ], | ||
31 | + 'concat_space' => [ | ||
32 | + 'spacing' => 'one' | ||
33 | + ], | ||
34 | + 'blank_line_before_statement' => [ | ||
35 | + 'statements' => [ | ||
36 | + 'declare', | ||
37 | + ], | ||
38 | + ], | ||
39 | + 'general_phpdoc_annotation_remove' => [ | ||
40 | + 'annotations' => [ | ||
41 | + 'author' | ||
42 | + ], | ||
43 | + ], | ||
44 | + 'ordered_imports' => [ | ||
45 | + 'imports_order' => [ | ||
46 | + 'class', 'function', 'const', | ||
47 | + ], | ||
48 | + 'sort_algorithm' => 'alpha', | ||
49 | + ], | ||
50 | + 'single_line_comment_style' => [ | ||
51 | + 'comment_types' => [ | ||
52 | + ], | ||
53 | + ], | ||
54 | + 'yoda_style' => [ | ||
55 | + 'always_move_variable' => false, | ||
56 | + 'equal' => false, | ||
57 | + 'identical' => false, | ||
58 | + ], | ||
59 | + 'phpdoc_align' => [ | ||
60 | + 'align' => 'left', | ||
61 | + ], | ||
62 | + 'multiline_whitespace_before_semicolons' => [ | ||
63 | + 'strategy' => 'no_multi_line', | ||
64 | + ], | ||
65 | + 'constant_case' => [ | ||
66 | + 'case' => 'lower', | ||
67 | + ], | ||
68 | + 'class_attributes_separation' => true, | ||
69 | + 'combine_consecutive_unsets' => true, | ||
70 | + 'declare_strict_types' => true, | ||
71 | + 'linebreak_after_opening_tag' => true, | ||
72 | + 'lowercase_static_reference' => true, | ||
73 | + 'no_useless_else' => true, | ||
74 | + 'no_unused_imports' => true, | ||
75 | + 'not_operator_with_successor_space' => true, | ||
76 | + 'not_operator_with_space' => false, | ||
77 | + 'ordered_class_elements' => true, | ||
78 | + 'php_unit_strict' => false, | ||
79 | + 'phpdoc_separation' => false, | ||
80 | + 'single_quote' => true, | ||
81 | + 'standardize_not_equals' => true, | ||
82 | + 'multiline_comment_opening_closing' => true, | ||
83 | + ]) | ||
84 | + ->setFinder( | ||
85 | + PhpCsFixer\Finder::create() | ||
86 | + ->exclude('vendor') | ||
87 | + ->in(__DIR__) | ||
88 | + ) | ||
89 | + ->setUsingCache(false); |
addons/epay/library/hyperf/engine/Dockerfile
0 → 100644
1 | +# Default Dockerfile | ||
2 | +# | ||
3 | +# @link https://www.hyperf.io | ||
4 | +# @document https://hyperf.wiki | ||
5 | +# @contact group@hyperf.io | ||
6 | +# @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE | ||
7 | + | ||
8 | +ARG PHP_VERSION | ||
9 | +ARG ALPINE_VERSION | ||
10 | + | ||
11 | +FROM hyperf/hyperf:${PHP_VERSION}-alpine-${ALPINE_VERSION}-swoole | ||
12 | +LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf" | ||
13 | + | ||
14 | +ARG timezone | ||
15 | +ARG PHP_VERSION | ||
16 | + | ||
17 | +ENV TIMEZONE=${timezone:-"Asia/Shanghai"} | ||
18 | +ENV COMPOSER_ROOT_VERSION="v1.2.0" | ||
19 | + | ||
20 | +# update | ||
21 | +RUN set -ex \ | ||
22 | + # show php version and extensions | ||
23 | + && php -v \ | ||
24 | + && php -m \ | ||
25 | + && php --ri swoole \ | ||
26 | + # ---------- some config ---------- | ||
27 | + && cd "/etc/php${PHP_VERSION%\.*}" \ | ||
28 | + # - config PHP | ||
29 | + && { \ | ||
30 | + echo "upload_max_filesize=128M"; \ | ||
31 | + echo "post_max_size=128M"; \ | ||
32 | + echo "memory_limit=1G"; \ | ||
33 | + echo "date.timezone=${TIMEZONE}"; \ | ||
34 | + } | tee conf.d/99_overrides.ini \ | ||
35 | + # - config timezone | ||
36 | + && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \ | ||
37 | + && echo "${TIMEZONE}" > /etc/timezone \ | ||
38 | + # ---------- clear works ---------- | ||
39 | + && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \ | ||
40 | + && echo -e "\033[42;37m Build Completed :).\033[0m\n" | ||
41 | + | ||
42 | +WORKDIR /opt/www | ||
43 | + | ||
44 | +COPY . /opt/www | ||
45 | + | ||
46 | +RUN composer install -o |
addons/epay/library/hyperf/engine/README.md
0 → 100644
1 | +{ | ||
2 | + "name": "hyperf/engine", | ||
3 | + "type": "library", | ||
4 | + "license": "MIT", | ||
5 | + "keywords": [ | ||
6 | + "php", | ||
7 | + "hyperf" | ||
8 | + ], | ||
9 | + "description": "", | ||
10 | + "autoload": { | ||
11 | + "psr-4": { | ||
12 | + "Hyperf\\Engine\\": "src/" | ||
13 | + } | ||
14 | + }, | ||
15 | + "autoload-dev": { | ||
16 | + "psr-4": { | ||
17 | + "HyperfTest\\": "tests" | ||
18 | + } | ||
19 | + }, | ||
20 | + "require": { | ||
21 | + "php": ">=7.4" | ||
22 | + }, | ||
23 | + "require-dev": { | ||
24 | + "friendsofphp/php-cs-fixer": "^3.0", | ||
25 | + "hyperf/guzzle": "^2.2", | ||
26 | + "phpstan/phpstan": "^1.0", | ||
27 | + "phpunit/phpunit": "^9.4", | ||
28 | + "swoole/ide-helper": "dev-master" | ||
29 | + }, | ||
30 | + "suggest": { | ||
31 | + "ext-swoole": ">=4.5" | ||
32 | + }, | ||
33 | + "minimum-stability": "dev", | ||
34 | + "prefer-stable": true, | ||
35 | + "config": { | ||
36 | + "optimize-autoloader": true, | ||
37 | + "sort-packages": true | ||
38 | + }, | ||
39 | + "extra": { | ||
40 | + "branch-alias": { | ||
41 | + "dev-master": "1.2-dev" | ||
42 | + } | ||
43 | + }, | ||
44 | + "scripts": { | ||
45 | + "test": "phpunit -c phpunit.xml --colors=always", | ||
46 | + "analyse": "phpstan analyse --memory-limit 1024M -l 0 ./src", | ||
47 | + "cs-fix": "php-cs-fixer fix $1" | ||
48 | + } | ||
49 | +} |
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<phpunit bootstrap="tests/bootstrap.php" | ||
3 | + backupGlobals="false" | ||
4 | + backupStaticAttributes="false" | ||
5 | + verbose="true" | ||
6 | + colors="true" | ||
7 | + convertErrorsToExceptions="true" | ||
8 | + convertNoticesToExceptions="true" | ||
9 | + convertWarningsToExceptions="true" | ||
10 | + processIsolation="false" | ||
11 | + stopOnFailure="false"> | ||
12 | + <testsuite name="Testsuite"> | ||
13 | + <directory>./tests/</directory> | ||
14 | + </testsuite> | ||
15 | +</phpunit> |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine; | ||
13 | + | ||
14 | +use Hyperf\Engine\Contract\ChannelInterface; | ||
15 | +use Hyperf\Engine\Exception\RuntimeException; | ||
16 | + | ||
17 | +if (PHP_VERSION_ID > 80000 && SWOOLE_VERSION_ID >= 50000) { | ||
18 | + class Channel extends \Swoole\Coroutine\Channel implements ChannelInterface | ||
19 | + { | ||
20 | + protected bool $closed = false; | ||
21 | + | ||
22 | + public function push(mixed $data, float $timeout = -1): bool | ||
23 | + { | ||
24 | + return parent::push($data, $timeout); | ||
25 | + } | ||
26 | + | ||
27 | + public function pop(float $timeout = -1): mixed | ||
28 | + { | ||
29 | + return parent::pop($timeout); | ||
30 | + } | ||
31 | + | ||
32 | + public function getCapacity(): int | ||
33 | + { | ||
34 | + return $this->capacity; | ||
35 | + } | ||
36 | + | ||
37 | + public function getLength(): int | ||
38 | + { | ||
39 | + return $this->length(); | ||
40 | + } | ||
41 | + | ||
42 | + public function isAvailable(): bool | ||
43 | + { | ||
44 | + return ! $this->isClosing(); | ||
45 | + } | ||
46 | + | ||
47 | + public function close(): bool | ||
48 | + { | ||
49 | + $this->closed = true; | ||
50 | + return parent::close(); | ||
51 | + } | ||
52 | + | ||
53 | + public function hasProducers(): bool | ||
54 | + { | ||
55 | + throw new RuntimeException('Not supported.'); | ||
56 | + } | ||
57 | + | ||
58 | + public function hasConsumers(): bool | ||
59 | + { | ||
60 | + throw new RuntimeException('Not supported.'); | ||
61 | + } | ||
62 | + | ||
63 | + public function isReadable(): bool | ||
64 | + { | ||
65 | + throw new RuntimeException('Not supported.'); | ||
66 | + } | ||
67 | + | ||
68 | + public function isWritable(): bool | ||
69 | + { | ||
70 | + throw new RuntimeException('Not supported.'); | ||
71 | + } | ||
72 | + | ||
73 | + public function isClosing(): bool | ||
74 | + { | ||
75 | + return $this->closed || $this->errCode === SWOOLE_CHANNEL_CLOSED; | ||
76 | + } | ||
77 | + | ||
78 | + public function isTimeout(): bool | ||
79 | + { | ||
80 | + return ! $this->closed && $this->errCode === SWOOLE_CHANNEL_TIMEOUT; | ||
81 | + } | ||
82 | + } | ||
83 | +} else { | ||
84 | + class Channel extends \Swoole\Coroutine\Channel implements ChannelInterface | ||
85 | + { | ||
86 | + /** | ||
87 | + * @var bool | ||
88 | + */ | ||
89 | + protected $closed = false; | ||
90 | + | ||
91 | + public function getCapacity(): int | ||
92 | + { | ||
93 | + return $this->capacity; | ||
94 | + } | ||
95 | + | ||
96 | + public function getLength(): int | ||
97 | + { | ||
98 | + return $this->length(); | ||
99 | + } | ||
100 | + | ||
101 | + public function isAvailable(): bool | ||
102 | + { | ||
103 | + return ! $this->isClosing(); | ||
104 | + } | ||
105 | + | ||
106 | + public function close(): bool | ||
107 | + { | ||
108 | + $this->closed = true; | ||
109 | + return parent::close(); | ||
110 | + } | ||
111 | + | ||
112 | + public function hasProducers(): bool | ||
113 | + { | ||
114 | + throw new RuntimeException('Not supported.'); | ||
115 | + } | ||
116 | + | ||
117 | + public function hasConsumers(): bool | ||
118 | + { | ||
119 | + throw new RuntimeException('Not supported.'); | ||
120 | + } | ||
121 | + | ||
122 | + public function isReadable(): bool | ||
123 | + { | ||
124 | + throw new RuntimeException('Not supported.'); | ||
125 | + } | ||
126 | + | ||
127 | + public function isWritable(): bool | ||
128 | + { | ||
129 | + throw new RuntimeException('Not supported.'); | ||
130 | + } | ||
131 | + | ||
132 | + public function isClosing(): bool | ||
133 | + { | ||
134 | + return $this->closed || $this->errCode === SWOOLE_CHANNEL_CLOSED; | ||
135 | + } | ||
136 | + | ||
137 | + public function isTimeout(): bool | ||
138 | + { | ||
139 | + return ! $this->closed && $this->errCode === SWOOLE_CHANNEL_TIMEOUT; | ||
140 | + } | ||
141 | + } | ||
142 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine; | ||
13 | + | ||
14 | +use Swoole\Coroutine\Http\Server as HttpServer; | ||
15 | +use Swoole\Coroutine\Server; | ||
16 | + | ||
17 | +class Constant | ||
18 | +{ | ||
19 | + public const ENGINE = 'Swoole'; | ||
20 | + | ||
21 | + public static function isCoroutineServer($server): bool | ||
22 | + { | ||
23 | + return $server instanceof Server || $server instanceof HttpServer; | ||
24 | + } | ||
25 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Contract; | ||
13 | + | ||
14 | +if (PHP_VERSION_ID > 80000 && SWOOLE_VERSION_ID >= 50000) { | ||
15 | + interface ChannelInterface | ||
16 | + { | ||
17 | + /** | ||
18 | + * @param float|int $timeout [optional] = -1 | ||
19 | + */ | ||
20 | + public function push(mixed $data, float $timeout = -1): bool; | ||
21 | + | ||
22 | + /** | ||
23 | + * @param float $timeout seconds [optional] = -1 | ||
24 | + * @return mixed when pop failed, return false | ||
25 | + */ | ||
26 | + public function pop(float $timeout = -1): mixed; | ||
27 | + | ||
28 | + /** | ||
29 | + * Swow: When the channel is closed, all the data in it will be destroyed. | ||
30 | + * Swoole: When the channel is closed, the data in it can still be popped out, but push behavior will no longer succeed. | ||
31 | + */ | ||
32 | + public function close(): bool; | ||
33 | + | ||
34 | + public function getCapacity(): int; | ||
35 | + | ||
36 | + public function getLength(): int; | ||
37 | + | ||
38 | + public function isAvailable(): bool; | ||
39 | + | ||
40 | + public function hasProducers(): bool; | ||
41 | + | ||
42 | + public function hasConsumers(): bool; | ||
43 | + | ||
44 | + public function isEmpty(): bool; | ||
45 | + | ||
46 | + public function isFull(): bool; | ||
47 | + | ||
48 | + public function isReadable(): bool; | ||
49 | + | ||
50 | + public function isWritable(): bool; | ||
51 | + | ||
52 | + public function isClosing(): bool; | ||
53 | + | ||
54 | + public function isTimeout(): bool; | ||
55 | + } | ||
56 | +} else { | ||
57 | + interface ChannelInterface | ||
58 | + { | ||
59 | + /** | ||
60 | + * @param mixed $data [required] | ||
61 | + * @param float|int $timeout [optional] = -1 | ||
62 | + * @return bool | ||
63 | + */ | ||
64 | + public function push($data, $timeout = -1); | ||
65 | + | ||
66 | + /** | ||
67 | + * @param float $timeout seconds [optional] = -1 | ||
68 | + * @return mixed when pop failed, return false | ||
69 | + */ | ||
70 | + public function pop($timeout = -1); | ||
71 | + | ||
72 | + /** | ||
73 | + * Swow: When the channel is closed, all the data in it will be destroyed. | ||
74 | + * Swoole: When the channel is closed, the data in it can still be popped out, but push behavior will no longer succeed. | ||
75 | + * @return mixed | ||
76 | + */ | ||
77 | + public function close(): bool; | ||
78 | + | ||
79 | + /** | ||
80 | + * @return int | ||
81 | + */ | ||
82 | + public function getCapacity(); | ||
83 | + | ||
84 | + /** | ||
85 | + * @return int | ||
86 | + */ | ||
87 | + public function getLength(); | ||
88 | + | ||
89 | + /** | ||
90 | + * @return bool | ||
91 | + */ | ||
92 | + public function isAvailable(); | ||
93 | + | ||
94 | + /** | ||
95 | + * @return bool | ||
96 | + */ | ||
97 | + public function hasProducers(); | ||
98 | + | ||
99 | + /** | ||
100 | + * @return bool | ||
101 | + */ | ||
102 | + public function hasConsumers(); | ||
103 | + | ||
104 | + /** | ||
105 | + * @return bool | ||
106 | + */ | ||
107 | + public function isEmpty(); | ||
108 | + | ||
109 | + /** | ||
110 | + * @return bool | ||
111 | + */ | ||
112 | + public function isFull(); | ||
113 | + | ||
114 | + /** | ||
115 | + * @return bool | ||
116 | + */ | ||
117 | + public function isReadable(); | ||
118 | + | ||
119 | + /** | ||
120 | + * @return bool | ||
121 | + */ | ||
122 | + public function isWritable(); | ||
123 | + | ||
124 | + /** | ||
125 | + * @return bool | ||
126 | + */ | ||
127 | + public function isClosing(); | ||
128 | + | ||
129 | + /** | ||
130 | + * @return bool | ||
131 | + */ | ||
132 | + public function isTimeout(); | ||
133 | + } | ||
134 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Contract; | ||
13 | + | ||
14 | +use Hyperf\Engine\Exception\CoroutineDestroyedException; | ||
15 | +use Hyperf\Engine\Exception\RunningInNonCoroutineException; | ||
16 | + | ||
17 | +interface CoroutineInterface | ||
18 | +{ | ||
19 | + /** | ||
20 | + * @param callable $callable [required] | ||
21 | + */ | ||
22 | + public function __construct(callable $callable); | ||
23 | + | ||
24 | + /** | ||
25 | + * @param mixed ...$data | ||
26 | + * @return $this | ||
27 | + */ | ||
28 | + public function execute(...$data); | ||
29 | + | ||
30 | + /** | ||
31 | + * @return int | ||
32 | + */ | ||
33 | + public function getId(); | ||
34 | + | ||
35 | + /** | ||
36 | + * @param callable $callable [required] | ||
37 | + * @param mixed ...$data | ||
38 | + * @return $this | ||
39 | + */ | ||
40 | + public static function create(callable $callable, ...$data); | ||
41 | + | ||
42 | + /** | ||
43 | + * @return int returns coroutine id from current coroutine, -1 in non coroutine environment | ||
44 | + */ | ||
45 | + public static function id(); | ||
46 | + | ||
47 | + /** | ||
48 | + * Returns the parent coroutine ID. | ||
49 | + * Returns 0 when running in the top level coroutine. | ||
50 | + * @throws RunningInNonCoroutineException when running in non-coroutine context | ||
51 | + * @throws CoroutineDestroyedException when the coroutine has been destroyed | ||
52 | + */ | ||
53 | + public static function pid(?int $id = null); | ||
54 | + | ||
55 | + /** | ||
56 | + * Set config to coroutine. | ||
57 | + */ | ||
58 | + public static function set(array $config); | ||
59 | + | ||
60 | + /** | ||
61 | + * @param null|int $id coroutine id | ||
62 | + * @return null|\ArrayObject | ||
63 | + */ | ||
64 | + public static function getContextFor(?int $id = null); | ||
65 | + | ||
66 | + /** | ||
67 | + * Execute callback when coroutine destruct. | ||
68 | + */ | ||
69 | + public static function defer(callable $callable); | ||
70 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Contract\Http; | ||
13 | + | ||
14 | +use Hyperf\Engine\Http\RawResponse; | ||
15 | + | ||
16 | +interface ClientInterface | ||
17 | +{ | ||
18 | + public function set(array $settings): bool; | ||
19 | + | ||
20 | + /** | ||
21 | + * @param string[][] $headers | ||
22 | + */ | ||
23 | + public function request(string $method = 'GET', string $path = '/', array $headers = [], string $contents = '', string $version = '1.1'): RawResponse; | ||
24 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Contract\WebSocket; | ||
13 | + | ||
14 | +interface WebSocketInterface | ||
15 | +{ | ||
16 | + public const ON_MESSAGE = 'message'; | ||
17 | + | ||
18 | + public const ON_CLOSE = 'close'; | ||
19 | + | ||
20 | + public function on(string $event, callable $callback): void; | ||
21 | + | ||
22 | + public function start(): void; | ||
23 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine; | ||
13 | + | ||
14 | +use Hyperf\Engine\Contract\CoroutineInterface; | ||
15 | +use Hyperf\Engine\Exception\CoroutineDestroyedException; | ||
16 | +use Hyperf\Engine\Exception\RunningInNonCoroutineException; | ||
17 | +use Hyperf\Engine\Exception\RuntimeException; | ||
18 | +use Swoole\Coroutine as SwooleCo; | ||
19 | + | ||
20 | +class Coroutine implements CoroutineInterface | ||
21 | +{ | ||
22 | + /** | ||
23 | + * @var callable | ||
24 | + */ | ||
25 | + private $callable; | ||
26 | + | ||
27 | + /** | ||
28 | + * @var int | ||
29 | + */ | ||
30 | + private $id; | ||
31 | + | ||
32 | + public function __construct(callable $callable) | ||
33 | + { | ||
34 | + $this->callable = $callable; | ||
35 | + } | ||
36 | + | ||
37 | + public static function create(callable $callable, ...$data) | ||
38 | + { | ||
39 | + $coroutine = new static($callable); | ||
40 | + $coroutine->execute(...$data); | ||
41 | + return $coroutine; | ||
42 | + } | ||
43 | + | ||
44 | + public function execute(...$data) | ||
45 | + { | ||
46 | + $this->id = SwooleCo::create($this->callable, ...$data); | ||
47 | + return $this; | ||
48 | + } | ||
49 | + | ||
50 | + public function getId() | ||
51 | + { | ||
52 | + if (is_null($this->id)) { | ||
53 | + throw new RuntimeException('Coroutine was not be executed.'); | ||
54 | + } | ||
55 | + return $this->id; | ||
56 | + } | ||
57 | + | ||
58 | + public static function id() | ||
59 | + { | ||
60 | + return SwooleCo::getCid(); | ||
61 | + } | ||
62 | + | ||
63 | + public static function pid(?int $id = null) | ||
64 | + { | ||
65 | + if ($id) { | ||
66 | + $cid = SwooleCo::getPcid($id); | ||
67 | + if ($cid === false) { | ||
68 | + throw new CoroutineDestroyedException(sprintf('Coroutine #%d has been destroyed.', $id)); | ||
69 | + } | ||
70 | + } else { | ||
71 | + $cid = SwooleCo::getPcid(); | ||
72 | + } | ||
73 | + if ($cid === false) { | ||
74 | + throw new RunningInNonCoroutineException('Non-Coroutine environment don\'t has parent coroutine id.'); | ||
75 | + } | ||
76 | + return max(0, $cid); | ||
77 | + } | ||
78 | + | ||
79 | + public static function set(array $config) | ||
80 | + { | ||
81 | + SwooleCo::set($config); | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * @return null|\ArrayObject | ||
86 | + */ | ||
87 | + public static function getContextFor(?int $id = null) | ||
88 | + { | ||
89 | + if ($id === null) { | ||
90 | + return SwooleCo::getContext(); | ||
91 | + } | ||
92 | + | ||
93 | + return SwooleCo::getContext($id); | ||
94 | + } | ||
95 | + | ||
96 | + public static function defer(callable $callable) | ||
97 | + { | ||
98 | + SwooleCo::defer($callable); | ||
99 | + } | ||
100 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Exception; | ||
13 | + | ||
14 | +class CoroutineDestroyedException extends RuntimeException | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Exception; | ||
13 | + | ||
14 | +class HttpClientException extends RuntimeException | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Exception; | ||
13 | + | ||
14 | +class RunningInNonCoroutineException extends RuntimeException | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Exception; | ||
13 | + | ||
14 | +class RuntimeException extends \RuntimeException | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine; | ||
13 | + | ||
14 | +class Extension | ||
15 | +{ | ||
16 | + public static function isLoaded(): bool | ||
17 | + { | ||
18 | + return extension_loaded('Swoole'); | ||
19 | + } | ||
20 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Http; | ||
13 | + | ||
14 | +use Hyperf\Engine\Contract\Http\ClientInterface; | ||
15 | +use Hyperf\Engine\Exception\HttpClientException; | ||
16 | +use Swoole\Coroutine\Http\Client as HttpClient; | ||
17 | + | ||
18 | +class Client extends HttpClient implements ClientInterface | ||
19 | +{ | ||
20 | + public function set(array $settings): bool | ||
21 | + { | ||
22 | + return parent::set($settings); | ||
23 | + } | ||
24 | + | ||
25 | + /** | ||
26 | + * @param string[][] $headers | ||
27 | + */ | ||
28 | + public function request(string $method = 'GET', string $path = '/', array $headers = [], string $contents = '', string $version = '1.1'): RawResponse | ||
29 | + { | ||
30 | + $this->setMethod($method); | ||
31 | + $this->setData($contents); | ||
32 | + $this->setHeaders($this->encodeHeaders($headers)); | ||
33 | + $this->execute($path); | ||
34 | + if ($this->errCode !== 0) { | ||
35 | + throw new HttpClientException($this->errMsg, $this->errCode); | ||
36 | + } | ||
37 | + return new RawResponse( | ||
38 | + $this->statusCode, | ||
39 | + $this->decodeHeaders($this->headers ?? []), | ||
40 | + $this->body, | ||
41 | + $version | ||
42 | + ); | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * @param string[] $headers | ||
47 | + * @return string[][] | ||
48 | + */ | ||
49 | + private function decodeHeaders(array $headers): array | ||
50 | + { | ||
51 | + $result = []; | ||
52 | + foreach ($headers as $name => $header) { | ||
53 | + // The key of header is lower case. | ||
54 | + $result[$name][] = $header; | ||
55 | + } | ||
56 | + if ($this->set_cookie_headers) { | ||
57 | + $result['set-cookie'] = $this->set_cookie_headers; | ||
58 | + } | ||
59 | + return $result; | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * Swoole engine not support two dimensional array. | ||
64 | + * @param string[][] $headers | ||
65 | + * @return string[] | ||
66 | + */ | ||
67 | + private function encodeHeaders(array $headers): array | ||
68 | + { | ||
69 | + $result = []; | ||
70 | + foreach ($headers as $name => $value) { | ||
71 | + $result[$name] = is_array($value) ? implode(',', $value) : $value; | ||
72 | + } | ||
73 | + | ||
74 | + return $result; | ||
75 | + } | ||
76 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Http; | ||
13 | + | ||
14 | +use Swoole\Http\Response; | ||
15 | + | ||
16 | +class FdGetter | ||
17 | +{ | ||
18 | + public function get(Response $response): int | ||
19 | + { | ||
20 | + return $response->fd; | ||
21 | + } | ||
22 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\Http; | ||
13 | + | ||
14 | +final class RawResponse | ||
15 | +{ | ||
16 | + /** | ||
17 | + * @var int | ||
18 | + */ | ||
19 | + public $statusCode = 0; | ||
20 | + | ||
21 | + /** | ||
22 | + * @var string[][] | ||
23 | + */ | ||
24 | + public $headers = []; | ||
25 | + | ||
26 | + /** | ||
27 | + * @var string | ||
28 | + */ | ||
29 | + public $body = ''; | ||
30 | + | ||
31 | + /** | ||
32 | + * Protocol version. | ||
33 | + * @var string | ||
34 | + */ | ||
35 | + public $version = ''; | ||
36 | + | ||
37 | + /** | ||
38 | + * @param string[][] $headers | ||
39 | + */ | ||
40 | + public function __construct(int $statusCode, array $headers, string $body, string $version) | ||
41 | + { | ||
42 | + $this->statusCode = $statusCode; | ||
43 | + $this->headers = $headers; | ||
44 | + $this->body = $body; | ||
45 | + $this->version = $version; | ||
46 | + } | ||
47 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine; | ||
13 | + | ||
14 | +class Socket extends \Swoole\Coroutine\Socket | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine; | ||
13 | + | ||
14 | +class WaitGroup extends \Swoole\Coroutine\WaitGroup | ||
15 | +{ | ||
16 | +} |
1 | +<?php | ||
2 | + | ||
3 | +declare(strict_types=1); | ||
4 | +/** | ||
5 | + * This file is part of Hyperf. | ||
6 | + * | ||
7 | + * @link https://www.hyperf.io | ||
8 | + * @document https://hyperf.wiki | ||
9 | + * @contact group@hyperf.io | ||
10 | + * @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
11 | + */ | ||
12 | +namespace Hyperf\Engine\WebSocket; | ||
13 | + | ||
14 | +class Frame | ||
15 | +{ | ||
16 | + public const PING = '27890027'; | ||
17 | + | ||
18 | + public const PONG = '278a0027'; | ||
19 | +} |
-
请 注册 或 登录 后发表评论