no message
This commit is contained in:
parent
218ed8d6c1
commit
81732bffbe
@ -32,6 +32,7 @@
|
|||||||
"phpmailer/phpmailer": "^6",
|
"phpmailer/phpmailer": "^6",
|
||||||
"postal/postal": "^2",
|
"postal/postal": "^2",
|
||||||
"ramsey/uuid": "^4",
|
"ramsey/uuid": "^4",
|
||||||
|
"resend/resend-php": "^1.3",
|
||||||
"sendgrid/sendgrid": "^8",
|
"sendgrid/sendgrid": "^8",
|
||||||
"sentry/sdk": "^4",
|
"sentry/sdk": "^4",
|
||||||
"slim/http": "^1",
|
"slim/http": "^1",
|
||||||
|
|||||||
150
composer.lock
generated
150
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "39ab430ad43a297c4e1b232afd979153",
|
"content-hash": "e0fd6bd3638d589f5952168b58c2189e",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adbario/php-dot-notation",
|
"name": "adbario/php-dot-notation",
|
||||||
@ -1378,22 +1378,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
"version": "7.8.1",
|
"version": "7.10.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/guzzle.git",
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
|
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
|
||||||
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
|
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"guzzlehttp/promises": "^1.5.3 || ^2.0.1",
|
"guzzlehttp/promises": "^2.3",
|
||||||
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
|
"guzzlehttp/psr7": "^2.8",
|
||||||
"php": "^7.2.5 || ^8.0",
|
"php": "^7.2.5 || ^8.0",
|
||||||
"psr/http-client": "^1.0",
|
"psr/http-client": "^1.0",
|
||||||
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||||
@ -1404,9 +1404,9 @@
|
|||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
|
"guzzle/client-integration-tests": "3.0.2",
|
||||||
"php-http/message-factory": "^1.1",
|
"php-http/message-factory": "^1.1",
|
||||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
|
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
|
||||||
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
@ -1484,7 +1484,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||||
"source": "https://github.com/guzzle/guzzle/tree/7.8.1"
|
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1500,20 +1500,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-12-03T20:35:24+00:00"
|
"time": "2025-08-23T22:36:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/promises",
|
"name": "guzzlehttp/promises",
|
||||||
"version": "2.0.2",
|
"version": "2.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/promises.git",
|
"url": "https://github.com/guzzle/promises.git",
|
||||||
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
|
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
|
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
|
||||||
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
|
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1521,7 +1521,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
@ -1567,7 +1567,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/promises/issues",
|
"issues": "https://github.com/guzzle/promises/issues",
|
||||||
"source": "https://github.com/guzzle/promises/tree/2.0.2"
|
"source": "https://github.com/guzzle/promises/tree/2.3.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1583,20 +1583,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-12-03T20:19:20+00:00"
|
"time": "2025-08-22T14:34:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
"version": "2.6.2",
|
"version": "2.9.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/psr7.git",
|
"url": "https://github.com/guzzle/psr7.git",
|
||||||
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
|
"reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
"url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884",
|
||||||
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
"reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1611,8 +1611,9 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"http-interop/http-factory-tests": "^0.9",
|
"http-interop/http-factory-tests": "0.9.0",
|
||||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
"jshttp/mime-db": "1.54.0.1",
|
||||||
|
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||||
@ -1683,7 +1684,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/psr7/issues",
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
"source": "https://github.com/guzzle/psr7/tree/2.6.2"
|
"source": "https://github.com/guzzle/psr7/tree/2.9.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1699,7 +1700,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-12-03T20:05:35+00:00"
|
"time": "2026-03-10T16:41:02+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "illuminate/collections",
|
"name": "illuminate/collections",
|
||||||
@ -3849,20 +3850,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-factory",
|
"name": "psr/http-factory",
|
||||||
"version": "1.0.2",
|
"version": "1.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/http-factory.git",
|
"url": "https://github.com/php-fig/http-factory.git",
|
||||||
"reference": "e616d01114759c4c489f93b099585439f795fe35"
|
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
|
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||||
"reference": "e616d01114759c4c489f93b099585439f795fe35",
|
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.0.0",
|
"php": ">=7.1",
|
||||||
"psr/http-message": "^1.0 || ^2.0"
|
"psr/http-message": "^1.0 || ^2.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -3886,7 +3887,7 @@
|
|||||||
"homepage": "https://www.php-fig.org/"
|
"homepage": "https://www.php-fig.org/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Common interfaces for PSR-7 HTTP message factories",
|
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"factory",
|
"factory",
|
||||||
"http",
|
"http",
|
||||||
@ -3898,9 +3899,9 @@
|
|||||||
"response"
|
"response"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
|
"source": "https://github.com/php-fig/http-factory"
|
||||||
},
|
},
|
||||||
"time": "2023-04-10T20:10:41+00:00"
|
"time": "2024-04-15T12:06:14+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-message",
|
"name": "psr/http-message",
|
||||||
@ -4394,6 +4395,63 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-11-08T05:53:05+00:00"
|
"time": "2023-11-08T05:53:05+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "resend/resend-php",
|
||||||
|
"version": "v1.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/resend/resend-php.git",
|
||||||
|
"reference": "87d29d98271a0ab1c09cdbee102daa2f9b3419db"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/resend/resend-php/zipball/87d29d98271a0ab1c09cdbee102daa2f9b3419db",
|
||||||
|
"reference": "87d29d98271a0ab1c09cdbee102daa2f9b3419db",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"guzzlehttp/guzzle": "^7.5",
|
||||||
|
"php": "^8.1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.13",
|
||||||
|
"mockery/mockery": "^1.6",
|
||||||
|
"pestphp/pest": "^1.0|^2.0|^3.0|^4.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/Resend.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Resend\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Resend and contributors",
|
||||||
|
"homepage": "https://github.com/resend/resend-php/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Resend PHP library.",
|
||||||
|
"homepage": "https://resend.com/",
|
||||||
|
"keywords": [
|
||||||
|
"api",
|
||||||
|
"client",
|
||||||
|
"php",
|
||||||
|
"resend",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/resend/resend-php/issues",
|
||||||
|
"source": "https://github.com/resend/resend-php/tree/v1.3.0"
|
||||||
|
},
|
||||||
|
"time": "2026-04-11T10:48:32+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "sendgrid/php-http-client",
|
"name": "sendgrid/php-http-client",
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
@ -5171,16 +5229,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v3.4.0",
|
"version": "v3.6.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
|
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||||
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
|
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -5188,12 +5246,12 @@
|
|||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "3.4-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/contracts",
|
"url": "https://github.com/symfony/contracts",
|
||||||
"url": "https://github.com/symfony/contracts"
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.6-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -5218,7 +5276,7 @@
|
|||||||
"description": "A generic function and convention to trigger deprecation notices",
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5234,7 +5292,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-05-23T14:45:45+00:00"
|
"time": "2024-09-25T14:21:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-client",
|
"name": "symfony/http-client",
|
||||||
@ -10480,6 +10538,6 @@
|
|||||||
"ext-yaml": "*",
|
"ext-yaml": "*",
|
||||||
"ext-zip": "*"
|
"ext-zip": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.6.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,8 +65,8 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<ul class="list-unstyled user-details list-unstyled-border list-unstyled-noborder">
|
<ul class="list-unstyled user-details list-unstyled-border list-unstyled-noborder">
|
||||||
<li class="media">
|
<li class="media">
|
||||||
{if $oNode->duck_class}
|
{if $oNode->country_code}
|
||||||
<img alt="image" class="mr-2 rounded-circle" width="50" height="50" src="/theme/cool/assets/fonts/flag-icon-css/flags/1x1/{$oNode->duck_class}.svg">
|
<img alt="image" class="mr-2 rounded-circle" width="50" height="50" src="/theme/cool/assets/fonts/flag-icon-css/flags/1x1/{$oNode->country_code}.svg">
|
||||||
{/if}
|
{/if}
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
{if in_array($oNode->pid, $aServerLiveIds)}
|
{if in_array($oNode->pid, $aServerLiveIds)}
|
||||||
|
|||||||
@ -84,6 +84,10 @@ EOL;
|
|||||||
|
|
||||||
$jobs->smtpClearDayCount(); // 重置stmp的day_count
|
$jobs->smtpClearDayCount(); // 重置stmp的day_count
|
||||||
|
|
||||||
|
$jobs->vcodeReport(); // 每日验证码注册率报表
|
||||||
|
$jobs->mailMustReport(); // 每日mailMust报表 - 需在重置之前
|
||||||
|
$jobs->mailMust_reset_month(); // 每天8点,check重置mailMust的month_count
|
||||||
|
|
||||||
// 每日清除前一天残留TgStep
|
// 每日清除前一天残留TgStep
|
||||||
$jobs->clearTgStep();
|
$jobs->clearTgStep();
|
||||||
|
|
||||||
@ -170,6 +174,7 @@ EOL;
|
|||||||
if ($minute === 0) {
|
if ($minute === 0) {
|
||||||
$jobs->hour_width_report(); // 检测小时耗流
|
$jobs->hour_width_report(); // 检测小时耗流
|
||||||
// $jobs->mergeBandWidth(); || 逻辑改变,不用了
|
// $jobs->mergeBandWidth(); || 逻辑改变,不用了
|
||||||
|
$jobs->mailMust_reset_day(); // 每小时0分,check重置mailMust的day_count
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run email queue
|
// Run email queue
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use App\Services\Auth;
|
|||||||
use App\Services\Cache;
|
use App\Services\Cache;
|
||||||
use App\Services\Captcha;
|
use App\Services\Captcha;
|
||||||
use App\Services\Filter;
|
use App\Services\Filter;
|
||||||
use App\Services\Mail;
|
use App\Services\MailMust;
|
||||||
use App\Services\MFA;
|
use App\Services\MFA;
|
||||||
use App\Services\RateLimit;
|
use App\Services\RateLimit;
|
||||||
use App\Services\Reward;
|
use App\Services\Reward;
|
||||||
@ -174,6 +174,7 @@ final class AuthController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function sendVerify(ServerRequest $request, Response $response, $next): ResponseInterface
|
public function sendVerify(ServerRequest $request, Response $response, $next): ResponseInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Config::obtain('reg_email_verify')) {
|
if (Config::obtain('reg_email_verify')) {
|
||||||
$email = strtolower(trim($this->antiXss->xss_clean($request->getParam('email'))));
|
$email = strtolower(trim($this->antiXss->xss_clean($request->getParam('email'))));
|
||||||
|
|
||||||
@ -205,7 +206,7 @@ final class AuthController extends BaseController
|
|||||||
$redis->setex('email_verify:' . $email_code, Config::obtain('email_verify_code_ttl'), $email);
|
$redis->setex('email_verify:' . $email_code, Config::obtain('email_verify_code_ttl'), $email);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Mail::send(
|
MailMust::sendVcode(
|
||||||
$email,
|
$email,
|
||||||
$_ENV['appName'] . ' - 验证邮件',
|
$_ENV['appName'] . ' - 验证邮件',
|
||||||
'verify_code.tpl',
|
'verify_code.tpl',
|
||||||
|
|||||||
@ -33,6 +33,17 @@ final class Config extends Model
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function _hit($item)
|
||||||
|
{
|
||||||
|
$config = (new Config())->where('item', $item)->first();
|
||||||
|
|
||||||
|
if (!$config) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $config->value;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getClass($class): array
|
public static function getClass($class): array
|
||||||
{
|
{
|
||||||
$configs = [];
|
$configs = [];
|
||||||
|
|||||||
34
src/Models/MailMust.php
Executable file
34
src/Models/MailMust.php
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
//use Illuminate\Database\Query\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
final class MailMust extends Model
|
||||||
|
{
|
||||||
|
protected $connection = 'default';
|
||||||
|
protected $table = 'mail_must';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function _incr()
|
||||||
|
{
|
||||||
|
$this->increment('inday_count');
|
||||||
|
$this->increment('inmonth_count');
|
||||||
|
|
||||||
|
$this->refresh();
|
||||||
|
|
||||||
|
if ($this->inday_count >= $this->inday_max) {
|
||||||
|
$this->status = -1;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->inmonth_count >= $this->inmonth_max) {
|
||||||
|
$this->status = -2;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -61,14 +61,14 @@ final class Node extends Model
|
|||||||
return $sMemoFront;
|
return $sMemoFront;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDuckClassAttribute(): string
|
// public function getDuckClassAttribute(): string
|
||||||
{
|
// {
|
||||||
$sLocation = $this->duck_group ?: ($this->duck_code ?? '');
|
// $sLocation = $this->duck_group ?: ($this->duck_code ?? '');
|
||||||
|
//
|
||||||
$sBeforeDash = strstr($sLocation, '-', true) ?: $sLocation;
|
// $sBeforeDash = strstr($sLocation, '-', true) ?: $sLocation;
|
||||||
|
//
|
||||||
return preg_replace('/\d+/', '', $sBeforeDash);
|
// return preg_replace('/\d+/', '', $sBeforeDash);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 节点状态颜色
|
* 节点状态颜色
|
||||||
|
|||||||
@ -53,11 +53,249 @@ use const PHP_EOL;
|
|||||||
use App\Models\Smtp as ModelSmtp;
|
use App\Models\Smtp as ModelSmtp;
|
||||||
//use Illuminate\Support\Facades\DB; // 线上可能要开
|
//use Illuminate\Support\Facades\DB; // 线上可能要开
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use App\Models\MailMust as ModelMailMust;
|
||||||
|
use App\Models\MailLog as ModelMailLog;
|
||||||
|
use App\Services\TomTool\Telegram\Slave as TeleSlave;
|
||||||
|
|
||||||
final class Cron
|
final class Cron
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// 必达邮件报表 - 必须在重置之前调用
|
||||||
|
public static function mailMustReport()
|
||||||
|
{
|
||||||
|
$cMailMust = ModelMailMust::where("status", "!=", 0)->get();
|
||||||
|
|
||||||
|
if ($cMailMust->isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sMsg = "\n====== ".$_ENV["site_code"]."必达邮件报表 ======";
|
||||||
|
foreach ($cMailMust as $oMailMust) {
|
||||||
|
|
||||||
|
$sStatusCn = match ($oMailMust->status) {
|
||||||
|
1 => " ♻️ 工作中",
|
||||||
|
-1 => " ‼️ 日流量用光",
|
||||||
|
-2 => " ‼️ 月流量用光",
|
||||||
|
default => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
$iSendCountPrev = $oMailMust->inday_count - $oMailMust->inday_count_prev;
|
||||||
|
$iLeft = $oMailMust->inmonth_max - $oMailMust->inmonth_count;
|
||||||
|
$iPerLeft = round(($iLeft / $oMailMust->inmonth_max * 100), 2);
|
||||||
|
|
||||||
|
// *start 距离天计算
|
||||||
|
$iResetDay = $oMailMust->inmonth_reset_day;
|
||||||
|
|
||||||
|
$oNow = new DateTime(); // 当前时间
|
||||||
|
$oResetDate = new DateTime(); // 初始化重置日期对象
|
||||||
|
$oResetDate->setDate((int)$oNow->format('Y'), (int)$oNow->format('m'), $iResetDay);
|
||||||
|
$oResetDate->setTime(0, 0, 0); // 规范化到当天凌晨
|
||||||
|
|
||||||
|
// 如果当前日期已经过了(或正好是)本月的重置日
|
||||||
|
if ($oNow >= $oResetDate) {
|
||||||
|
$oResetDate->modify('+1 month'); // 目标锁定下个月 10 号
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算差值
|
||||||
|
$oInterval = $oNow->diff($oResetDate);
|
||||||
|
$iDaysRem = (int)$oInterval->format('%a'); // 剩余天数
|
||||||
|
// *end 距离天计算
|
||||||
|
|
||||||
|
$sMsg .= "\n---- {$oMailMust->client}{$sStatusCn} ----";
|
||||||
|
$sMsg .= "\n昨日发送数:{$iSendCountPrev}";
|
||||||
|
$sMsg .= "\n月余量:{$iPerLeft}%({$iLeft})";
|
||||||
|
$sMsg .= "\n距重置:{$iDaysRem}天";
|
||||||
|
$sMsg .= "\n[日限额:{$oMailMust->inday_max}、月限额:{$oMailMust->inmonth_max}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
TeleSlave::notify()->enableDetail(false)->send($sMsg);
|
||||||
|
|
||||||
|
echo "必达邮件报表发送完成";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册验证邮件报表
|
||||||
|
public static function vcodeReport()
|
||||||
|
{
|
||||||
|
|
||||||
|
$sPrevTime = strtotime("-1 day");
|
||||||
|
// $sPrevTime = strtotime("-1 day"); // test
|
||||||
|
$sPrevDate = date("Y-m-d", $sPrevTime);
|
||||||
|
|
||||||
|
$cMailLog = ModelMailLog::where("scene", "vcode")->whereDate("date", $sPrevDate)->get();
|
||||||
|
|
||||||
|
if ($cMailLog->isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aUserEmails = User::whereDate("reg_date", $sPrevDate)->pluck("email")->toArray();
|
||||||
|
$aUserEmails = array_flip($aUserEmails);
|
||||||
|
|
||||||
|
$aMailUser = [];
|
||||||
|
$iTotalSendCount = 0; // 发送数量-重复
|
||||||
|
$cCom = [];
|
||||||
|
foreach ($cMailLog as $oMailLog) {
|
||||||
|
$iTotalSendCount++;
|
||||||
|
$aComTmp = explode('@', $oMailLog->to);
|
||||||
|
$sCom = end($aComTmp);
|
||||||
|
|
||||||
|
//// sart mailUser统计
|
||||||
|
if (!isset($aMailUser[$oMailLog->to])) { // 初始mailUser
|
||||||
|
$aMailUser[$oMailLog->to] = [
|
||||||
|
"bRegDone" => false,
|
||||||
|
"iSendCount" => 0,
|
||||||
|
"sClient" => '',
|
||||||
|
"sCom" => $sCom
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$aMailUser[$oMailLog->to]["iSendCount"]++;
|
||||||
|
$aMailUser[$oMailLog->to]["sClient"] = $oMailLog->client ?? '';
|
||||||
|
|
||||||
|
if (isset($aUserEmails[$oMailLog->to])) {
|
||||||
|
$aMailUser[$oMailLog->to]["bRegDone"] = true;
|
||||||
|
}
|
||||||
|
//// end mailUser统计
|
||||||
|
|
||||||
|
// start com统计
|
||||||
|
if (!isset($cCom[$sCom])) { // 初始com
|
||||||
|
$cCom[$sCom] = [
|
||||||
|
"sName" => $sCom,
|
||||||
|
"iSendCount" => 0,
|
||||||
|
"iRegDoneCount" => 0,
|
||||||
|
"iRegLossCount" => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$cCom[$sCom]["iSendCount"]++;
|
||||||
|
// end com统计
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$aComInfo = $cCom; // cominfo
|
||||||
|
$iRegDoneCount = 0; // 注册成功
|
||||||
|
$iRegLossCount = 0; // 注册失败-彻底(发码而未注册上)
|
||||||
|
$iMailUserCount = count($aMailUser); // 发送数量-非重复
|
||||||
|
$aFoolUser = []; // 发n次邮箱却没注册上的用户
|
||||||
|
$iFoolLimit = 4; // 参数
|
||||||
|
$iRegDoneSendCount = 0;
|
||||||
|
$iRegLossSendCount = 0;
|
||||||
|
foreach ($aMailUser as $sUserMail => $aCounts) {
|
||||||
|
|
||||||
|
if (!isset($aComInfo[$aCounts["sCom"]])) { // 按说不需要,稳健一点
|
||||||
|
$aComInfo[$aCounts["sCom"]] = [
|
||||||
|
"sName" => $sCom,
|
||||||
|
"iSendCount" => 0,
|
||||||
|
"iRegDoneCount" => 0,
|
||||||
|
"iRegLossCount" => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aCounts["bRegDone"] == true) {
|
||||||
|
$iRegDoneCount++;
|
||||||
|
$iRegDoneSendCount += $aCounts["iSendCount"];
|
||||||
|
$aComInfo[$aCounts["sCom"]]["iRegDoneCount"]++;
|
||||||
|
} else {
|
||||||
|
$iRegLossCount++;
|
||||||
|
$iRegLossSendCount += $aCounts["iSendCount"];
|
||||||
|
$aComInfo[$aCounts["sCom"]]["iRegLossCount"]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aCounts["bRegDone"] == false && $aCounts["iSendCount"] > $iFoolLimit) {
|
||||||
|
$aFoolUser[$sUserMail] = $aCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$iPerTotalRedDone = $iTotalSendCount > 0 ? round(($iRegDoneCount / $iTotalSendCount) * 100, 2) : 0;
|
||||||
|
$iAvgTotalSend = $iMailUserCount > 0 ? round($iTotalSendCount / $iMailUserCount, 2) : 0; // 平均每个用户发送了多少封邮件
|
||||||
|
$iAvgRegDone = $iRegDoneCount > 0 ? round($iRegDoneSendCount / $iRegDoneCount, 2) : 0; // 注册上的均发
|
||||||
|
$iPerRegDone = $iMailUserCount > 0 ? round(($iRegDoneCount / $iMailUserCount) * 100, 2) : 0; // 去重注册上率
|
||||||
|
$iAvgRegLoss = $iRegLossCount > 0 ? round($iRegLossSendCount / $iRegLossCount, 2) : 0; // 没注册上的均发
|
||||||
|
$iPerRegLoss = $iMailUserCount > 0 ? round(($iRegLossCount / $iMailUserCount) * 100, 2) : 0; // 去重没注册上率
|
||||||
|
|
||||||
|
$sMsg = "\n====== ".$_ENV["site_code"]."发码表报 - 注册 ======";
|
||||||
|
$sMsg .= "\n总发送:{$iTotalSendCount}";
|
||||||
|
$sMsg .= "\n总均发:{$iAvgTotalSend}";
|
||||||
|
$sMsg .= "\n总注册上率:{$iPerTotalRedDone}%({$iRegDoneCount}个)";
|
||||||
|
$sMsg .= "\n去重发送:{$iMailUserCount}";
|
||||||
|
$sMsg .= "\n去重注册上率:{$iPerRegDone}% [数量:{$iRegDoneCount}、均发:{$iAvgRegDone}]";
|
||||||
|
$sMsg .= "\n去重没注册上率:{$iPerRegLoss}% [数量:{$iRegLossCount}、均发:{$iAvgRegLoss}]";
|
||||||
|
|
||||||
|
TeleSlave::notify()->enableDetail(false)->send($sMsg);
|
||||||
|
|
||||||
|
usort($aComInfo, function ($a, $b) {
|
||||||
|
$iPerA = $a["iRegDoneCount"] / $a["iSendCount"];
|
||||||
|
$iPerB = $b["iRegDoneCount"] / $b["iSendCount"];
|
||||||
|
// 升序:如果 a 小于 b 返回负数
|
||||||
|
return $iPerB <=> $iPerA;
|
||||||
|
});
|
||||||
|
|
||||||
|
$sMsg = "\n====== ".$_ENV["site_code"]."发码表报 - 邮箱 ======";
|
||||||
|
foreach ($aComInfo as $sCom => $aCom) {
|
||||||
|
$iPerComReg = ($aCom["iRegDoneCount"] / $aCom["iSendCount"]) * 100;
|
||||||
|
$sMsg .= "\n".$aCom["sName"]." [成功率:{$iPerComReg}%、数量:".$aCom["iSendCount"]."]";
|
||||||
|
}
|
||||||
|
|
||||||
|
TeleSlave::notify()->enableDetail(false)->send($sMsg);
|
||||||
|
|
||||||
|
echo "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置mailMust day
|
||||||
|
public static function mailMust_reset_day()
|
||||||
|
{
|
||||||
|
$iCurrentHour = (int) date('H');
|
||||||
|
// $iCurrentHour = 8; // test
|
||||||
|
|
||||||
|
$cModels = ModelMailMust::where('inday_reset_hour', $iCurrentHour)->get();
|
||||||
|
|
||||||
|
if ($cModels->isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($cModels as $oModelMailMust) {
|
||||||
|
|
||||||
|
$oModelMailMust->inday_count_prev += $oModelMailMust->inday_count;
|
||||||
|
$oModelMailMust->inday_count = 0;
|
||||||
|
|
||||||
|
if ($oModelMailMust->status === -1) {
|
||||||
|
$oModelMailMust->status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oModelMailMust->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\nmailMust_reset_day - ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置maulMust month
|
||||||
|
public static function mailMust_reset_month()
|
||||||
|
{
|
||||||
|
$j = (int) date("j");
|
||||||
|
// $j = 1; //test
|
||||||
|
|
||||||
|
$cModelMailMust = ModelMailMust::where('inmonth_reset_day', $j)->get();
|
||||||
|
|
||||||
|
if ($cModelMailMust->isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($cModelMailMust as $oModelMailMust) {
|
||||||
|
|
||||||
|
$oModelMailMust->inmonth_count = 0;
|
||||||
|
$oModelMailMust->inday_count_prev = 0;
|
||||||
|
|
||||||
|
if ($oModelMailMust->status === -2) {
|
||||||
|
$oModelMailMust->status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oModelMailMust->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\nmailMust_reset_month - ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//// 商品自动化
|
//// 商品自动化
|
||||||
public static function productAuto(): void
|
public static function productAuto(): void
|
||||||
{
|
{
|
||||||
@ -268,7 +506,7 @@ final class Cron
|
|||||||
}
|
}
|
||||||
|
|
||||||
$aOrder = Order::whereBetween("update_time", [$sPrevTimeStart, $sPrevTimeEnd])
|
$aOrder = Order::whereBetween("update_time", [$sPrevTimeStart, $sPrevTimeEnd])
|
||||||
->where("status", "activated")
|
->whereIn("status", ["activated", "pending"])
|
||||||
->get()
|
->get()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
@ -2070,15 +2308,15 @@ final class Cron
|
|||||||
$text_html .= '<br>昨日总收入笔数:' . count($paylists) . '<br>昨日总收入金额:' . $paylists->sum('total');
|
$text_html .= '<br>昨日总收入笔数:' . count($paylists) . '<br>昨日总收入金额:' . $paylists->sum('total');
|
||||||
echo 'Sending daily finance email to admin user' . PHP_EOL;
|
echo 'Sending daily finance email to admin user' . PHP_EOL;
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
Notification::notifyAdmin(
|
// Notification::notifyAdmin(
|
||||||
'财务日报',
|
// '财务日报',
|
||||||
$text_html,
|
// $text_html,
|
||||||
'finance.tpl'
|
// 'finance.tpl'
|
||||||
);
|
// );
|
||||||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||||||
echo $e->getMessage() . PHP_EOL;
|
// echo $e->getMessage() . PHP_EOL;
|
||||||
}
|
// }
|
||||||
|
|
||||||
echo Tools::toDateTime(time()) . ' 成功发送财务日报' . PHP_EOL;
|
echo Tools::toDateTime(time()) . ' 成功发送财务日报' . PHP_EOL;
|
||||||
}
|
}
|
||||||
@ -2094,15 +2332,15 @@ final class Cron
|
|||||||
$text_html = '<br>上周总收入笔数:' . count($paylists) . '<br>上周总收入金额:' . $paylists->sum('total');
|
$text_html = '<br>上周总收入笔数:' . count($paylists) . '<br>上周总收入金额:' . $paylists->sum('total');
|
||||||
echo 'Sending weekly finance email to admin user' . PHP_EOL;
|
echo 'Sending weekly finance email to admin user' . PHP_EOL;
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
Notification::notifyAdmin(
|
// Notification::notifyAdmin(
|
||||||
'财务周报',
|
// '财务周报',
|
||||||
$text_html,
|
// $text_html,
|
||||||
'finance.tpl'
|
// 'finance.tpl'
|
||||||
);
|
// );
|
||||||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||||||
echo $e->getMessage() . PHP_EOL;
|
// echo $e->getMessage() . PHP_EOL;
|
||||||
}
|
// }
|
||||||
|
|
||||||
echo Tools::toDateTime(time()) . ' 成功发送财务周报' . PHP_EOL;
|
echo Tools::toDateTime(time()) . ' 成功发送财务周报' . PHP_EOL;
|
||||||
}
|
}
|
||||||
@ -2118,15 +2356,15 @@ final class Cron
|
|||||||
$text_html = '<br>上月总收入笔数:' . count($paylists) . '<br>上月总收入金额:' . $paylists->sum('total');
|
$text_html = '<br>上月总收入笔数:' . count($paylists) . '<br>上月总收入金额:' . $paylists->sum('total');
|
||||||
echo 'Sending monthly finance email to admin user' . PHP_EOL;
|
echo 'Sending monthly finance email to admin user' . PHP_EOL;
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
Notification::notifyAdmin(
|
// Notification::notifyAdmin(
|
||||||
'财务月报',
|
// '财务月报',
|
||||||
$text_html,
|
// $text_html,
|
||||||
'finance.tpl'
|
// 'finance.tpl'
|
||||||
);
|
// );
|
||||||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||||||
echo $e->getMessage() . PHP_EOL;
|
// echo $e->getMessage() . PHP_EOL;
|
||||||
}
|
// }
|
||||||
|
|
||||||
echo Tools::toDateTime(time()) . ' 成功发送财务月报' . PHP_EOL;
|
echo Tools::toDateTime(time()) . ' 成功发送财务月报' . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,9 +55,12 @@ final class Mail
|
|||||||
return $smarty->fetch($template);
|
return $smarty->fetch($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
to = 对方email
|
||||||
* @throws ClientExceptionInterface
|
subject = 标题
|
||||||
|
tmplate = 使用哪个模版
|
||||||
|
array = 模版内容说是? - 使用smarty模版渲染arr的key是变量名
|
||||||
*/
|
*/
|
||||||
public static function send($to, $subject, $template, $array = []): void
|
public static function send($to, $subject, $template, $array = []): void
|
||||||
{
|
{
|
||||||
|
|||||||
79
src/Services/Mail/Resend.php
Executable file
79
src/Services/Mail/Resend.php
Executable file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\Mail;
|
||||||
|
|
||||||
|
use App\Models\Config;
|
||||||
|
use Exception;
|
||||||
|
//use PHPMailer\PHPMailer\PHPMailer;
|
||||||
|
//use App\Models\MailLog as ModelMailLog;
|
||||||
|
//use App\Services\Mail\Resend;
|
||||||
|
use App\Models\MailMust as ModelMailMust;
|
||||||
|
use Resend as ResendSdk;
|
||||||
|
|
||||||
|
final class Resend extends Base
|
||||||
|
{
|
||||||
|
private $oMailSdk;
|
||||||
|
private $oModelMailMust;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->oModelMailMust = ModelMailMust::where('client', 'resend')->first();
|
||||||
|
$this->oMailSdk = ResendSdk::client($this->oModelMailMust->apikey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send($to, $subject, $body): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$oResult = $this->oMailSdk->emails->send([
|
||||||
|
'from' => $this->oModelMailMust->auther,
|
||||||
|
'to' => [$to],
|
||||||
|
'subject' => $subject,
|
||||||
|
'html' => $body,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sResultId = is_array($oResult) ? ($oResult['id'] ?? null) : ($oResult->id ?? null);
|
||||||
|
|
||||||
|
if (!$sResultId) {
|
||||||
|
throw new Exception("Resend 服务器未返回有效 ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->oModelMailMust->_incr();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientCode()
|
||||||
|
{
|
||||||
|
return 'resend';
|
||||||
|
}
|
||||||
|
|
||||||
|
// public function send($to, $subject, $body): void
|
||||||
|
// {
|
||||||
|
// try {
|
||||||
|
//
|
||||||
|
// $oResult = $this->oMailSdk->emails->send([
|
||||||
|
// 'from' => $this->oModelMailMust->auther,
|
||||||
|
// 'to' => [$to],
|
||||||
|
// 'subject' => $subject,
|
||||||
|
// 'html' => $body,
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// $sResultId = is_array($oResult) ? ($oResult['id'] ?? null) : ($oResult->id ?? null);
|
||||||
|
//
|
||||||
|
// if (!$sResultId) {
|
||||||
|
// throw new Exception("Resend 服务器未返回有效 ID");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $this->oModelMailMust->_incr();
|
||||||
|
//
|
||||||
|
// } catch (\Exception $e) {
|
||||||
|
//
|
||||||
|
// $s = "有邮件发送失败(logid:{$oMailLog->id}): " . $e->getMessage();
|
||||||
|
//
|
||||||
|
// TeleSlave::warn()->send($s);
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
72
src/Services/MailMust.php
Executable file
72
src/Services/MailMust.php
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Config;
|
||||||
|
use App\Models\MailMust as ModelMailMust;
|
||||||
|
use Exception;
|
||||||
|
use Psr\Http\Client\ClientExceptionInterface;
|
||||||
|
use Smarty\Smarty;
|
||||||
|
use App\Services\MailMust;
|
||||||
|
use App\Services\Mail\Resend;
|
||||||
|
use App\Models\MailLog as ModelMailLog;
|
||||||
|
use App\Services\TomTool\Telegram\Slave as TeleSlave;
|
||||||
|
|
||||||
|
final class MailMust
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function getClient()
|
||||||
|
{
|
||||||
|
$oMailMust = ModelMailMust::where("status", 1)->orderBy("sort")->first();
|
||||||
|
|
||||||
|
if (!$oMailMust) {
|
||||||
|
return new NullMail();
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($oMailMust->client) {
|
||||||
|
'resend' => new Resend(),
|
||||||
|
default => new NullMail(),
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function send($to, $subject, $template, $array = [], $scene = ''): void
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
$sGroupUse = Config::_hit("mailMustMap_clientGroup:".$scene);
|
||||||
|
if ($sGroupUse == "must") {
|
||||||
|
$oClient = self::getClient();
|
||||||
|
} else {
|
||||||
|
$oClient = Mail::getClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
$oMailLog = new ModelMailLog();
|
||||||
|
$oMailLog->to = $to;
|
||||||
|
$oMailLog->title = $subject;
|
||||||
|
$oMailLog->scene = $scene;
|
||||||
|
$oMailLog->client = $oClient->getClientCode();
|
||||||
|
$oMailLog->date = date("Y-m-d H:i:s");
|
||||||
|
$oMailLog->save();
|
||||||
|
|
||||||
|
$body = Mail::genHtml($template, $array);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$oClient->send($to, $subject, $body);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
TeleSlave::warn()->send("有邮件发送失败({$oMailLog->id}):".$e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function sendVcode($to, $subject, $template, $array = [], $scene = 'vcode')
|
||||||
|
{
|
||||||
|
self::send($to, $subject, $template, $array, $scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
50
src/Services/Tg/Hook/Mod/Config.php
Normal file
50
src/Services/Tg/Hook/Mod/Config.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Tg\Hook\Mod;
|
||||||
|
|
||||||
|
use App\Models\Config as ModelConfig;
|
||||||
|
use App\Services\Tg\Hook\Dog;
|
||||||
|
|
||||||
|
class Config extends Base {
|
||||||
|
|
||||||
|
private $oDog;
|
||||||
|
|
||||||
|
public function __construct($aUpdate)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->oDog = new Dog(new ModelConfig());
|
||||||
|
$this->oDog->_setDogName("config"); // 必须,me用,正常就是类名,只不过后期没准改名,所以就这里写死
|
||||||
|
$this->oDog->_setPrimaryKey("item"); // 可选,默认id
|
||||||
|
// $this->oDog->_setStrField(["content"]); // 可选,指定长文本字段
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($sName, $aArg)
|
||||||
|
{
|
||||||
|
return $this->oDog->$sName($aArg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function t1()
|
||||||
|
{
|
||||||
|
$r = ModelConfig::_hit("mailMustMap_clientGroup:vcode");
|
||||||
|
tomd($r, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public function show($aParam)
|
||||||
|
// {
|
||||||
|
// $sDate = $aParam["aArg"][1] ?? date("Y-m-d");
|
||||||
|
//
|
||||||
|
// $aMailLog = ModelMailLog::whereDate("date", $sDate)->get()->toArray();
|
||||||
|
//
|
||||||
|
// return $this->toJson($aMailLog);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function count()
|
||||||
|
// {
|
||||||
|
// $aCount = ModelMailLog::selectRaw('date, count(*) as total')
|
||||||
|
// ->groupBy('date')
|
||||||
|
// ->get();
|
||||||
|
//
|
||||||
|
// return $this->toJson($aCount);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@ -12,6 +12,8 @@ use App\Services\Cron;
|
|||||||
use App\Command\Cron as CommandCron;
|
use App\Command\Cron as CommandCron;
|
||||||
use App\Services\TomTool\Http;
|
use App\Services\TomTool\Http;
|
||||||
use App\Models\PlanQueue;
|
use App\Models\PlanQueue;
|
||||||
|
use Resend;
|
||||||
|
use App\Services\TomTool\Telegram\Slave as TeleSlave;
|
||||||
|
|
||||||
final class Test extends Base
|
final class Test extends Base
|
||||||
{
|
{
|
||||||
@ -42,10 +44,34 @@ final class Test extends Base
|
|||||||
// abort(404);
|
// abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function job($aParam)
|
||||||
|
{
|
||||||
|
return $this->cron($aParam);
|
||||||
|
}
|
||||||
|
|
||||||
public function t1()
|
public function t1()
|
||||||
{
|
{
|
||||||
echo 123;
|
|
||||||
|
$oTeleSlave = TeleSlave::warn("xxxx")->send("123123");
|
||||||
|
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
$iPayClass = $_ENV["resend_apikey"];
|
||||||
|
|
||||||
|
echo $iPayClass;
|
||||||
|
|
||||||
|
exit;
|
||||||
|
$resend = Resend::client('re_bopdT4FJ_Na1R1sHVaHGAWuWwXZ6VgH5U');
|
||||||
|
|
||||||
|
$resend->emails->send([
|
||||||
|
'from' => 'Acme <onboarding@resend.dev>',
|
||||||
|
'to' => ['mukaitao@proton.me'],
|
||||||
|
'subject' => 'hello world',
|
||||||
|
'html' => '<strong>it works!</strong>',
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo 1;exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rootGet()
|
public function rootGet()
|
||||||
|
|||||||
425
src/Services/TomTool/Flow.php
Executable file
425
src/Services/TomTool/Flow.php
Executable file
@ -0,0 +1,425 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\TomTool;
|
||||||
|
|
||||||
|
use App\Services\TomTool\TelegramVdb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
默认:
|
||||||
|
name:none
|
||||||
|
isDone:false
|
||||||
|
|
||||||
|
new:
|
||||||
|
$oResult = Flow::make("name");
|
||||||
|
|
||||||
|
快速:
|
||||||
|
Flow::make("name")->fail("kkkkkkk");
|
||||||
|
|
||||||
|
进阶:
|
||||||
|
Flow::make("name")->noDone()->msg("哟哟哟哟哟哟")->sendTg()->fetch();
|
||||||
|
|
||||||
|
业务:
|
||||||
|
step()
|
||||||
|
msg()
|
||||||
|
data()
|
||||||
|
aData()
|
||||||
|
jData()
|
||||||
|
sData()
|
||||||
|
code()
|
||||||
|
put()
|
||||||
|
merge()
|
||||||
|
toDone()
|
||||||
|
noDone()
|
||||||
|
step("start")
|
||||||
|
|
||||||
|
action:
|
||||||
|
reset()
|
||||||
|
done(?$msg)
|
||||||
|
fail(?$msg, ?$aParentResult)
|
||||||
|
sendTg() 伪action
|
||||||
|
fetch() or get()
|
||||||
|
fetchAll() or geAll()
|
||||||
|
|
||||||
|
set:
|
||||||
|
enableTg();
|
||||||
|
parent($aParentResult);
|
||||||
|
|
||||||
|
with:
|
||||||
|
withTraceId();
|
||||||
|
withTimestamp();
|
||||||
|
withStep();
|
||||||
|
|
||||||
|
判断:
|
||||||
|
::isDone($aResult);
|
||||||
|
::isFail($aResult);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Flow
|
||||||
|
{
|
||||||
|
protected array $aStep = [];
|
||||||
|
protected array $aParent = [];
|
||||||
|
protected bool $isToTg = false;
|
||||||
|
protected bool $isToTgOne = false;
|
||||||
|
protected array $aResult = [
|
||||||
|
'isDone' => false,
|
||||||
|
];
|
||||||
|
protected string $sName;
|
||||||
|
private bool $isChain = false;
|
||||||
|
|
||||||
|
public function __construct(string $name = 'none')
|
||||||
|
{
|
||||||
|
$this->sName = $name;
|
||||||
|
$this->aStep[] = "{$this->sName}::start";
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function make(string $name = 'none'): self
|
||||||
|
{
|
||||||
|
return new self($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function start($sName = 'none')
|
||||||
|
{
|
||||||
|
$oInstance = new self($sName);
|
||||||
|
$oInstance->isChain = true;
|
||||||
|
return $oInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// option
|
||||||
|
public function enableTg(bool $flag = true): self
|
||||||
|
{
|
||||||
|
$this->isToTg = $flag;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// option
|
||||||
|
public function enableTgOne(bool $flag = true): self
|
||||||
|
{
|
||||||
|
$this->enableTg(true);
|
||||||
|
$this->isToTgOne = $flag;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// option
|
||||||
|
public function parent(array $aParentResult): self
|
||||||
|
{
|
||||||
|
$this->aParent = $aParentResult;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function step(string $step): self
|
||||||
|
{
|
||||||
|
$this->aStep[] = "{$this->sName}::{$step}";
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function msg($msg = "msg未设置"): self
|
||||||
|
{
|
||||||
|
if (is_array($msg)) {
|
||||||
|
$msg = json_encode($msg);
|
||||||
|
}
|
||||||
|
$this->put('sMsg', $msg);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function aData(array $data): self
|
||||||
|
{
|
||||||
|
$this->put('aData', $data);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function aDataPut($k, $v)
|
||||||
|
{
|
||||||
|
$this->aResult["aData"][$k] = $v;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function sData(string $data): self
|
||||||
|
{
|
||||||
|
$this->put('sData', $data);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function code(string $code): self
|
||||||
|
{
|
||||||
|
$this->put('sCode', $code);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function put(string $key, mixed $value, $sDataKey = ''): self
|
||||||
|
{
|
||||||
|
if ($sDataKey) {
|
||||||
|
$this->aResult[$sDataKey][$key] = $value;
|
||||||
|
} else {
|
||||||
|
$this->aResult[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function merge(array $data): self
|
||||||
|
{
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
$this->put($k, $v);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function setDone(bool $b = true): self
|
||||||
|
{
|
||||||
|
$this->aResult['isDone'] = $b;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
public function setFail(string $step = ''): self
|
||||||
|
{
|
||||||
|
if ($step) {
|
||||||
|
$this->step($step);
|
||||||
|
}
|
||||||
|
$this->aResult['isDone'] = false;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// with
|
||||||
|
public function withTraceId(string $id = null): self
|
||||||
|
{
|
||||||
|
$this->aResult['sTraceId'] = $id ?? uniqid('trace_', true);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// with
|
||||||
|
public function withTimestamp(): self
|
||||||
|
{
|
||||||
|
$this->aResult['sTimestamp'] = (new \DateTime())->format(\DateTime::ATOM);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// with
|
||||||
|
public function withStep(bool $flag = true): self
|
||||||
|
{
|
||||||
|
if ($flag) {
|
||||||
|
$this->withParentStep();
|
||||||
|
$this->aResult['aStep'] = $this->aStep;
|
||||||
|
} else {
|
||||||
|
unset($this->aResult['aStep']);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function reset(): self
|
||||||
|
{
|
||||||
|
$this->aStep = [$this->sName . '::start'];
|
||||||
|
$this->aParent = [];
|
||||||
|
$this->isToTg = false;
|
||||||
|
$this->isToTgOne = false;
|
||||||
|
$this->aResult = ['isDone' => false];
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function done(mixed $msg = null)
|
||||||
|
{
|
||||||
|
$this->setDone();
|
||||||
|
if ($msg) {
|
||||||
|
$this->msg($msg);
|
||||||
|
}
|
||||||
|
return $this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function fail(mixed $msg = null, array $aParentResult = [])
|
||||||
|
{
|
||||||
|
$this->setFail('fail');
|
||||||
|
if ($aParentResult) {
|
||||||
|
$this->aParent = $aParentResult;
|
||||||
|
}
|
||||||
|
if ($msg) {
|
||||||
|
$this->msg($msg);
|
||||||
|
}
|
||||||
|
return $this->getFull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
// public function sendTg() // 伪装成非set
|
||||||
|
// {
|
||||||
|
// $this->enableTgOne();
|
||||||
|
// return $this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function sendTg($sBotCode = 'base', $sChatCode = 'base')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataA()
|
||||||
|
{
|
||||||
|
return $this->aResult["aData"] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataS()
|
||||||
|
{
|
||||||
|
return (string) $this->aResult["sData"] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataI()
|
||||||
|
{
|
||||||
|
return (int) $this->aResult["iData"] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataB()
|
||||||
|
{
|
||||||
|
return (bool) $this->aResult["bData"] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataX()
|
||||||
|
{
|
||||||
|
return $this->aResult["xData"] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataA(array $aData): self
|
||||||
|
{
|
||||||
|
$this->aData($aData);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataB(bool $bData): self
|
||||||
|
{
|
||||||
|
$this->aResult["bData"] = $bData;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataS(string $sData): self
|
||||||
|
{
|
||||||
|
$this->aResult["sData"] = $sData;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataI(int $iData): self
|
||||||
|
{
|
||||||
|
$this->aResult["iData"] = $iData;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataX($xData): self
|
||||||
|
{
|
||||||
|
$this->aResult["xData"] = $xData;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult(): array
|
||||||
|
{
|
||||||
|
return $this->aResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
if ($this->isToTg) {
|
||||||
|
$this->_sendTg();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isToTgOne) {
|
||||||
|
$this->isToTg = false;
|
||||||
|
$this->isToTgOne = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isChain) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->aResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function getFull()
|
||||||
|
{
|
||||||
|
$this->withStep();
|
||||||
|
return $this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return $this->aResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function toJson($bFormat = true)
|
||||||
|
{
|
||||||
|
if ($bFormat === true) {
|
||||||
|
return json_encode($this->aResult, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||||
|
} else {
|
||||||
|
return json_encode($this->aResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper
|
||||||
|
public function isDone()
|
||||||
|
{
|
||||||
|
return $this->aResult["isDone"] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper
|
||||||
|
public function isFail()
|
||||||
|
{
|
||||||
|
return !$this->isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper
|
||||||
|
public static function isDoneResult(array $aResult): bool
|
||||||
|
{
|
||||||
|
return $aResult['isDone'] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper
|
||||||
|
public static function isFailResult(array $aResult): bool
|
||||||
|
{
|
||||||
|
return !self::isDoneResult($aResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shell
|
||||||
|
public function fetch()
|
||||||
|
{
|
||||||
|
return $this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// shell
|
||||||
|
public function fetchAll()
|
||||||
|
{
|
||||||
|
return $this->getFull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _sendTg()
|
||||||
|
{
|
||||||
|
TelegramVdb::make()->dataArr($this->aResult)->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addStepParent(): void
|
||||||
|
{
|
||||||
|
$this->aStep[] = $this->aParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function withParentStep(): void
|
||||||
|
{
|
||||||
|
if ($this->aParent) {
|
||||||
|
$this->addStepParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
203
src/Services/TomTool/HttpV2.php
Executable file
203
src/Services/TomTool/HttpV2.php
Executable file
@ -0,0 +1,203 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// 版本:25-12-12
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\TomTool;
|
||||||
|
|
||||||
|
use App\Services\TomTool\Flow;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
默认:
|
||||||
|
method:post
|
||||||
|
|
||||||
|
new:
|
||||||
|
HttpV2::make($url)
|
||||||
|
|
||||||
|
基本:
|
||||||
|
HttpV2::make($url)->send()
|
||||||
|
|
||||||
|
进阶:
|
||||||
|
HttpV2::make($url, "get")->setDataA($aData)->enableJsonAs()->enableAsync()->optMethod("get")->send();
|
||||||
|
|
||||||
|
action:
|
||||||
|
send()
|
||||||
|
|
||||||
|
data:
|
||||||
|
xData()
|
||||||
|
sData()
|
||||||
|
jData()
|
||||||
|
sData()
|
||||||
|
|
||||||
|
set:
|
||||||
|
optMethod()
|
||||||
|
enableJsonAs()
|
||||||
|
enableJsonSend()
|
||||||
|
enableJsonReturn()
|
||||||
|
|
||||||
|
@note:
|
||||||
|
默认关闭 SSL 验证(适用于开发环境),生产环境建议开启
|
||||||
|
异步模式下不会返回响应内容,仅快速触发请求
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class HttpV2
|
||||||
|
{
|
||||||
|
protected string $method;
|
||||||
|
protected $data = [];
|
||||||
|
protected string $url;
|
||||||
|
protected bool $sendJson = false;
|
||||||
|
protected bool $returnJson = false;
|
||||||
|
protected bool $async = false;
|
||||||
|
// 匈牙利命名法,仅新增一个 token 变量
|
||||||
|
protected string $sToken = '';
|
||||||
|
|
||||||
|
public static function make(string $url, string $method = 'post'): self
|
||||||
|
{
|
||||||
|
$instance = new self();
|
||||||
|
$instance->url = $url;
|
||||||
|
$instance->optMethod($method);
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optMethod(string $method): self
|
||||||
|
{
|
||||||
|
$this->method = strtolower($method);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增:支持携带 Token
|
||||||
|
* 如果不传值,默认从环境变量 token_base 获取
|
||||||
|
*/
|
||||||
|
public function withToken(?string $sToken = null): self
|
||||||
|
{
|
||||||
|
$this->sToken = $sToken ?? (string)env('token_base', false);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataX($xData)
|
||||||
|
{
|
||||||
|
$this->setData($xData);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataA($aData)
|
||||||
|
{
|
||||||
|
$this->setData($aData);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataS($sData)
|
||||||
|
{
|
||||||
|
$this->setData($sData);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData($xData)
|
||||||
|
{
|
||||||
|
$this->data = $xData;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableJsonSend(bool $flag = true): self
|
||||||
|
{
|
||||||
|
$this->sendJson = $flag;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableJsonReturn(bool $flag = true): self
|
||||||
|
{
|
||||||
|
$this->returnJson = $flag;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableJsonAs(): self
|
||||||
|
{
|
||||||
|
$this->sendJson = true;
|
||||||
|
$this->returnJson = true;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableAsync(bool $flag = true): self
|
||||||
|
{
|
||||||
|
$this->async = $flag;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(): string
|
||||||
|
{
|
||||||
|
$oFlow = Flow::make("HttpV2::send");
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
$headers = [];
|
||||||
|
|
||||||
|
// --- 核心嵌入:如果 sToken 有值且不是 false,塞进 Header ---
|
||||||
|
if ($this->sToken && $this->sToken !== 'false') {
|
||||||
|
$headers[] = 'Authorization: Bearer ' . $this->sToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建 URL 和请求体 (完全保留原样)
|
||||||
|
if ($this->method === 'get') {
|
||||||
|
$url = $this->url . '?' . http_build_query($this->data);
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
||||||
|
} else {
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $this->url);
|
||||||
|
$payload = $this->sendJson ? json_encode($this->data) : http_build_query($this->data);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||||
|
|
||||||
|
if ($this->method === 'post') {
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
} else {
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($this->method));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->sendJson) {
|
||||||
|
$headers[] = 'Content-Type: application/json';
|
||||||
|
$headers[] = 'Content-Length: ' . strlen($payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->returnJson) {
|
||||||
|
$headers[] = 'Accept: application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($headers)) {
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSL 设置 (完全保留原样)
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
|
||||||
|
// 异步发送 (完全保留原样)
|
||||||
|
if ($this->async) {
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
|
||||||
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 200);
|
||||||
|
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
|
||||||
|
curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
return 'sent';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阻塞执行 (完全保留原样)
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
$error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
throw new Exception("cURL Error: {$error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
177
src/Services/TomTool/Telegram/Master.php
Executable file
177
src/Services/TomTool/Telegram/Master.php
Executable file
@ -0,0 +1,177 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\TomTool\Telegram;
|
||||||
|
|
||||||
|
use App\Services\HttpQueue as ServiceHttpQueue;
|
||||||
|
use App\Services\TomTool\Flow;
|
||||||
|
use App\Services\TomTool\Telegram\Sdk as ServiceTelegramSdk;
|
||||||
|
use App\Models\TelegramKey as ModelTelegramKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
注意是master服务器端专用的,这里会对code找map,slave不会。
|
||||||
|
|
||||||
|
new:
|
||||||
|
start(?$sBodeCode, ?$sChatCode)
|
||||||
|
|
||||||
|
set:
|
||||||
|
setBotCode()
|
||||||
|
setChatCode()
|
||||||
|
setBotToken()
|
||||||
|
setChatId()
|
||||||
|
setMsgS()
|
||||||
|
|
||||||
|
action:
|
||||||
|
send()
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class Master
|
||||||
|
{
|
||||||
|
public string $sBotCode = "base";
|
||||||
|
public string $sChatCode = "base";
|
||||||
|
public string $sBotToken = '';
|
||||||
|
public int $iChatId = 0;
|
||||||
|
|
||||||
|
public string $sMsg = '';
|
||||||
|
public string $sPhotoUrl = '';
|
||||||
|
public int $iPhotoWidth = 0;
|
||||||
|
public int $iPhotoHeight = 0;
|
||||||
|
|
||||||
|
public string $sFileUrl = '';
|
||||||
|
public string $sFileName = '';
|
||||||
|
|
||||||
|
public string $sType = '';
|
||||||
|
|
||||||
|
public bool $enableQueue = false; // 应该用不到了
|
||||||
|
|
||||||
|
public bool $bKeyBegin = false;
|
||||||
|
|
||||||
|
public static function start($sBotCode = 'base', $sChatCode = 'base'): self
|
||||||
|
{
|
||||||
|
$oInstance = new self();
|
||||||
|
$oInstance->sBotCode = $sBotCode;
|
||||||
|
$oInstance->sChatCode = $sChatCode;
|
||||||
|
return $oInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBotCode(string $sBotCode): self
|
||||||
|
{
|
||||||
|
$this->sBotCode = $sBotCode;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setChatCode(string $sChatCode): self
|
||||||
|
{
|
||||||
|
$this->sChatCode = $sChatCode;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBotToken(string $sBotToken): self
|
||||||
|
{
|
||||||
|
$this->sBotToken = $sBotToken;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setChatId(int $iChatId): self
|
||||||
|
{
|
||||||
|
$this->iChatId = $iChatId;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMsgS(string $sMsg): self
|
||||||
|
{
|
||||||
|
$this->sMsg = $sMsg;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPhotoUrl(string $sPhotoUrl, int $iPhotoWidth = 0, int $iPhotoHeight = 0): self
|
||||||
|
{
|
||||||
|
$this->sPhotoUrl = $sPhotoUrl;
|
||||||
|
$this->iPhotoWidth = $iPhotoWidth;
|
||||||
|
$this->iPhotoHeight = $iPhotoHeight;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType(string $sType): self
|
||||||
|
{
|
||||||
|
$this->sType = $sType;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFileUrl(string $sFileUrl = '', string $sFileName = ''): self
|
||||||
|
{
|
||||||
|
$this->sFileUrl = $sFileUrl;
|
||||||
|
$this->sFileName = $sFileName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send($sMsg = ''): Flow
|
||||||
|
{
|
||||||
|
if ($sMsg) {
|
||||||
|
$this->sMsg = $sMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->sMsg) {
|
||||||
|
// throw new \Exception("未设置msg");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->keyBegin();
|
||||||
|
|
||||||
|
if ($this->enableQueue) {
|
||||||
|
$aData = $this->buildDataTom();
|
||||||
|
$oFlow = ServiceHttpQueue::start("telegram_local")->arg($aData)->save();
|
||||||
|
} else {
|
||||||
|
$oFlow = ServiceTelegramSdk::start()
|
||||||
|
->setBotToken($this->sBotToken)
|
||||||
|
->setChatId($this->iChatId)
|
||||||
|
->setMsgS($this->sMsg)
|
||||||
|
->setPhotoUrl($this->sPhotoUrl, $this->iPhotoWidth, $this->iPhotoHeight)
|
||||||
|
->setFileUrl($this->sFileUrl, $this->sFileName)
|
||||||
|
->setType($this->sType)
|
||||||
|
->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $oFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function keyBegin()
|
||||||
|
{
|
||||||
|
if (!$this->bKeyBegin) {
|
||||||
|
if (!$this->sBotToken) {
|
||||||
|
$this->sBotToken = ModelTelegramKey::botTokenByCode($this->sBotCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->iChatId) {
|
||||||
|
$this->iChatId = ModelTelegramKey::chatIdByCode($this->sChatCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->sBotToken || !$this->iChatId) {
|
||||||
|
throw new \RuntimeException("botToken或chatId没找到,botCode={$this->sBotCode},chatCode={$this->sChatCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->bKeyBegin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildDataTom(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"sBotCode" => $this->sBotCode ?? '',
|
||||||
|
"sChatCode" => $this->sChatCode ?? '',
|
||||||
|
"sBotToken" => $this->sBotToken ?? '',
|
||||||
|
"iChatId" => $this->iChatId ?? '',
|
||||||
|
"sPhotoUrl" => $this->sPhotoUrl ?? '',
|
||||||
|
"iPhotoWidth" => $this->iPhotoWidth,
|
||||||
|
"iPhotoHeight" => $this->iPhotoHeight,
|
||||||
|
"sFileUrl" => $this->sFileUrl,
|
||||||
|
"sFileName" => $this->sFileName,
|
||||||
|
"sMsg" => $this->sMsg ?? '',
|
||||||
|
"sType" => $this->sType ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
215
src/Services/TomTool/Telegram/Sdk.php
Executable file
215
src/Services/TomTool/Telegram/Sdk.php
Executable file
@ -0,0 +1,215 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\TomTool\Telegram;
|
||||||
|
use Telegram\Bot\Api;
|
||||||
|
use Telegram\Bot\FileUpload\InputFile;
|
||||||
|
use Telegram\Bot\Exceptions\TelegramSDKException;
|
||||||
|
use App\Services\TomTool\Flow;
|
||||||
|
//use Intervention\Image\Laravel\Facades\Image;
|
||||||
|
use Intervention\Image\ImageManager;
|
||||||
|
use Intervention\Image\Drivers\Gd\Driver;
|
||||||
|
use App\Services\TomTool\HttpV2;
|
||||||
|
|
||||||
|
class Sdk
|
||||||
|
{
|
||||||
|
public $sMsgFormat = [];
|
||||||
|
public $sMsgFormatType = 'none';
|
||||||
|
public $sBotToken = '';
|
||||||
|
public $iChatId = 0;
|
||||||
|
public $sPhotoUrl = '';
|
||||||
|
public $iPhotoWidth = 0;
|
||||||
|
public $iPhotoHeight = 0;
|
||||||
|
public $sFileUrl = '';
|
||||||
|
public $sFileName = '';
|
||||||
|
public $sMsg;
|
||||||
|
public $oApi;
|
||||||
|
|
||||||
|
private const ALLOWED_FORMATS = ['none', 'html', 'markdown', 'markdownV2'];
|
||||||
|
|
||||||
|
public static function start()
|
||||||
|
{
|
||||||
|
$oInstance = new self();
|
||||||
|
return $oInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBotToken($sBotToken)
|
||||||
|
{
|
||||||
|
$this->oApi = new Api($sBotToken);
|
||||||
|
$this->sBotToken = $sBotToken;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setChatId($iChatId)
|
||||||
|
{
|
||||||
|
$this->iChatId = $iChatId;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMsgS($sMsg = '')
|
||||||
|
{
|
||||||
|
$this->sMsg = $sMsg;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPhotoUrl($sUrl = '', $iPhotoWidth = 0, $iPhotoHeight = 0)
|
||||||
|
{
|
||||||
|
$this->sPhotoUrl = $sUrl;
|
||||||
|
$this->iPhotoWidth = $iPhotoWidth;
|
||||||
|
$this->iPhotoHeight = $iPhotoHeight;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFileUrl($sFileUrl = '', $sFileName = '')
|
||||||
|
{
|
||||||
|
$this->sFileUrl = $sFileUrl;
|
||||||
|
$this->sFileName = $sFileName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType($sType)
|
||||||
|
{
|
||||||
|
if ($sType) {
|
||||||
|
$this->sMsgFormatType = $sType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send()
|
||||||
|
{
|
||||||
|
$oFlow = Flow::start("tg_sdk_send");
|
||||||
|
|
||||||
|
$this->msgFormat();
|
||||||
|
|
||||||
|
// try {
|
||||||
|
|
||||||
|
if ($this->sPhotoUrl) {
|
||||||
|
$r = $this->oApi->sendPhoto($this->sMsgFormat);
|
||||||
|
} else if ($this->sFileUrl) {
|
||||||
|
$r = $this->oApi->sendDocument($this->sMsgFormat);
|
||||||
|
} else {
|
||||||
|
$r = $this->oApi->sendMessage($this->sMsgFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($r && $r->getMessageId())) {
|
||||||
|
return $oFlow->fail($r);
|
||||||
|
}
|
||||||
|
// } catch (TelegramSDKException $e) {
|
||||||
|
// return $oFlow->fail(['error' => $e->getMessage()]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return $oFlow->done();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMsgFormat()
|
||||||
|
{
|
||||||
|
$this->msgFormat();
|
||||||
|
|
||||||
|
return $this->sMsgFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function msgFormat()
|
||||||
|
{
|
||||||
|
if (!in_array($this->sMsgFormatType, self::ALLOWED_FORMATS, true)) {
|
||||||
|
throw new \RuntimeException("不支持的格式类型: {$this->sMsgFormatType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = 'msgFormat_' . $this->sMsgFormatType;
|
||||||
|
$this->sMsgFormat = $this->$method();
|
||||||
|
|
||||||
|
if ($this->sPhotoUrl) {
|
||||||
|
|
||||||
|
$oManager = new ImageManager(new Driver());
|
||||||
|
|
||||||
|
$sTempPath = $_ENV['dir_base'].'public/upload';
|
||||||
|
$sTempPath .= "/tg_output.png";
|
||||||
|
|
||||||
|
$sImg = file_get_contents($this->sPhotoUrl);
|
||||||
|
$oImage = $oManager->read($sImg);
|
||||||
|
|
||||||
|
if ($this->iPhotoWidth && $this->iPhotoHeight) {
|
||||||
|
$oImage = $oImage->cover($this->iPhotoWidth, $this->iPhotoHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
$oImage->toJpg(80)->save($sTempPath);
|
||||||
|
|
||||||
|
$photo = InputFile::create($sTempPath, date("Y-m-d").'.jpg');
|
||||||
|
|
||||||
|
$this->sMsgFormat["photo"] = $photo;
|
||||||
|
|
||||||
|
$this->sMsgFormat["caption"] = $this->sMsgFormat["text"];
|
||||||
|
unset($this->sMsgFormat["text"]);
|
||||||
|
|
||||||
|
} else if ($this->sFileUrl) {
|
||||||
|
|
||||||
|
if (!$this->sFileName) {
|
||||||
|
$sFileName = date("Y-m-d H:i:s").'.txt';
|
||||||
|
} else {
|
||||||
|
$sFileName = $this->sFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sFile = InputFile::create($this->sFileUrl, $sFileName);
|
||||||
|
|
||||||
|
$this->sMsgFormat["document"] = $sFile;
|
||||||
|
$this->sMsgFormat["caption"] = $this->sMsgFormat["text"];
|
||||||
|
unset($this->sMsgFormat["text"]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function msgFormat_none()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'chat_id' => $this->iChatId,
|
||||||
|
'text' => $this->sMsg,
|
||||||
|
'parse_mode' => '',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function msgFormat_html()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'chat_id' => $this->iChatId,
|
||||||
|
'text' => strip_tags($this->sMsg, [
|
||||||
|
'b', 'strong', 'i', 'em', 'u', 'ins', 's', 'strike', 'del', 'span', 'tg-spoiler', 'a', 'tg-emoji',
|
||||||
|
'code', 'pre',
|
||||||
|
]),
|
||||||
|
'parse_mode' => 'HTML',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function msgFormat_markdown()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'chat_id' => $this->iChatId,
|
||||||
|
'text' => $this->sMsg,
|
||||||
|
'parse_mode' => 'Markdown',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function msgFormat_markdownV2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'chat_id' => $this->iChatId,
|
||||||
|
'text' => $this->sMsg,
|
||||||
|
'parse_mode' => 'MarkdownV2',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
361
src/Services/TomTool/Telegram/Slave.php
Executable file
361
src/Services/TomTool/Telegram/Slave.php
Executable file
@ -0,0 +1,361 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// 版本 25/12/12
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\TomTool\Telegram;
|
||||||
|
|
||||||
|
use App\Services\TomTool\HttpV2;
|
||||||
|
use App\Services\TomTool\Telegram\Sdk as ServiceTelegramSdk;
|
||||||
|
use App\Services\TomTool\Flow;
|
||||||
|
use App\Services\HttpQueue as ServiceHttpQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
提醒:
|
||||||
|
master自身已经没有队列了,收到slave消息直接转发
|
||||||
|
|
||||||
|
默认:
|
||||||
|
走本地队列,发送到master
|
||||||
|
走异步
|
||||||
|
|
||||||
|
new:
|
||||||
|
start()
|
||||||
|
log()
|
||||||
|
warn()
|
||||||
|
fail()
|
||||||
|
notify()
|
||||||
|
|
||||||
|
opt:
|
||||||
|
enableMaster(:true)
|
||||||
|
enableMasterQueue(:true)
|
||||||
|
enableSlaveQueue(:true)
|
||||||
|
enableDetail(:true)
|
||||||
|
|
||||||
|
set:
|
||||||
|
setMsgS()
|
||||||
|
setMsgA()
|
||||||
|
setBotCode()
|
||||||
|
setChatCode()
|
||||||
|
setBotToken()
|
||||||
|
setChatId()
|
||||||
|
|
||||||
|
action:
|
||||||
|
send()
|
||||||
|
sendMaster()
|
||||||
|
sendLocal()
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Slave
|
||||||
|
{
|
||||||
|
public string $sBotCode;
|
||||||
|
public string $sChatCode;
|
||||||
|
|
||||||
|
public string $sBotToken = '';
|
||||||
|
public int $iChatId = 0;
|
||||||
|
|
||||||
|
public string $sMsg = '';
|
||||||
|
public string $sPhotoUrl = '';
|
||||||
|
public int $iPhotoWidth = 0;
|
||||||
|
public int $iPhotoHeight = 0;
|
||||||
|
|
||||||
|
public string $sFileUrl = '';
|
||||||
|
public string $sFileName = '';
|
||||||
|
|
||||||
|
public string $sType = '';
|
||||||
|
|
||||||
|
public bool $enableMaster = true;
|
||||||
|
public bool $enableMasterQueue = false; // 这里之前想错了,不会有master队列,只在slave有,master转发就行了
|
||||||
|
public bool $enableSlaveQueue = false;
|
||||||
|
|
||||||
|
public bool $enableDetail = true;
|
||||||
|
|
||||||
|
public bool $enableAsync = false;
|
||||||
|
|
||||||
|
private bool $enableSend = true;
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function start(string $sBotCode = 'base', string $sChatCode = 'base'): self
|
||||||
|
{
|
||||||
|
$oInstance = new self;
|
||||||
|
$oInstance->sBotCode = $sBotCode;
|
||||||
|
$oInstance->sChatCode = $sChatCode;
|
||||||
|
$oInstance->enableSend = filter_var($_ENV["tg_send_enable"] ?? true, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
return $oInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function log(string $sChatCode = 'admin'): self
|
||||||
|
{
|
||||||
|
return self::start("log", $sChatCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function warn(string $sChatCode = 'admin'): self
|
||||||
|
{
|
||||||
|
return self::start("warn", $sChatCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function fail(string $sChatCode = 'admin'): self
|
||||||
|
{
|
||||||
|
return self::start("fail", $sChatCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
public static function notify(string $sChatCode = 'admin'): self
|
||||||
|
{
|
||||||
|
return self::start("fail", $sChatCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// opt
|
||||||
|
public function enableAsync(bool $b = true): self
|
||||||
|
{
|
||||||
|
$this->enableAsync = $b;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opt
|
||||||
|
public function enableDetail(bool $b = true): self
|
||||||
|
{
|
||||||
|
$this->enableDetail = $b;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opt
|
||||||
|
public function enableSlaveQueue(bool $b = true): self
|
||||||
|
{
|
||||||
|
$this->enableSlaveQueue = $b;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opt
|
||||||
|
public function enableMaster(bool $b = true): self
|
||||||
|
{
|
||||||
|
$this->enableMaster = $b;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opt
|
||||||
|
public function enableMasterQueue(bool $b = true): self
|
||||||
|
{
|
||||||
|
$this->enableMasterQueue = $b;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setPhotoUrl(string $sPhotoUrl, int $iWidth = 0, int $iHeight = 0): self
|
||||||
|
{
|
||||||
|
$this->sPhotoUrl = $sPhotoUrl;
|
||||||
|
$this->iPhotoWidth = $iWidth;
|
||||||
|
$this->iPhotoHeight = $iHeight;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setFileUrl(string $sFileUrl, string $sFileName = ''): self
|
||||||
|
{
|
||||||
|
$this->sFileUrl = $sFileUrl;
|
||||||
|
$this->sFileName = $sFileName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setType(string $sType): self
|
||||||
|
{
|
||||||
|
$this->sType = $sType;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setMsgS(string $sMsg = ''): self
|
||||||
|
{
|
||||||
|
if ($this->enableDetail) {
|
||||||
|
$sMsg = "[ ".$this->getEnvSiteCode()." | ".date("d:H:i:s")." ] ".$sMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sMsg = $sMsg;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setMsgA(array $aMsg = []): self
|
||||||
|
{
|
||||||
|
$aMsgNew = $aMsg;
|
||||||
|
|
||||||
|
if ($this->enableDetail) {
|
||||||
|
$aMsgNew = [];
|
||||||
|
$aMsgNew["site_code"] = $this->getEnvSiteCode();
|
||||||
|
$aMsgNew["date"] = date("Y-m-d H:i:s");
|
||||||
|
$aMsgNew["data"] = $aMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sMsg = json_encode($aMsgNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setBotCode(string $sBotCode): self
|
||||||
|
{
|
||||||
|
$this->sBotCode = $sBotCode;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setChatCode(string $sChatCode): self
|
||||||
|
{
|
||||||
|
$this->sChatCode = $sChatCode;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setBotToken(string $sBotToken): self
|
||||||
|
{
|
||||||
|
$this->sBotToken = $sBotToken;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
public function setChatId(int $iChatId): self
|
||||||
|
{
|
||||||
|
$this->iChatId = $iChatId;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function send($xMsg = ''): Flow
|
||||||
|
{
|
||||||
|
if ($this->enableSend == false) {
|
||||||
|
$oFlow = Flow::start();
|
||||||
|
return $oFlow->done("不发送");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($xMsg) {
|
||||||
|
if (is_array($xMsg)) {
|
||||||
|
$this->setMsgA($xMsg);
|
||||||
|
} else {
|
||||||
|
$this->setMsgS($xMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->sMsg) {
|
||||||
|
// throw new \Exception("未设置msg");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->enableMaster) {
|
||||||
|
$oFlow = $this->_send_master();
|
||||||
|
} else {
|
||||||
|
$oFlow = $this->_send_local();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $oFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function sendMaster($xMsg = ''): Flow
|
||||||
|
{
|
||||||
|
$this->enableMaster(true);
|
||||||
|
return $this->send($xMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// action
|
||||||
|
public function sendLocal($xMsg = ''): Flow
|
||||||
|
{
|
||||||
|
$this->enableMaster(false);
|
||||||
|
return $this->send($xMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _send_master(): Flow
|
||||||
|
{
|
||||||
|
$aData = $this->buildDataTom();
|
||||||
|
|
||||||
|
if ($this->enableSlaveQueue) {
|
||||||
|
$oFlow = ServiceHttpQueue::start("telegram_master")->arg($aData)->save();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$oFlow = Flow::start("_send_master");
|
||||||
|
$sUrlMaSterBase = $_ENV["url_master_base"] ?? "";
|
||||||
|
|
||||||
|
if (!$sUrlMaSterBase) {
|
||||||
|
throw new \Exception("未设置env的url_master_base");
|
||||||
|
}
|
||||||
|
|
||||||
|
$sUrlMasterPost = "https://".$sUrlMaSterBase."/api/telegram/post";
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$oHttpV2 = HttpV2::make($sUrlMasterPost);
|
||||||
|
|
||||||
|
if ($this->enableAsync) {
|
||||||
|
$oHttpV2 = $oHttpV2->enableAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = $oHttpV2->enableJsonAs()->setData($aData)->send();
|
||||||
|
|
||||||
|
if ($this->enableAsync) {
|
||||||
|
return $oFlow->sData("async")->done("async");
|
||||||
|
} else {
|
||||||
|
$a = json_decode($r, true);
|
||||||
|
$isDone = $a["isDone"] ?? false;
|
||||||
|
|
||||||
|
if ($isDone) {
|
||||||
|
return $oFlow->done();
|
||||||
|
} else {
|
||||||
|
return $oFlow->fail($r);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$oFlow = $oFlow->fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $oFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接从本地发到tg,几乎用不上,都走master了
|
||||||
|
private function _send_local(): Flow
|
||||||
|
{
|
||||||
|
if ($this->enableSlaveQueue) {
|
||||||
|
$aData = $this->buildDataTom();
|
||||||
|
$oFlow = ServiceHttpQueue::start("telegram_local")->arg($aData)->save();
|
||||||
|
} else {
|
||||||
|
$oFlow = ServiceTelegramSdk::start($this->sBotToken, $this->iChatId)->setMsgS($this->sMsg)->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $oFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildDataTom(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"sBotCode" => $this->sBotCode ?? '',
|
||||||
|
"sChatCode" => $this->sChatCode ?? '',
|
||||||
|
"sBotToken" => $this->sBotToken ?? '',
|
||||||
|
"iChatId" => $this->iChatId ?? '',
|
||||||
|
"enableMasterQueue" => $this->enableMasterQueue ?? '',
|
||||||
|
"enableMaster" => $this->enableMaster,
|
||||||
|
"sMsg" => $this->sMsg ?? '',
|
||||||
|
"sPhotoUrl" => $this->sPhotoUrl ?? '',
|
||||||
|
"iPhotoWidth" => $this->iPhotoWidth ?? 0,
|
||||||
|
"iPhotoHeight" => $this->iPhotoHeight ?? 0,
|
||||||
|
"sType" => $this->sType ?? '',
|
||||||
|
"sFileUrl" => $this->sFileUrl ?? '',
|
||||||
|
"sFileName" => $this->sFileName ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getEnvSiteCode(): string
|
||||||
|
{
|
||||||
|
$sEnvSiteCode = $_ENV["site_code"] ?? "未设置env的site_code";
|
||||||
|
|
||||||
|
return $sEnvSiteCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
121
src/Services/TomTool/TelegramV2.php
Executable file
121
src/Services/TomTool/TelegramV2.php
Executable file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\IM;
|
||||||
|
|
||||||
|
use App\Models\Config;
|
||||||
|
use Telegram\Bot\Api;
|
||||||
|
use Telegram\Bot\Exceptions\TelegramSDKException;
|
||||||
|
use function strip_tags;
|
||||||
|
|
||||||
|
// 没有必须,默认使用base配置
|
||||||
|
final class TelegramV2
|
||||||
|
{
|
||||||
|
private Api $bot;
|
||||||
|
public $iTo;
|
||||||
|
public $sToken;
|
||||||
|
public $sMsgType = false;
|
||||||
|
|
||||||
|
public function __construct($sToken = "base", $sTo = "base")
|
||||||
|
{
|
||||||
|
$this->setToken($sToken);
|
||||||
|
|
||||||
|
$this->setTo($sTo);
|
||||||
|
|
||||||
|
// $this->bot = new Api($this->sToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMsgType($sMsgType)
|
||||||
|
{
|
||||||
|
$this->sMsgType = $sMsgType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTo($xTo, $sType = "code")
|
||||||
|
{
|
||||||
|
$iChatId = $xTo;
|
||||||
|
|
||||||
|
if ($sType == "code") {
|
||||||
|
// $sEnvKey = "tgChat_".$xTo;
|
||||||
|
$iChatId = $_ENV['tgChat'][$iChatId];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->iTo = $iChatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setToken($xToken, $sType = "code")
|
||||||
|
{
|
||||||
|
$sToken = $xToken;
|
||||||
|
|
||||||
|
if ($sType == "code") {
|
||||||
|
// $sEnvKey = "tgToken_".$xToken;
|
||||||
|
$sToken = $_ENV['tgToken'][$sToken];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sToken = $sToken;
|
||||||
|
|
||||||
|
$this->bot = new Api($this->sToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send($sMsg, $sMsgType = 'str')
|
||||||
|
{
|
||||||
|
if ($sMsgType == "arr") {
|
||||||
|
$sMsg = json_encode($sMsg, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->sMsgType === false) {
|
||||||
|
$sendMessage = [
|
||||||
|
'chat_id' => $this->iTo,
|
||||||
|
'text' => $sMsg,
|
||||||
|
'parse_mode' => '',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
} else if ($this->sMsgType === "html") {
|
||||||
|
$sendMessage = [
|
||||||
|
'chat_id' => $this->iTo,
|
||||||
|
'text' => strip_tags(
|
||||||
|
$sMsg,
|
||||||
|
['b', 'strong', 'i', 'em', 'u', 'ins', 's', 'strike','del', 'span','tg-spoiler', 'a', 'tg-emoji',
|
||||||
|
'code', 'pre',
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'parse_mode' => 'HTML',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
} else if ($this->sMsgType === "markdown") {
|
||||||
|
$sendMessage = [
|
||||||
|
'chat_id' => $this->iTo,
|
||||||
|
'text' => $sMsg,
|
||||||
|
'parse_mode' => 'Markdown',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
} else if ($this->sMsgType === "markdownV2") {
|
||||||
|
$sendMessage = [
|
||||||
|
'chat_id' => $this->iTo,
|
||||||
|
'text' => $sMsg,
|
||||||
|
'parse_mode' => 'MarkdownV2',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$sendMessage = [
|
||||||
|
'chat_id' => $this->iTo,
|
||||||
|
'text' => $sMsg,
|
||||||
|
'parse_mode' => '',
|
||||||
|
'disable_web_page_preview' => false,
|
||||||
|
'reply_to_message_id' => null,
|
||||||
|
'reply_markup' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->bot->sendMessage($sendMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user