修复越权

This commit is contained in:
taoser 2023-03-16 22:35:59 +08:00
parent 9c83c4d0cd
commit 88275662c3
52 changed files with 701 additions and 477 deletions

View File

@ -557,9 +557,7 @@ class Addons extends AdminController
$data = Request::only(['id','name','version','uid','price']); $data = Request::only(['id','name','version','uid','price']);
// $url = $this->getSystem()['api_url'].'/v1/createOrder'; // $url = $this->getSystem()['api_url'].'/v1/createOrder';
// $order = Api::urlPost($url,$data); // $order = Api::urlPost($url,$data);
$response = HttpHelper::withHost()->post('/v1/createOrder', $data); $response = HttpHelper::withHost()->post('/v1/createOrder', $data);
if ($response->ok()) { if ($response->ok()) {
// $orderData = json_decode(json_encode($response->toJson()->data),TRUE); // $orderData = json_decode(json_encode($response->toJson()->data),TRUE);
View::assign('orderData',$response->toArray()['data']); View::assign('orderData',$response->toArray()['data']);

View File

@ -66,7 +66,7 @@
//上传头像 //上传头像
upload.render({ upload.render({
elem: '.upload-select' elem: '.upload-select'
,url: 'uploads' ,url: "{:url('Addons/uploads')}"
,data: {type:'image'} ,data: {type:'image'}
,accept: 'images' ,accept: 'images'
,method: 'get' ,method: 'get'

View File

@ -153,8 +153,7 @@ class User extends Model
//更新设置 //更新设置
public function setNew($data) public function setNew($data)
{ {
$userId = $data['user_id']; $user = User::where('id', session('user_id'))->find();
$user = User::where('id',$userId)->find();
$result = $user->allowField(['email','active','nickname','sex','city','area_id','sign'])->save($data); $result = $user->allowField(['email','active','nickname','sex','city','area_id','sign'])->save($data);
if($result){ if($result){
return 1; return 1;

View File

@ -241,7 +241,8 @@ class Article extends BaseController
// 检验发帖是否开放 // 检验发帖是否开放
if(config('taoler.config.is_post') == 0 ) return json(['code'=>-1,'msg'=>'抱歉,系统维护中,暂时禁止发帖!']); if(config('taoler.config.is_post') == 0 ) return json(['code'=>-1,'msg'=>'抱歉,系统维护中,暂时禁止发帖!']);
// 数据 // 数据
$data = Request::only(['cate_id', 'title', 'title_color', 'user_id', 'content', 'upzip', 'keywords', 'description', 'captcha']); $data = Request::only(['cate_id', 'title', 'title_color', 'content', 'upzip', 'keywords', 'description', 'captcha']);
$data['user_id'] = $this->uid;
$tagId = input('tagid'); $tagId = input('tagid');
// 验证码 // 验证码
@ -340,6 +341,7 @@ class Article extends BaseController
if(Request::isAjax()){ if(Request::isAjax()){
$data = Request::only(['id','cate_id','title','title_color','user_id','content','upzip','keywords','description','captcha']); $data = Request::only(['id','cate_id','title','title_color','user_id','content','upzip','keywords','description','captcha']);
$data['user_id'] = $this->uid;
$tagId = input('tagid'); $tagId = input('tagid');
// 验证码 // 验证码

View File

@ -119,7 +119,8 @@ class User extends BaseController
public function set() public function set()
{ {
if(Request::isAjax()){ if(Request::isAjax()){
$data = Request::only(['user_id','email','nickname','sex','city','area_id','sign']); $data = Request::only(['email','nickname','sex','city','area_id','sign']);
$data['user_id'] = $this->uid;
// 过滤 // 过滤
$sign = strtolower($data['sign']); $sign = strtolower($data['sign']);
if(strstr($sign, 'script')) return json(['code'=>-1,'msg'=>'包含有非法字符串script脚本']); if(strstr($sign, 'script')) return json(['code'=>-1,'msg'=>'包含有非法字符串script脚本']);

84
composer.lock generated
View File

@ -8,16 +8,16 @@
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
"version": "2.0.7", "version": "2.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git", "url": "https://github.com/Bacon/BaconQrCode.git",
"reference": "d70c840f68657ce49094b8d91f9ee0cc07fbf66c" "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/d70c840f68657ce49094b8d91f9ee0cc07fbf66c", "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22",
"reference": "d70c840f68657ce49094b8d91f9ee0cc07fbf66c", "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -62,9 +62,9 @@
"homepage": "https://github.com/Bacon/BaconQrCode", "homepage": "https://github.com/Bacon/BaconQrCode",
"support": { "support": {
"issues": "https://github.com/Bacon/BaconQrCode/issues", "issues": "https://github.com/Bacon/BaconQrCode/issues",
"source": "https://github.com/Bacon/BaconQrCode/tree/2.0.7" "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8"
}, },
"time": "2022-03-14T02:02:36+00:00" "time": "2022-12-07T17:46:57+00:00"
}, },
{ {
"name": "cache/adapter-common", "name": "cache/adapter-common",
@ -1488,16 +1488,16 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.6.4", "version": "v6.7.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b" "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/49cd7ea3d2563f028d7811f06864a53b1f15ff55",
"reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b", "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1513,22 +1513,24 @@
"php": ">=5.5.0" "php": ">=5.5.0"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.6.2", "squizlabs/php_codesniffer": "^3.7.1",
"yoast/phpunit-polyfills": "^1.0.0" "yoast/phpunit-polyfills": "^1.0.4"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging", "psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -1560,7 +1562,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.7.1"
}, },
"funding": [ "funding": [
{ {
@ -1568,7 +1570,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-08-22T09:22:00+00:00" "time": "2022-12-08T13:30:06+00:00"
}, },
{ {
"name": "psr/cache", "name": "psr/cache",
@ -2372,16 +2374,16 @@
}, },
{ {
"name": "symfony/var-exporter", "name": "symfony/var-exporter",
"version": "v5.4.10", "version": "v5.4.17",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-exporter.git", "url": "https://github.com/symfony/var-exporter.git",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340" "reference": "2adac0a9b55f9fb40b983b790509581dc3db0fff"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340", "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2adac0a9b55f9fb40b983b790509581dc3db0fff",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340", "reference": "2adac0a9b55f9fb40b983b790509581dc3db0fff",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2431,7 +2433,7 @@
"serialize" "serialize"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-exporter/tree/v5.4.10" "source": "https://github.com/symfony/var-exporter/tree/v5.4.17"
}, },
"funding": [ "funding": [
{ {
@ -2447,7 +2449,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-05-27T12:56:18+00:00" "time": "2022-12-22T10:10:04+00:00"
}, },
{ {
"name": "taoser/think-addons", "name": "taoser/think-addons",
@ -3026,16 +3028,16 @@
}, },
{ {
"name": "topthink/think-orm", "name": "topthink/think-orm",
"version": "v2.0.54", "version": "v2.0.56",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-orm.git", "url": "https://github.com/top-think/think-orm.git",
"reference": "97b061b47616301ff29fbd4c35ed9184e1162e4e" "reference": "75b8512736daaa056d511f42c15bed87c9f3605a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/97b061b47616301ff29fbd4c35ed9184e1162e4e", "url": "https://api.github.com/repos/top-think/think-orm/zipball/75b8512736daaa056d511f42c15bed87c9f3605a",
"reference": "97b061b47616301ff29fbd4c35ed9184e1162e4e", "reference": "75b8512736daaa056d511f42c15bed87c9f3605a",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3081,9 +3083,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/top-think/think-orm/issues", "issues": "https://github.com/top-think/think-orm/issues",
"source": "https://github.com/top-think/think-orm/tree/v2.0.54" "source": "https://github.com/top-think/think-orm/tree/v2.0.56"
}, },
"time": "2022-07-05T05:25:51+00:00" "time": "2022-12-15T02:52:53+00:00"
}, },
{ {
"name": "topthink/think-template", "name": "topthink/think-template",
@ -3326,16 +3328,16 @@
}, },
{ {
"name": "workerman/workerman", "name": "workerman/workerman",
"version": "v4.1.4", "version": "v4.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/walkor/workerman.git", "url": "https://github.com/walkor/workerman.git",
"reference": "83e007acf936e2233ac92d7368b87716f2bae338" "reference": "16bcfc2c7574feea46cdadaaa8ae73f14d464b21"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/walkor/workerman/zipball/83e007acf936e2233ac92d7368b87716f2bae338", "url": "https://api.github.com/repos/walkor/workerman/zipball/16bcfc2c7574feea46cdadaaa8ae73f14d464b21",
"reference": "83e007acf936e2233ac92d7368b87716f2bae338", "reference": "16bcfc2c7574feea46cdadaaa8ae73f14d464b21",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3391,7 +3393,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2022-10-09T11:33:14+00:00" "time": "2022-12-14T11:58:06+00:00"
}, },
{ {
"name": "yansongda/pay", "name": "yansongda/pay",
@ -3545,16 +3547,16 @@
}, },
{ {
"name": "yzh52521/easyhttp", "name": "yzh52521/easyhttp",
"version": "v1.0.4", "version": "v1.0.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/yzh52521/easyhttp.git", "url": "https://github.com/yzh52521/easyhttp.git",
"reference": "e34628f8f90295cf0a19e5cd2bcc4dd19000373b" "reference": "a74fa5a1d4f701bd20e581b0731e885aac3daf9f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/yzh52521/easyhttp/zipball/e34628f8f90295cf0a19e5cd2bcc4dd19000373b", "url": "https://api.github.com/repos/yzh52521/easyhttp/zipball/a74fa5a1d4f701bd20e581b0731e885aac3daf9f",
"reference": "e34628f8f90295cf0a19e5cd2bcc4dd19000373b", "reference": "a74fa5a1d4f701bd20e581b0731e885aac3daf9f",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3597,9 +3599,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/yzh52521/easyhttp/issues", "issues": "https://github.com/yzh52521/easyhttp/issues",
"source": "https://github.com/yzh52521/easyhttp/tree/v1.0.4" "source": "https://github.com/yzh52521/easyhttp/tree/v1.0.5"
}, },
"time": "2022-11-10T01:24:11+00:00" "time": "2022-12-05T12:18:34+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [

View File

@ -16,7 +16,7 @@ return [
// 应用名,此项不可更改 // 应用名,此项不可更改
'appname' => 'TaoLer', 'appname' => 'TaoLer',
// 版本配置 // 版本配置
'version' => '2.1.1', 'version' => '2.1.3',
// 加盐 // 加盐
'salt' => 'taoler', 'salt' => 'taoler',
// 数据库备份目录 // 数据库备份目录

View File

@ -106,7 +106,7 @@ layui.define(["table", "form", "upload","notify","hxNav"], function (exports) {
layer.close(index); layer.close(index);
layer.open({ layer.open({
type: 2, type: 2,
area: ['50%', '65%'], area: ['55%', '75%'],
fixed: false, //不固定 fixed: false, //不固定
maxmin: true, maxmin: true,
content: 'pay.html'+ "?id=" + data.id+ "&name=" + data.name + "&version=" + data.version + "&uid=" + userinfo.uid + "&price=" + data.price, content: 'pay.html'+ "?id=" + data.id+ "&name=" + data.name + "&version=" + data.version + "&uid=" + userinfo.uid + "&price=" + data.price,

View File

@ -34,5 +34,11 @@
"allow-plugins": { "allow-plugins": {
"ocramius/package-versions": true "ocramius/package-versions": true
} }
},
"archive": {
"exclude": [
"/test",
"/phpunit.xml.dist"
]
} }
} }

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<testsuites>
<testsuite name="BaconQrCode Tests">
<directory>./test</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@ -89,6 +89,9 @@ final class CharacterSetEci extends AbstractEnum
*/ */
private static $nameToEci; private static $nameToEci;
/**
* @param int[] $values
*/
public function __construct(array $values, string ...$otherEncodingNames) public function __construct(array $values, string ...$otherEncodingNames)
{ {
$this->values = $values; $this->values = $values;

View File

@ -62,7 +62,7 @@ class FormatInformation
/** /**
* Offset i holds the number of 1 bits in the binary representation of i. * Offset i holds the number of 1 bits in the binary representation of i.
* *
* @var array * @var int[]
*/ */
private const BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]; private const BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];

View File

@ -42,6 +42,9 @@ final class Mode extends AbstractEnum
*/ */
private $bits; private $bits;
/**
* @param int[] $characterCountBitsForVersions
*/
protected function __construct(array $characterCountBitsForVersions, int $bits) protected function __construct(array $characterCountBitsForVersions, int $bits)
{ {
$this->characterCountBitsForVersions = $characterCountBitsForVersions; $this->characterCountBitsForVersions = $characterCountBitsForVersions;

View File

@ -37,7 +37,7 @@ final class Encoder
/** /**
* Codec cache. * Codec cache.
* *
* @var array * @var array<string,ReedSolomonCodec>
*/ */
private static $codecs = []; private static $codecs = [];

View File

@ -334,7 +334,7 @@ final class SvgImageBackEnd implements ImageBackEndInterface
$this->xmlWriter->writeAttribute('stop-color', $this->getColorString($startColor)); $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($startColor));
if ($startColor instanceof Alpha) { if ($startColor instanceof Alpha) {
$this->xmlWriter->writeAttribute('stop-opacity', $startColor->getAlpha()); $this->xmlWriter->writeAttribute('stop-opacity', (string) $startColor->getAlpha());
} }
$this->xmlWriter->endElement(); $this->xmlWriter->endElement();
@ -344,7 +344,7 @@ final class SvgImageBackEnd implements ImageBackEndInterface
$this->xmlWriter->writeAttribute('stop-color', $this->getColorString($endColor)); $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($endColor));
if ($endColor instanceof Alpha) { if ($endColor instanceof Alpha) {
$this->xmlWriter->writeAttribute('stop-opacity', $endColor->getAlpha()); $this->xmlWriter->writeAttribute('stop-opacity', (string) $endColor->getAlpha());
} }
$this->xmlWriter->endElement(); $this->xmlWriter->endElement();

View File

@ -41,7 +41,7 @@ final class EdgeIterator implements IteratorAggregate
} }
/** /**
* @return Edge[] * @return Traversable<Edge>
*/ */
public function getIterator() : Traversable public function getIterator() : Traversable
{ {

View File

@ -136,7 +136,7 @@ final class EllipticArc implements OperationInterface
/** /**
* @return Curve[] * @return Curve[]
*/ */
private function createCurves(float $fromX, $fromY) : array private function createCurves(float $fromX, float $fromY) : array
{ {
$xAngle = deg2rad($this->xAxisAngle); $xAngle = deg2rad($this->xAxisAngle);
list($centerX, $centerY, $radiusX, $radiusY, $startAngle, $deltaAngle) = list($centerX, $centerY, $radiusX, $radiusY, $startAngle, $deltaAngle) =

View File

@ -17,10 +17,16 @@ use BaconQrCode\Writer;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Spatie\Snapshots\MatchesSnapshots; use Spatie\Snapshots\MatchesSnapshots;
/**
* @group integration
*/
final class ImagickRenderingTest extends TestCase final class ImagickRenderingTest extends TestCase
{ {
use MatchesSnapshots; use MatchesSnapshots;
/**
* @requires extension imagick
*/
public function testGenericQrCode() : void public function testGenericQrCode() : void
{ {
$renderer = new ImageRenderer( $renderer = new ImageRenderer(
@ -35,6 +41,9 @@ final class ImagickRenderingTest extends TestCase
unlink($tempName); unlink($tempName);
} }
/**
* @requires extension imagick
*/
public function testIssue79() : void public function testIssue79() : void
{ {
$eye = SquareEye::instance(); $eye = SquareEye::instance();

View File

@ -14,7 +14,7 @@ return array(
'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'), 'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'), 'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'), 'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src'), 'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-orm/src'),
'taoser\\think\\' => array($vendorDir . '/taoser/think-auth/src'), 'taoser\\think\\' => array($vendorDir . '/taoser/think-auth/src'),
'taoser\\' => array($vendorDir . '/taoser/think-addons/src', $vendorDir . '/taoser/think-setarr/src'), 'taoser\\' => array($vendorDir . '/taoser/think-addons/src', $vendorDir . '/taoser/think-setarr/src'),
'phpspirit\\databackup\\' => array($vendorDir . '/lotofbadcode/phpspirit_databackup/src'), 'phpspirit\\databackup\\' => array($vendorDir . '/lotofbadcode/phpspirit_databackup/src'),

View File

@ -182,8 +182,8 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2
array ( array (
0 => __DIR__ . '/..' . '/topthink/framework/src/think', 0 => __DIR__ . '/..' . '/topthink/framework/src/think',
1 => __DIR__ . '/..' . '/topthink/think-helper/src', 1 => __DIR__ . '/..' . '/topthink/think-helper/src',
2 => __DIR__ . '/..' . '/topthink/think-orm/src', 2 => __DIR__ . '/..' . '/topthink/think-template/src',
3 => __DIR__ . '/..' . '/topthink/think-template/src', 3 => __DIR__ . '/..' . '/topthink/think-orm/src',
), ),
'taoser\\think\\' => 'taoser\\think\\' =>
array ( array (

View File

@ -2,18 +2,24 @@
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
"version": "2.0.7", "version": "2.0.8",
"version_normalized": "2.0.7.0", "version_normalized": "2.0.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git", "url": "https://github.com/Bacon/BaconQrCode.git",
"reference": "d70c840f68657ce49094b8d91f9ee0cc07fbf66c" "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/d70c840f68657ce49094b8d91f9ee0cc07fbf66c", "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22",
"reference": "d70c840f68657ce49094b8d91f9ee0cc07fbf66c", "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22",
"shasum": "" "shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
}, },
"require": { "require": {
"dasprid/enum": "^1.0.3", "dasprid/enum": "^1.0.3",
@ -29,7 +35,7 @@
"suggest": { "suggest": {
"ext-imagick": "to generate QR code images" "ext-imagick": "to generate QR code images"
}, },
"time": "2022-03-14T02:02:36+00:00", "time": "2022-12-07T17:46:57+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -53,7 +59,7 @@
"homepage": "https://github.com/Bacon/BaconQrCode", "homepage": "https://github.com/Bacon/BaconQrCode",
"support": { "support": {
"issues": "https://github.com/Bacon/BaconQrCode/issues", "issues": "https://github.com/Bacon/BaconQrCode/issues",
"source": "https://github.com/Bacon/BaconQrCode/tree/2.0.7" "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8"
}, },
"install-path": "../bacon/bacon-qr-code" "install-path": "../bacon/bacon-qr-code"
}, },
@ -1437,17 +1443,17 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.6.4", "version": "v6.7.1",
"version_normalized": "6.6.4.0", "version_normalized": "6.7.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b" "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/49cd7ea3d2563f028d7811f06864a53b1f15ff55",
"reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b", "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1463,24 +1469,26 @@
"php": ">=5.5.0" "php": ">=5.5.0"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.6.2", "squizlabs/php_codesniffer": "^3.7.1",
"yoast/phpunit-polyfills": "^1.0.0" "yoast/phpunit-polyfills": "^1.0.4"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging", "psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
}, },
"time": "2022-08-22T09:22:00+00:00", "time": "2022-12-08T13:30:06+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -1512,7 +1520,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.7.1"
}, },
"funding": [ "funding": [
{ {
@ -2336,18 +2344,24 @@
}, },
{ {
"name": "symfony/var-exporter", "name": "symfony/var-exporter",
"version": "v5.4.10", "version": "v5.4.17",
"version_normalized": "5.4.10.0", "version_normalized": "5.4.17.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-exporter.git", "url": "https://github.com/symfony/var-exporter.git",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340" "reference": "2adac0a9b55f9fb40b983b790509581dc3db0fff"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340", "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2adac0a9b55f9fb40b983b790509581dc3db0fff",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340", "reference": "2adac0a9b55f9fb40b983b790509581dc3db0fff",
"shasum": "" "shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
@ -2356,7 +2370,7 @@
"require-dev": { "require-dev": {
"symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
}, },
"time": "2022-05-27T12:56:18+00:00", "time": "2022-12-22T10:10:04+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -2392,7 +2406,7 @@
"serialize" "serialize"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-exporter/tree/v5.4.10" "source": "https://github.com/symfony/var-exporter/tree/v5.4.17"
}, },
"funding": [ "funding": [
{ {
@ -2983,17 +2997,17 @@
}, },
{ {
"name": "topthink/think-orm", "name": "topthink/think-orm",
"version": "v2.0.54", "version": "v2.0.56",
"version_normalized": "2.0.54.0", "version_normalized": "2.0.56.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-orm.git", "url": "https://github.com/top-think/think-orm.git",
"reference": "97b061b47616301ff29fbd4c35ed9184e1162e4e" "reference": "75b8512736daaa056d511f42c15bed87c9f3605a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/97b061b47616301ff29fbd4c35ed9184e1162e4e", "url": "https://api.github.com/repos/top-think/think-orm/zipball/75b8512736daaa056d511f42c15bed87c9f3605a",
"reference": "97b061b47616301ff29fbd4c35ed9184e1162e4e", "reference": "75b8512736daaa056d511f42c15bed87c9f3605a",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3013,7 +3027,7 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7|^8|^9.5" "phpunit/phpunit": "^7|^8|^9.5"
}, },
"time": "2022-07-05T05:25:51+00:00", "time": "2022-12-15T02:52:53+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -3041,7 +3055,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/top-think/think-orm/issues", "issues": "https://github.com/top-think/think-orm/issues",
"source": "https://github.com/top-think/think-orm/tree/v2.0.54" "source": "https://github.com/top-think/think-orm/tree/v2.0.56"
}, },
"install-path": "../topthink/think-orm" "install-path": "../topthink/think-orm"
}, },
@ -3345,17 +3359,17 @@
}, },
{ {
"name": "workerman/workerman", "name": "workerman/workerman",
"version": "v4.1.4", "version": "v4.1.5",
"version_normalized": "4.1.4.0", "version_normalized": "4.1.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/walkor/workerman.git", "url": "https://github.com/walkor/workerman.git",
"reference": "83e007acf936e2233ac92d7368b87716f2bae338" "reference": "16bcfc2c7574feea46cdadaaa8ae73f14d464b21"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/walkor/workerman/zipball/83e007acf936e2233ac92d7368b87716f2bae338", "url": "https://api.github.com/repos/walkor/workerman/zipball/16bcfc2c7574feea46cdadaaa8ae73f14d464b21",
"reference": "83e007acf936e2233ac92d7368b87716f2bae338", "reference": "16bcfc2c7574feea46cdadaaa8ae73f14d464b21",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3370,7 +3384,7 @@
"suggest": { "suggest": {
"ext-event": "For better performance. " "ext-event": "For better performance. "
}, },
"time": "2022-10-09T11:33:14+00:00", "time": "2022-12-14T11:58:06+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -3561,17 +3575,17 @@
}, },
{ {
"name": "yzh52521/easyhttp", "name": "yzh52521/easyhttp",
"version": "v1.0.4", "version": "v1.0.5",
"version_normalized": "1.0.4.0", "version_normalized": "1.0.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/yzh52521/easyhttp.git", "url": "https://github.com/yzh52521/easyhttp.git",
"reference": "e34628f8f90295cf0a19e5cd2bcc4dd19000373b" "reference": "a74fa5a1d4f701bd20e581b0731e885aac3daf9f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/yzh52521/easyhttp/zipball/e34628f8f90295cf0a19e5cd2bcc4dd19000373b", "url": "https://api.github.com/repos/yzh52521/easyhttp/zipball/a74fa5a1d4f701bd20e581b0731e885aac3daf9f",
"reference": "e34628f8f90295cf0a19e5cd2bcc4dd19000373b", "reference": "a74fa5a1d4f701bd20e581b0731e885aac3daf9f",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3585,7 +3599,7 @@
"php": "^7.2.5|^8.0", "php": "^7.2.5|^8.0",
"psr/log": "^1.0|^2.0|^3.0" "psr/log": "^1.0|^2.0|^3.0"
}, },
"time": "2022-11-10T01:24:11+00:00", "time": "2022-12-05T12:18:34+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -3616,7 +3630,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/yzh52521/easyhttp/issues", "issues": "https://github.com/yzh52521/easyhttp/issues",
"source": "https://github.com/yzh52521/easyhttp/tree/v1.0.4" "source": "https://github.com/yzh52521/easyhttp/tree/v1.0.5"
}, },
"install-path": "../yzh52521/easyhttp" "install-path": "../yzh52521/easyhttp"
} }

View File

@ -3,7 +3,7 @@
'name' => 'taoser/taoler', 'name' => 'taoser/taoler',
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => 'e3f1590beb50ab5826fd410fd37264870b5967f4', 'reference' => '09978bd07a1c769bc266ff2cb0c8c639bc3d41e8',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@ -11,9 +11,9 @@
), ),
'versions' => array( 'versions' => array(
'bacon/bacon-qr-code' => array( 'bacon/bacon-qr-code' => array(
'pretty_version' => '2.0.7', 'pretty_version' => '2.0.8',
'version' => '2.0.7.0', 'version' => '2.0.8.0',
'reference' => 'd70c840f68657ce49094b8d91f9ee0cc07fbf66c', 'reference' => '8674e51bb65af933a5ffaf1c308a660387c35c22',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../bacon/bacon-qr-code', 'install_path' => __DIR__ . '/../bacon/bacon-qr-code',
'aliases' => array(), 'aliases' => array(),
@ -200,9 +200,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'phpmailer/phpmailer' => array( 'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.6.4', 'pretty_version' => 'v6.7.1',
'version' => '6.6.4.0', 'version' => '6.7.1.0',
'reference' => 'a94fdebaea6bd17f51be0c2373ab80d3d681269b', 'reference' => '49cd7ea3d2563f028d7811f06864a53b1f15ff55',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer', 'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(), 'aliases' => array(),
@ -347,9 +347,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/var-exporter' => array( 'symfony/var-exporter' => array(
'pretty_version' => 'v5.4.10', 'pretty_version' => 'v5.4.17',
'version' => '5.4.10.0', 'version' => '5.4.17.0',
'reference' => '8fc03ee75eeece3d9be1ef47d26d79bea1afb340', 'reference' => '2adac0a9b55f9fb40b983b790509581dc3db0fff',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-exporter', 'install_path' => __DIR__ . '/../symfony/var-exporter',
'aliases' => array(), 'aliases' => array(),
@ -358,7 +358,7 @@
'taoser/taoler' => array( 'taoser/taoler' => array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => 'e3f1590beb50ab5826fd410fd37264870b5967f4', 'reference' => '09978bd07a1c769bc266ff2cb0c8c639bc3d41e8',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@ -455,9 +455,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-orm' => array( 'topthink/think-orm' => array(
'pretty_version' => 'v2.0.54', 'pretty_version' => 'v2.0.56',
'version' => '2.0.54.0', 'version' => '2.0.56.0',
'reference' => '97b061b47616301ff29fbd4c35ed9184e1162e4e', 'reference' => '75b8512736daaa056d511f42c15bed87c9f3605a',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-orm', 'install_path' => __DIR__ . '/../topthink/think-orm',
'aliases' => array(), 'aliases' => array(),
@ -518,9 +518,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'workerman/workerman' => array( 'workerman/workerman' => array(
'pretty_version' => 'v4.1.4', 'pretty_version' => 'v4.1.5',
'version' => '4.1.4.0', 'version' => '4.1.5.0',
'reference' => '83e007acf936e2233ac92d7368b87716f2bae338', 'reference' => '16bcfc2c7574feea46cdadaaa8ae73f14d464b21',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../workerman/workerman', 'install_path' => __DIR__ . '/../workerman/workerman',
'aliases' => array(), 'aliases' => array(),
@ -545,9 +545,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'yzh52521/easyhttp' => array( 'yzh52521/easyhttp' => array(
'pretty_version' => 'v1.0.4', 'pretty_version' => 'v1.0.5',
'version' => '1.0.4.0', 'version' => '1.0.5.0',
'reference' => 'e34628f8f90295cf0a19e5cd2bcc4dd19000373b', 'reference' => 'a74fa5a1d4f701bd20e581b0731e885aac3daf9f',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../yzh52521/easyhttp', 'install_path' => __DIR__ . '/../yzh52521/easyhttp',
'aliases' => array(), 'aliases' => array(),

View File

@ -16,7 +16,7 @@
- Probably the world's most popular code for sending email from PHP! - Probably the world's most popular code for sending email from PHP!
- Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more - Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more
- Integrated SMTP support send without a local mail server - Integrated SMTP support send without a local mail server
- Send emails with multiple To, CC, BCC and Reply-to addresses - Send emails with multiple To, CC, BCC, and Reply-to addresses
- Multipart/alternative emails for mail clients that do not read HTML email - Multipart/alternative emails for mail clients that do not read HTML email
- Add attachments, including inline - Add attachments, including inline
- Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings - Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings
@ -25,7 +25,7 @@
- Protects against header injection attacks - Protects against header injection attacks
- Error messages in over 50 languages! - Error messages in over 50 languages!
- DKIM and S/MIME signing support - DKIM and S/MIME signing support
- Compatible with PHP 5.5 and later, including PHP 8.1 - Compatible with PHP 5.5 and later, including PHP 8.2
- Namespaced to prevent name clashes - Namespaced to prevent name clashes
- Much more! - Much more!
@ -38,7 +38,7 @@ The PHP `mail()` function usually sends via a local mail server, typically front
*Please* don't be tempted to do it yourself if you don't use PHPMailer, there are many other excellent libraries that *Please* don't be tempted to do it yourself if you don't use PHPMailer, there are many other excellent libraries that
you should look at before rolling your own. Try [SwiftMailer](https://swiftmailer.symfony.com/) you should look at before rolling your own. Try [SwiftMailer](https://swiftmailer.symfony.com/)
, [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail) etc. , [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail), etc.
## License ## License
This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution. This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution.
@ -47,7 +47,7 @@ This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lg
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file: PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
```json ```json
"phpmailer/phpmailer": "^6.5" "phpmailer/phpmailer": "^6.7.1"
``` ```
or run or run
@ -136,14 +136,14 @@ try {
} }
``` ```
You'll find plenty to play with in the [examples](https://github.com/PHPMailer/PHPMailer/tree/master/examples) folder, which covers many common scenarios including sending through gmail, building contact forms, sending to mailing lists, and more. You'll find plenty to play with in the [examples](https://github.com/PHPMailer/PHPMailer/tree/master/examples) folder, which covers many common scenarios including sending through Gmail, building contact forms, sending to mailing lists, and more.
If you are re-using the instance (e.g. when sending to a mailing list), you may need to clear the recipient list to avoid sending duplicate messages. See [the mailing list example](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps) for further guidance. If you are re-using the instance (e.g. when sending to a mailing list), you may need to clear the recipient list to avoid sending duplicate messages. See [the mailing list example](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps) for further guidance.
That's it. You should now be ready to use PHPMailer! That's it. You should now be ready to use PHPMailer!
## Localization ## Localization
PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this: PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder, you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this:
```php ```php
//To load the French version //To load the French version
@ -178,9 +178,9 @@ Please disclose any vulnerabilities found responsibly report security issues
See [SECURITY](https://github.com/PHPMailer/PHPMailer/tree/master/SECURITY.md) and [PHPMailer's security advisories on GitHub](https://github.com/PHPMailer/PHPMailer/security). See [SECURITY](https://github.com/PHPMailer/PHPMailer/tree/master/SECURITY.md) and [PHPMailer's security advisories on GitHub](https://github.com/PHPMailer/PHPMailer/security).
## Contributing ## Contributing
Please submit bug reports, suggestions and pull requests to the [GitHub issue tracker](https://github.com/PHPMailer/PHPMailer/issues). Please submit bug reports, suggestions, and pull requests to the [GitHub issue tracker](https://github.com/PHPMailer/PHPMailer/issues).
We're particularly interested in fixing edge-cases, expanding test coverage and updating translations. We're particularly interested in fixing edge cases, expanding test coverage, and updating translations.
If you found a mistake in the docs, or want to add something, go ahead and amend the wiki anyone can edit it. If you found a mistake in the docs, or want to add something, go ahead and amend the wiki anyone can edit it.
@ -204,7 +204,7 @@ Donations are very welcome, whether in beer 🍺, T-shirts 👕, or cold, hard c
Available as part of the Tidelift Subscription. Available as part of the Tidelift Subscription.
The maintainers of PHPMailer and thousands of other packages are working with Tidelift to deliver commercial The maintainers of PHPMailer and thousands of other packages are working with Tidelift to deliver commercial
support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and support and maintenance for the open-source packages you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact packages you improve code health, while paying the maintainers of the exact packages you
use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpmailer-phpmailer?utm_source=packagist-phpmailer-phpmailer&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpmailer-phpmailer?utm_source=packagist-phpmailer-phpmailer&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
@ -222,9 +222,9 @@ See [changelog](changelog.md).
### What's changed since moving from SourceForge? ### What's changed since moving from SourceForge?
- Official successor to the SourceForge and Google Code projects. - Official successor to the SourceForge and Google Code projects.
- Test suite. - Test suite.
- Continuous integration with Github Actions. - Continuous integration with GitHub Actions.
- Composer support. - Composer support.
- Public development. - Public development.
- Additional languages and language strings. - Additional languages and language strings.
- CRAM-MD5 authentication support. - CRAM-MD5 authentication support.
- Preserves full repo history of authors, commits and branches from the original SourceForge project. - Preserves full repo history of authors, commits, and branches from the original SourceForge project.

View File

@ -1 +1 @@
6.6.4 6.7.1

View File

@ -37,21 +37,23 @@
"ext-hash": "*" "ext-hash": "*"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.6.2", "squizlabs/php_codesniffer": "^3.7.1",
"yoast/phpunit-polyfills": "^1.0.0" "yoast/phpunit-polyfills": "^1.0.4"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging", "psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
}, },
"autoload": { "autoload": {

View File

@ -44,6 +44,8 @@ use League\OAuth2\Client\Provider\Google;
use Hayageek\OAuth2\Client\Provider\Yahoo; use Hayageek\OAuth2\Client\Provider\Yahoo;
//@see https://github.com/stevenmaguire/oauth2-microsoft //@see https://github.com/stevenmaguire/oauth2-microsoft
use Stevenmaguire\OAuth2\Client\Provider\Microsoft; use Stevenmaguire\OAuth2\Client\Provider\Microsoft;
//@see https://github.com/greew/oauth2-azure-provider
use Greew\OAuth2\Client\Provider\Azure;
if (!isset($_GET['code']) && !isset($_POST['provider'])) { if (!isset($_GET['code']) && !isset($_POST['provider'])) {
?> ?>
@ -57,11 +59,14 @@ if (!isset($_GET['code']) && !isset($_POST['provider'])) {
<label for="providerYahoo">Yahoo</label><br> <label for="providerYahoo">Yahoo</label><br>
<input type="radio" name="provider" value="Microsoft" id="providerMicrosoft"> <input type="radio" name="provider" value="Microsoft" id="providerMicrosoft">
<label for="providerMicrosoft">Microsoft</label><br> <label for="providerMicrosoft">Microsoft</label><br>
<input type="radio" name="provider" value="Azure" id="providerAzure">
<label for="providerAzure">Azure</label><br>
<h1>Enter id and secret</h1> <h1>Enter id and secret</h1>
<p>These details are obtained by setting up an app in your provider's developer console. <p>These details are obtained by setting up an app in your provider's developer console.
</p> </p>
<p>ClientId: <input type="text" name="clientId"><p> <p>ClientId: <input type="text" name="clientId"><p>
<p>ClientSecret: <input type="text" name="clientSecret"></p> <p>ClientSecret: <input type="text" name="clientSecret"></p>
<p>TenantID (only relevant for Azure): <input type="text" name="tenantId"></p>
<input type="submit" value="Continue"> <input type="submit" value="Continue">
</form> </form>
</body> </body>
@ -77,18 +82,22 @@ session_start();
$providerName = ''; $providerName = '';
$clientId = ''; $clientId = '';
$clientSecret = ''; $clientSecret = '';
$tenantId = '';
if (array_key_exists('provider', $_POST)) { if (array_key_exists('provider', $_POST)) {
$providerName = $_POST['provider']; $providerName = $_POST['provider'];
$clientId = $_POST['clientId']; $clientId = $_POST['clientId'];
$clientSecret = $_POST['clientSecret']; $clientSecret = $_POST['clientSecret'];
$tenantId = $_POST['tenantId'];
$_SESSION['provider'] = $providerName; $_SESSION['provider'] = $providerName;
$_SESSION['clientId'] = $clientId; $_SESSION['clientId'] = $clientId;
$_SESSION['clientSecret'] = $clientSecret; $_SESSION['clientSecret'] = $clientSecret;
$_SESSION['tenantId'] = $tenantId;
} elseif (array_key_exists('provider', $_SESSION)) { } elseif (array_key_exists('provider', $_SESSION)) {
$providerName = $_SESSION['provider']; $providerName = $_SESSION['provider'];
$clientId = $_SESSION['clientId']; $clientId = $_SESSION['clientId'];
$clientSecret = $_SESSION['clientSecret']; $clientSecret = $_SESSION['clientSecret'];
$tenantId = $_SESSION['tenantId'];
} }
//If you don't want to use the built-in form, set your client id and secret here //If you don't want to use the built-in form, set your client id and secret here
@ -130,6 +139,17 @@ switch ($providerName) {
] ]
]; ];
break; break;
case 'Azure':
$params['tenantId'] = $tenantId;
$provider = new Azure($params);
$options = [
'scope' => [
'https://outlook.office.com/SMTP.Send',
'offline_access'
]
];
break;
} }
if (null === $provider) { if (null === $provider) {

View File

@ -14,16 +14,22 @@ $PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data blev ikke accepteret.
$PHPMAILER_LANG['empty_message'] = 'Meddelelsen er uden indhold'; $PHPMAILER_LANG['empty_message'] = 'Meddelelsen er uden indhold';
$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; $PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: ';
$PHPMAILER_LANG['execute'] = 'Kunne ikke afvikle: '; $PHPMAILER_LANG['execute'] = 'Kunne ikke afvikle: ';
$PHPMAILER_LANG['extension_missing'] = 'Udvidelse mangler: ';
$PHPMAILER_LANG['file_access'] = 'Kunne ikke tilgå filen: '; $PHPMAILER_LANG['file_access'] = 'Kunne ikke tilgå filen: ';
$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; $PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: ';
$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; $PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: ';
$PHPMAILER_LANG['instantiate'] = 'Email funktionen kunne ikke initialiseres.'; $PHPMAILER_LANG['instantiate'] = 'Email funktionen kunne ikke initialiseres.';
$PHPMAILER_LANG['invalid_address'] = 'Udgyldig adresse: '; $PHPMAILER_LANG['invalid_address'] = 'Udgyldig adresse: ';
$PHPMAILER_LANG['invalid_header'] = 'Ugyldig header navn eller værdi';
$PHPMAILER_LANG['invalid_hostentry'] = 'Ugyldig hostentry: ';
$PHPMAILER_LANG['invalid_host'] = 'Ugyldig vært: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; $PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.';
$PHPMAILER_LANG['provide_address'] = 'Indtast mindst en modtagers email adresse.'; $PHPMAILER_LANG['provide_address'] = 'Indtast mindst en modtagers email adresse.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: '; $PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere fejlede: ';
$PHPMAILER_LANG['signing'] = 'Signeringsfejl: '; $PHPMAILER_LANG['signing'] = 'Signeringsfejl: ';
$PHPMAILER_LANG['smtp_code'] = 'SMTP kode: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Yderligere SMTP info: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.'; $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.';
$PHPMAILER_LANG['smtp_detail'] = 'Detalje: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: '; $PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: ';
$PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: '; $PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: ';
$PHPMAILER_LANG['extension_missing'] = 'Udvidelse mangler: ';

View File

@ -4,6 +4,7 @@
* Spanish PHPMailer language file: refer to English translation for definitive list * Spanish PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer * @package PHPMailer
* @author Matt Sturdy <matt.sturdy@gmail.com> * @author Matt Sturdy <matt.sturdy@gmail.com>
* @author Crystopher Glodzienski Cardoso <crystopher.glodzienski@gmail.com>
*/ */
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.'; $PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
@ -25,3 +26,6 @@ $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: '; $PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: '; $PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: '; $PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
$PHPMAILER_LANG['smtp_code'] = 'Código del servidor SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Información adicional del servidor SMTP: ';
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';

View File

@ -9,19 +9,18 @@ $PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: Nie można przeprowadzi
$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.'; $PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.';
$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.'; $PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.';
$PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.'; $PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.';
$PHPMAILER_LANG['encoding'] = 'Nieznany sposób kodowania znaków: '; $PHPMAILER_LANG['encoding'] = 'Błędny sposób kodowania znaków: ';
$PHPMAILER_LANG['execute'] = 'Nie można uruchomić: '; $PHPMAILER_LANG['execute'] = 'Nie można uruchomić: ';
$PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: '; $PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: ';
$PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: '; $PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: ';
$PHPMAILER_LANG['from_failed'] = 'Następujący adres Nadawcy jest nieprawidłowy: '; $PHPMAILER_LANG['from_failed'] = 'Następujący adres nadawcy jest nieprawidłowy lub nie istnieje: ';
$PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.'; $PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.';
$PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, ' . $PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, ' . 'następujący adres odbiorcy jest nieprawidłowy lub nie istnieje: ';
'następujący adres Odbiorcy jest nieprawidłowy: '; $PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email odbiorcy.';
$PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email Odbiorcy.';
$PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.'; $PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.';
$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi: '; $PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi lub nie istnieją: ';
$PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: '; $PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zakończone niepowodzeniem.'; $PHPMAILER_LANG['smtp_connect_failed'] = 'Wywołanie funkcji SMTP Connect() zostało zakończone niepowodzeniem.';
$PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: '; $PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Nie można ustawić lub zmodyfikować zmiennej: '; $PHPMAILER_LANG['variable_set'] = 'Nie można ustawić lub zmodyfikować zmiennej: ';
$PHPMAILER_LANG['extension_missing'] = 'Brakujące rozszerzenie: '; $PHPMAILER_LANG['extension_missing'] = 'Brakujące rozszerzenie: ';

View File

@ -750,7 +750,7 @@ class PHPMailer
* *
* @var string * @var string
*/ */
const VERSION = '6.6.4'; const VERSION = '6.7.1';
/** /**
* Error severity: message only, continue processing. * Error severity: message only, continue processing.
@ -858,7 +858,7 @@ class PHPMailer
private function mailPassthru($to, $subject, $body, $header, $params) private function mailPassthru($to, $subject, $body, $header, $params)
{ {
//Check overloading of mail function to avoid double-encoding //Check overloading of mail function to avoid double-encoding
if (ini_get('mbstring.func_overload') & 1) { if ((int)ini_get('mbstring.func_overload') & 1) {
$subject = $this->secureHeader($subject); $subject = $this->secureHeader($subject);
} else { } else {
$subject = $this->encodeHeader($this->secureHeader($subject)); $subject = $this->encodeHeader($this->secureHeader($subject));
@ -1124,6 +1124,22 @@ class PHPMailer
return call_user_func_array([$this, 'addAnAddress'], $params); return call_user_func_array([$this, 'addAnAddress'], $params);
} }
/**
* Set the boundaries to use for delimiting MIME parts.
* If you override this, ensure you set all 3 boundaries to unique values.
* The default boundaries include a "=_" sequence which cannot occur in quoted-printable bodies,
* as suggested by https://www.rfc-editor.org/rfc/rfc2045#section-6.7
*
* @return void
*/
public function setBoundaries()
{
$this->uniqueid = $this->generateId();
$this->boundary[1] = 'b1=_' . $this->uniqueid;
$this->boundary[2] = 'b2=_' . $this->uniqueid;
$this->boundary[3] = 'b3=_' . $this->uniqueid;
}
/** /**
* Add an address to one of the recipient arrays or to the ReplyTo array. * Add an address to one of the recipient arrays or to the ReplyTo array.
* Addresses that have been added already return false, but do not throw exceptions. * Addresses that have been added already return false, but do not throw exceptions.
@ -1671,11 +1687,11 @@ class PHPMailer
return $this->mailSend($this->MIMEHeader, $this->MIMEBody); return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
} }
} catch (Exception $exc) { } catch (Exception $exc) {
if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true) {
$this->smtp->reset();
}
$this->setError($exc->getMessage()); $this->setError($exc->getMessage());
$this->edebug($exc->getMessage()); $this->edebug($exc->getMessage());
if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true && $this->smtp->connected()) {
$this->smtp->reset();
}
if ($this->exceptions) { if ($this->exceptions) {
throw $exc; throw $exc;
} }
@ -1863,7 +1879,7 @@ class PHPMailer
if (!static::isPermittedPath($path)) { if (!static::isPermittedPath($path)) {
return false; return false;
} }
$readable = file_exists($path); $readable = is_file($path);
//If not a UNC path (expected to start with \\), check read permission, see #2069 //If not a UNC path (expected to start with \\), check read permission, see #2069
if (strpos($path, '\\\\') !== 0) { if (strpos($path, '\\\\') !== 0) {
$readable = $readable && is_readable($path); $readable = $readable && is_readable($path);
@ -2101,6 +2117,9 @@ class PHPMailer
$this->smtp->setDebugLevel($this->SMTPDebug); $this->smtp->setDebugLevel($this->SMTPDebug);
$this->smtp->setDebugOutput($this->Debugoutput); $this->smtp->setDebugOutput($this->Debugoutput);
$this->smtp->setVerp($this->do_verp); $this->smtp->setVerp($this->do_verp);
if ($this->Host === null) {
$this->Host = 'localhost';
}
$hosts = explode(';', $this->Host); $hosts = explode(';', $this->Host);
$lastexception = null; $lastexception = null;
@ -2791,10 +2810,7 @@ class PHPMailer
{ {
$body = ''; $body = '';
//Create unique IDs and preset boundaries //Create unique IDs and preset boundaries
$this->uniqueid = $this->generateId(); $this->setBoundaries();
$this->boundary[1] = 'b1_' . $this->uniqueid;
$this->boundary[2] = 'b2_' . $this->uniqueid;
$this->boundary[3] = 'b3_' . $this->uniqueid;
if ($this->sign_key_file) { if ($this->sign_key_file) {
$body .= $this->getMailMIME() . static::$LE; $body .= $this->getMailMIME() . static::$LE;
@ -2830,7 +2846,7 @@ class PHPMailer
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE; $altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
} }
//Use this as a preamble in all multipart message types //Use this as a preamble in all multipart message types
$mimepre = 'This is a multi-part message in MIME format.' . static::$LE . static::$LE; $mimepre = '';
switch ($this->message_type) { switch ($this->message_type) {
case 'inline': case 'inline':
$body .= $mimepre; $body .= $mimepre;
@ -3066,6 +3082,18 @@ class PHPMailer
return $body; return $body;
} }
/**
* Get the boundaries that this message will use
* @return array
*/
public function getBoundaries()
{
if (empty($this->boundary)) {
$this->setBoundaries();
}
return $this->boundary;
}
/** /**
* Return the start of a message boundary. * Return the start of a message boundary.
* *
@ -4183,6 +4211,7 @@ class PHPMailer
* @param string $name Custom header name * @param string $name Custom header name
* @param string|null $value Header value * @param string|null $value Header value
* *
* @return bool True if a header was set successfully
* @throws Exception * @throws Exception
*/ */
public function addCustomHeader($name, $value = null) public function addCustomHeader($name, $value = null)
@ -4632,15 +4661,27 @@ class PHPMailer
} }
/** /**
* Remove trailing breaks from a string. * Remove trailing whitespace from a string.
*
* @param string $text
*
* @return string The text to remove whitespace from
*/
public static function stripTrailingWSP($text)
{
return rtrim($text, " \r\n\t");
}
/**
* Strip trailing line breaks from a string.
* *
* @param string $text * @param string $text
* *
* @return string The text to remove breaks from * @return string The text to remove breaks from
*/ */
public static function stripTrailingWSP($text) public static function stripTrailingBreaks($text)
{ {
return rtrim($text, " \r\n\t"); return rtrim($text, "\r\n");
} }
/** /**
@ -4806,7 +4847,7 @@ class PHPMailer
$body = static::normalizeBreaks($body, self::CRLF); $body = static::normalizeBreaks($body, self::CRLF);
//Reduce multiple trailing line breaks to a single one //Reduce multiple trailing line breaks to a single one
return static::stripTrailingWSP($body) . self::CRLF; return static::stripTrailingBreaks($body) . self::CRLF;
} }
/** /**

View File

@ -46,7 +46,7 @@ class POP3
* *
* @var string * @var string
*/ */
const VERSION = '6.6.4'; const VERSION = '6.7.1';
/** /**
* Default POP3 port number. * Default POP3 port number.
@ -337,7 +337,12 @@ class POP3
*/ */
public function disconnect() public function disconnect()
{ {
$this->sendString('QUIT'); // If could not connect at all, no need to disconnect
if ($this->pop_conn === false) {
return;
}
$this->sendString('QUIT' . static::LE);
// RFC 1939 shows POP3 server sending a +OK response to the QUIT command. // RFC 1939 shows POP3 server sending a +OK response to the QUIT command.
// Try to get it. Ignore any failures here. // Try to get it. Ignore any failures here.

View File

@ -35,7 +35,7 @@ class SMTP
* *
* @var string * @var string
*/ */
const VERSION = '6.6.4'; const VERSION = '6.7.1';
/** /**
* SMTP line break constant. * SMTP line break constant.
@ -682,7 +682,6 @@ class SMTP
*/ */
public function close() public function close()
{ {
$this->setError('');
$this->server_caps = null; $this->server_caps = null;
$this->helo_rply = null; $this->helo_rply = null;
if (is_resource($this->smtp_conn)) { if (is_resource($this->smtp_conn)) {

2
vendor/services.php vendored
View File

@ -1,5 +1,5 @@
<?php <?php
// This file is automatically generated at:2022-12-03 13:32:51 // This file is automatically generated at:2023-01-04 21:42:43
declare (strict_types = 1); declare (strict_types = 1);
return array ( return array (
0 => 'taoser\\addons\\Service', 0 => 'taoser\\addons\\Service',

View File

@ -149,6 +149,7 @@ class Exporter
} }
if (null !== $sleep) { if (null !== $sleep) {
if (!isset($sleep[$n]) || ($i && $c !== $class)) { if (!isset($sleep[$n]) || ($i && $c !== $class)) {
unset($arrayValue[$name]);
continue; continue;
} }
$sleep[$n] = false; $sleep[$n] = false;
@ -164,6 +165,9 @@ class Exporter
} }
} }
} }
if (method_exists($class, '__unserialize')) {
$properties = $arrayValue;
}
prepare_value: prepare_value:
$objectsPool[$value] = [$id = \count($objectsPool)]; $objectsPool[$value] = [$id = \count($objectsPool)];

View File

@ -341,6 +341,16 @@ class DbManager
return $this->listen; return $this->listen;
} }
/**
* 获取所有连接实列
* @access public
* @return array
*/
public function getInstance(): array
{
return $this->instance;
}
/** /**
* 注册回调方法 * 注册回调方法
* @access public * @access public

View File

@ -377,6 +377,19 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
return $this->items; return $this->items;
} }
/**
* 设置数据集
*
* @param Collection $items
* @return $this
*/
public function setCollection(Collection $items)
{
$this->items = $items;
return $this;
}
public function isEmpty(): bool public function isEmpty(): bool
{ {
return $this->items->isEmpty(); return $this->items->isEmpty();

View File

@ -559,23 +559,4 @@ trait ModelRelationQuery
$result->refreshOrigin(); $result->refreshOrigin();
} }
/**
* 查询软删除数据
* @access public
* @return Query
*/
public function withTrashed()
{
return $this->model ? $this->model->queryWithTrashed() : $this;
}
/**
* 只查询软删除数据
* @access public
* @return Query
*/
public function onlyTrashed()
{
return $this->model ? $this->model->queryOnlyTrashed() : $this;
}
} }

View File

@ -383,7 +383,7 @@ trait Attribute
} elseif (isset($this->type[$name])) { } elseif (isset($this->type[$name])) {
// 类型转换 // 类型转换
$value = $this->writeTransform($value, $this->type[$name]); $value = $this->writeTransform($value, $this->type[$name]);
} elseif (array_key_exists($name, $this->origin) && is_object($value) && method_exists($value, '__toString')) { } elseif ((array_key_exists($name, $this->origin) || empty($this->origin)) && is_object($value) && method_exists($value, '__toString')) {
// 对象类型 // 对象类型
$value = $value->__toString(); $value = $value->__toString();
} }

View File

@ -18,14 +18,18 @@ use think\Model;
/** /**
* 数据软删除 * 数据软删除
* @mixin Model * @mixin Model
* @method $this withTrashed()
* @method $this onlyTrashed()
*/ */
trait SoftDelete trait SoftDelete
{ {
/**
* 是否包含软删除数据 public function db($scope = []): Query
* @var bool {
*/ $query = parent::db($scope);
protected $withTrashed = false; $this->withNoTrashed($query);
return $query;
}
/** /**
* 判断当前实例是否被软删除 * 判断当前实例是否被软删除
@ -43,74 +47,18 @@ trait SoftDelete
return false; return false;
} }
/** public function scopeWithTrashed(Query $query)
* 查询软删除数据
* @access public
* @return Query
*/
public static function withTrashed(): Query
{ {
$model = new static(); $query->removeOption('soft_delete');
return $model->withTrashedData(true)->db();
} }
/** public function scopeOnlyTrashed(Query $query)
* 查询软删除数据
* @access public
* @return Query
*/
public function queryWithTrashed(): Query
{
return $this->withTrashedData(true)->db();
}
/**
* 是否包含软删除数据
* @access protected
* @param bool $withTrashed 是否包含软删除数据
* @return $this
*/
protected function withTrashedData(bool $withTrashed)
{
$this->withTrashed = $withTrashed;
return $this;
}
/**
* 只查询软删除数据
* @access public
* @return Query
*/
public static function onlyTrashed(): Query
{
$model = new static();
$field = $model->getDeleteTimeField(true);
if ($field) {
return $model
->db()
->useSoftDelete($field, $model->getWithTrashedExp());
}
return $model->db();
}
/**
* 只查询软删除数据
* @access public
* @return Query
*/
public function queryOnlyTrashed(): Query
{ {
$field = $this->getDeleteTimeField(true); $field = $this->getDeleteTimeField(true);
if ($field) { if ($field) {
return $this->db() $query->useSoftDelete($field, $this->getWithTrashedExp());
->useSoftDelete($field, $this->getWithTrashedExp());
} }
return $this->db();
} }
/** /**
@ -139,9 +87,9 @@ trait SoftDelete
if ($name && !$force) { if ($name && !$force) {
// 软删除 // 软删除
$this->set($name, $this->autoWriteTimestamp($name)); $this->set($name, $this->autoWriteTimestamp());
$result = $this->exists()->withEvent(false)->save(); $this->exists()->withEvent(false)->save();
$this->withEvent(true); $this->withEvent(true);
} else { } else {
@ -149,7 +97,7 @@ trait SoftDelete
$where = $this->getWhere(); $where = $this->getWhere();
// 删除当前模型数据 // 删除当前模型数据
$result = $this->db() $this->db()
->where($where) ->where($where)
->removeOption('soft_delete') ->removeOption('soft_delete')
->delete(); ->delete();
@ -182,13 +130,15 @@ trait SoftDelete
if (empty($data) && 0 !== $data) { if (empty($data) && 0 !== $data) {
return false; return false;
} }
// 仅当强制删除时包含软删除数据
$model = (new static()); $model = (new static());
if ($force) {
$model->withTrashedData(true);
}
$query = $model->db(false); $query = $model->db(false);
// 仅当强制删除时包含软删除数据
if ($force) {
$query->removeOption('soft_delete');
}
if (is_array($data) && key($data) !== 0) { if (is_array($data) && key($data) !== 0) {
$query->where($data); $query->where($data);
$data = null; $data = null;
@ -202,6 +152,7 @@ trait SoftDelete
$resultSet = $query->select($data); $resultSet = $query->select($data);
foreach ($resultSet as $result) { foreach ($resultSet as $result) {
/** @var Model $result */
$result->force($force)->delete(); $result->force($force)->delete();
} }

View File

@ -179,7 +179,7 @@ trait TimeStamp
protected function formatDateTime($format, $time = 'now', bool $timestamp = false) protected function formatDateTime($format, $time = 'now', bool $timestamp = false)
{ {
if (empty($time)) { if (empty($time)) {
return; return $time;
} }
if (false === $format) { if (false === $format) {

View File

@ -241,7 +241,7 @@ class BelongsTo extends OneToOne
if (!empty($this->bindAttr)) { if (!empty($this->bindAttr)) {
// 绑定关联属性 // 绑定关联属性
$this->bindAttr($result, $relationModel); $this->bindAttr($result, $relationModel);
$result->hidden([$relation]); $result->hidden([$relation], true);
} }
} }
} }
@ -283,7 +283,7 @@ class BelongsTo extends OneToOne
if (!empty($this->bindAttr)) { if (!empty($this->bindAttr)) {
// 绑定关联属性 // 绑定关联属性
$this->bindAttr($result, $relationModel); $this->bindAttr($result, $relationModel);
$result->hidden([$relation]); $result->hidden([$relation], true);
} }
} }

View File

@ -240,7 +240,7 @@ class HasOne extends OneToOne
if (!empty($this->bindAttr)) { if (!empty($this->bindAttr)) {
// 绑定关联属性 // 绑定关联属性
$this->bindAttr($result, $relationModel); $this->bindAttr($result, $relationModel);
$result->hidden([$relation]); $result->hidden([$relation], true);
} }
} }
} }
@ -282,7 +282,7 @@ class HasOne extends OneToOne
if (!empty($this->bindAttr)) { if (!empty($this->bindAttr)) {
// 绑定关联属性 // 绑定关联属性
$this->bindAttr($result, $relationModel); $this->bindAttr($result, $relationModel);
$result->hidden([$relation]); $result->hidden([$relation], true);
} }
} }

View File

@ -13,6 +13,7 @@ namespace think\model\relation;
use Closure; use Closure;
use think\db\exception\DbException as Exception; use think\db\exception\DbException as Exception;
use think\db\Query;
use think\helper\Str; use think\helper\Str;
use think\Model; use think\Model;
use think\model\Relation; use think\model\Relation;
@ -46,6 +47,8 @@ class MorphTo extends Relation
*/ */
protected $relation; protected $relation;
protected $queryCaller = [];
/** /**
* 架构函数 * 架构函数
* @access public * @access public
@ -53,7 +56,7 @@ class MorphTo extends Relation
* @param string $morphType 多态字段名 * @param string $morphType 多态字段名
* @param string $morphKey 外键名 * @param string $morphKey 外键名
* @param array $alias 多态别名定义 * @param array $alias 多态别名定义
* @param string $relation 关联名 * @param ?string $relation 关联名
*/ */
public function __construct(Model $parent, string $morphType, string $morphKey, array $alias = [], string $relation = null) public function __construct(Model $parent, string $morphType, string $morphKey, array $alias = [], string $relation = null)
{ {
@ -81,7 +84,7 @@ class MorphTo extends Relation
* 延迟获取关联数据 * 延迟获取关联数据
* @access public * @access public
* @param array $subRelation 子关联名 * @param array $subRelation 子关联名
* @param Closure $closure 闭包查询条件 * @param ?Closure $closure 闭包查询条件
* @return Model * @return Model
*/ */
public function getRelation(array $subRelation = [], Closure $closure = null) public function getRelation(array $subRelation = [], Closure $closure = null)
@ -95,7 +98,7 @@ class MorphTo extends Relation
// 主键数据 // 主键数据
$pk = $this->parent->$morphKey; $pk = $this->parent->$morphKey;
$relationModel = (new $model)->relation($subRelation)->find($pk); $relationModel = $this->buildQuery((new $model)->relation($subRelation))->find($pk);
if ($relationModel) { if ($relationModel) {
$relationModel->setParent(clone $this->parent); $relationModel->setParent(clone $this->parent);
@ -125,19 +128,43 @@ class MorphTo extends Relation
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段 * @param mixed $fields 字段
* @param string $joinType JOIN类型 * @param string $joinType JOIN类型
* @param Query $query Query对象 * @param ?Query $query Query对象
* @return Query * @return Query
*/ */
public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null) public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null)
{ {
throw new Exception('relation not support: hasWhere'); $alias = class_basename($this->parent);
$types = $this->parent->distinct()->column($this->morphType);
$query = $query ?: $this->parent->db();
return $query->alias($alias)
->where(function (Query $query) use ($types, $where, $alias) {
foreach ($types as $type) {
if ($type) {
$query->whereExists(function (Query $query) use ($type, $where, $alias) {
$class = $this->parseModel($type);
/** @var Model $model */
$model = new $class();
$table = $model->getTable();
$query
->table($table)
->where($alias . '.' . $this->morphType, $type)
->whereRaw("`{$alias}`.`{$this->morphKey}`=`{$table}`.`{$model->getPk()}`")
->where($where);
}, 'OR');
}
}
});
} }
/** /**
* 解析模型的完整命名空间 * 解析模型的完整命名空间
* @access protected * @access protected
* @param string $model 模型名(或者完整类名) * @param string $model 模型名(或者完整类名)
* @return string * @return Model
*/ */
protected function parseModel(string $model): string protected function parseModel(string $model): string
{ {
@ -173,7 +200,7 @@ class MorphTo extends Relation
* @access public * @access public
* @return $this * @return $this
*/ */
public function removeOption() public function removeOption(string $option = '')
{ {
return $this; return $this;
} }
@ -184,7 +211,7 @@ class MorphTo extends Relation
* @param array $resultSet 数据集 * @param array $resultSet 数据集
* @param string $relation 当前关联名 * @param string $relation 当前关联名
* @param array $subRelation 子关联名 * @param array $subRelation 子关联名
* @param Closure $closure 闭包 * @param ?Closure $closure 闭包
* @param array $cache 关联缓存 * @param array $cache 关联缓存
* @return void * @return void
* @throws Exception * @throws Exception
@ -245,7 +272,7 @@ class MorphTo extends Relation
* @param Model $result 数据对象 * @param Model $result 数据对象
* @param string $relation 当前关联名 * @param string $relation 当前关联名
* @param array $subRelation 子关联名 * @param array $subRelation 子关联名
* @param Closure $closure 闭包 * @param ?Closure $closure 闭包
* @param array $cache 关联缓存 * @param array $cache 关联缓存
* @return void * @return void
*/ */
@ -261,13 +288,14 @@ class MorphTo extends Relation
* 关联统计 * 关联统计
* @access public * @access public
* @param Model $result 数据对象 * @param Model $result 数据对象
* @param Closure $closure 闭包 * @param ?Closure $closure 闭包
* @param string $aggregate 聚合查询方法 * @param string $aggregate 聚合查询方法
* @param string $field 字段 * @param string $field 字段
* @return integer * @return integer
*/ */
public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*') public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*')
{} {
}
/** /**
* 多态MorphTo 关联模型预查询 * 多态MorphTo 关联模型预查询
@ -283,6 +311,10 @@ class MorphTo extends Relation
{ {
// 预载入关联查询 支持嵌套预载入 // 预载入关联查询 支持嵌套预载入
$pk = $this->parent->{$this->morphKey}; $pk = $this->parent->{$this->morphKey};
$data = null;
if (\class_exists($model)) {
$data = (new $model)->with($subRelation) $data = (new $model)->with($subRelation)
->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null)
->find($pk); ->find($pk);
@ -291,6 +323,7 @@ class MorphTo extends Relation
$data->setParent(clone $result); $data->setParent(clone $result);
$data->exists(true); $data->exists(true);
} }
}
$result->setRelation($relation, $data ?: null); $result->setRelation($relation, $data ?: null);
} }
@ -332,4 +365,18 @@ class MorphTo extends Relation
return $this->parent->setRelation($this->relation, null); return $this->parent->setRelation($this->relation, null);
} }
protected function buildQuery(Query $query)
{
foreach ($this->queryCaller as $caller) {
call_user_func_array([$query, $caller[0]], $caller[1]);
}
return $query;
}
public function __call($method, $args)
{
$this->queryCaller[] = [$method, $args];
return $this;
}
} }

View File

@ -91,9 +91,23 @@ abstract class OneToOne extends Relation
$query->via($joinAlias); $query->via($joinAlias);
if ($this instanceof BelongsTo) { if ($this instanceof BelongsTo) {
$joinOn = $name . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey;
$foreignKeyExp = $this->foreignKey;
if (strpos($foreignKeyExp, '.') === false) {
$foreignKeyExp = $name . '.' . $this->foreignKey;
}
$joinOn = $foreignKeyExp . '=' . $joinAlias . '.' . $this->localKey;
} else { } else {
$joinOn = $name . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey;
$foreignKeyExp = $this->foreignKey;
if (strpos($foreignKeyExp, '.') === false) {
$foreignKeyExp = $joinAlias . '.' . $this->foreignKey;
}
$joinOn = $name . '.' . $this->localKey . '=' . $foreignKeyExp;
} }
if ($closure) { if ($closure) {

View File

@ -157,6 +157,13 @@ class TcpConnection extends ConnectionInterface
*/ */
public $maxSendBufferSize = 1048576; public $maxSendBufferSize = 1048576;
/**
* Context.
*
* @var array
*/
public $context = null;
/** /**
* Default send buffer size. * Default send buffer size.
* *
@ -285,6 +292,7 @@ class TcpConnection extends ConnectionInterface
$this->maxPackageSize = self::$defaultMaxPackageSize; $this->maxPackageSize = self::$defaultMaxPackageSize;
$this->_remoteAddress = $remote_address; $this->_remoteAddress = $remote_address;
static::$connections[$this->id] = $this; static::$connections[$this->id] = $this;
$this->context = new \stdClass;
} }
/** /**

View File

@ -565,7 +565,7 @@ class Request
'tmp_name' => $tmp_file, 'tmp_name' => $tmp_file,
'size' => $size, 'size' => $size,
'error' => $error, 'error' => $error,
'type' => null, 'type' => '',
]; ];
break; break;
} // Is post field. } // Is post field.

View File

@ -11,10 +11,12 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Workerman\Protocols; namespace Workerman\Protocols;
use Workerman\Connection\ConnectionInterface; use Workerman\Connection\ConnectionInterface;
use Workerman\Connection\TcpConnection; use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Worker; use Workerman\Worker;
/** /**
@ -29,6 +31,13 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
*/ */
const BINARY_TYPE_BLOB = "\x81"; const BINARY_TYPE_BLOB = "\x81";
/**
* Websocket blob type.
*
* @var string
*/
const BINARY_TYPE_BLOB_DEFLATE = "\xc1";
/** /**
* Websocket arraybuffer type. * Websocket arraybuffer type.
* *
@ -36,6 +45,13 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
*/ */
const BINARY_TYPE_ARRAYBUFFER = "\x82"; const BINARY_TYPE_ARRAYBUFFER = "\x82";
/**
* Websocket arraybuffer type.
*
* @var string
*/
const BINARY_TYPE_ARRAYBUFFER_DEFLATE = "\xc2";
/** /**
* Check the integrity of the package. * Check the integrity of the package.
* *
@ -53,23 +69,23 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
} }
// Has not yet completed the handshake. // Has not yet completed the handshake.
if (empty($connection->websocketHandshake)) { if (empty($connection->context->websocketHandshake)) {
return static::dealHandshake($buffer, $connection); return static::dealHandshake($buffer, $connection);
} }
// Buffer websocket frame data. // Buffer websocket frame data.
if ($connection->websocketCurrentFrameLength) { if ($connection->context->websocketCurrentFrameLength) {
// We need more frame data. // We need more frame data.
if ($connection->websocketCurrentFrameLength > $recv_len) { if ($connection->context->websocketCurrentFrameLength > $recv_len) {
// Return 0, because it is not clear the full packet length, waiting for the frame of fin=1. // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1.
return 0; return 0;
} }
} else { } else {
$firstbyte = \ord($buffer[0]); $first_byte = \ord($buffer[0]);
$secondbyte = \ord($buffer[1]); $second_byte = \ord($buffer[1]);
$data_len = $secondbyte & 127; $data_len = $second_byte & 127;
$is_fin_frame = $firstbyte >> 7; $is_fin_frame = $first_byte >> 7;
$masked = $secondbyte >> 7; $masked = $second_byte >> 7;
if (!$masked) { if (!$masked) {
Worker::safeEcho("frame not masked so close the connection\n"); Worker::safeEcho("frame not masked so close the connection\n");
@ -77,7 +93,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
return 0; return 0;
} }
$opcode = $firstbyte & 0xf; $opcode = $first_byte & 0xf;
switch ($opcode) { switch ($opcode) {
case 0x0: case 0x0:
break; break;
@ -90,12 +106,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
// Close package. // Close package.
case 0x8: case 0x8:
// Try to emit onWebSocketClose callback. // Try to emit onWebSocketClose callback.
if (isset($connection->onWebSocketClose) || isset($connection->worker->onWebSocketClose)) { $close_cb = $connection->onWebSocketClose ?? $connection->worker->onWebSocketClose ?? false;
if ($close_cb) {
try { try {
\call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection); $close_cb($connection);
} catch (\Exception $e) { } catch (\Throwable $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e); Worker::stopAll(250, $e);
} }
} // Close connection. } // Close connection.
@ -137,7 +152,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
} }
$current_frame_length = $head_len + $data_len; $current_frame_length = $head_len + $data_len;
$total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length; $total_package_size = \strlen($connection->context->websocketDataBuffer) + $current_frame_length;
if ($total_package_size > $connection->maxPackageSize) { if ($total_package_size > $connection->maxPackageSize) {
Worker::safeEcho("error package. package_length=$total_package_size\n"); Worker::safeEcho("error package. package_length=$total_package_size\n");
$connection->close(); $connection->close();
@ -151,12 +166,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
$connection->consumeRecvBuffer($current_frame_length); $connection->consumeRecvBuffer($current_frame_length);
$tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
$connection->websocketType = "\x8a"; $connection->websocketType = "\x8a";
if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) { $ping_cb = $connection->onWebSocketPing ?? $connection->worker->onWebSocketPing ?? false;
if ($ping_cb) {
try { try {
\call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data); $ping_cb($connection, $ping_data);
} catch (\Exception $e) { } catch (\Throwable $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e); Worker::stopAll(250, $e);
} }
} else { } else {
@ -175,12 +189,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
$tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
$connection->websocketType = "\x8a"; $connection->websocketType = "\x8a";
// Try to emit onWebSocketPong callback. // Try to emit onWebSocketPong callback.
if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) { $pong_cb = $connection->onWebSocketPong ?? $connection->worker->onWebSocketPong ?? false;
if ($pong_cb) {
try { try {
\call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data); $pong_cb($connection, $pong_data);
} catch (\Exception $e) { } catch (\Throwable $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e); Worker::stopAll(250, $e);
} }
} }
@ -193,22 +206,22 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
} }
return $current_frame_length; return $current_frame_length;
} else { } else {
$connection->websocketCurrentFrameLength = $current_frame_length; $connection->context->websocketCurrentFrameLength = $current_frame_length;
} }
} }
// Received just a frame length data. // Received just a frame length data.
if ($connection->websocketCurrentFrameLength === $recv_len) { if ($connection->context->websocketCurrentFrameLength === $recv_len) {
static::decode($buffer, $connection); static::decode($buffer, $connection);
$connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength);
$connection->websocketCurrentFrameLength = 0; $connection->context->websocketCurrentFrameLength = 0;
return 0; return 0;
} // The length of the received data is greater than the length of a frame. } // The length of the received data is greater than the length of a frame.
elseif ($connection->websocketCurrentFrameLength < $recv_len) { elseif ($connection->context->websocketCurrentFrameLength < $recv_len) {
static::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); static::decode(\substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection);
$connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength);
$current_frame_length = $connection->websocketCurrentFrameLength; $current_frame_length = $connection->context->websocketCurrentFrameLength;
$connection->websocketCurrentFrameLength = 0; $connection->context->websocketCurrentFrameLength = 0;
// Continue to read next frame. // Continue to read next frame.
return static::input(\substr($buffer, $current_frame_length), $connection); return static::input(\substr($buffer, $current_frame_length), $connection);
} // The length of the received data is less than the length of a frame. } // The length of the received data is less than the length of a frame.
@ -229,12 +242,18 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
if (!is_scalar($buffer)) { if (!is_scalar($buffer)) {
throw new \Exception("You can't send(" . \gettype($buffer) . ") to client, you need to convert it to a string. "); throw new \Exception("You can't send(" . \gettype($buffer) . ") to client, you need to convert it to a string. ");
} }
$len = \strlen($buffer);
if (empty($connection->websocketType)) { if (empty($connection->websocketType)) {
$connection->websocketType = static::BINARY_TYPE_BLOB; $connection->websocketType = static::BINARY_TYPE_BLOB;
} }
// permessage-deflate
if (\ord($connection->websocketType) & 64) {
$buffer = static::deflate($connection, $buffer);
}
$first_byte = $connection->websocketType; $first_byte = $connection->websocketType;
$len = \strlen($buffer);
if ($len <= 125) { if ($len <= 125) {
$encode_buffer = $first_byte . \chr($len) . $buffer; $encode_buffer = $first_byte . \chr($len) . $buffer;
@ -247,37 +266,32 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
} }
// Handshake not completed so temporary buffer websocket data waiting for send. // Handshake not completed so temporary buffer websocket data waiting for send.
if (empty($connection->websocketHandshake)) { if (empty($connection->context->websocketHandshake)) {
if (empty($connection->tmpWebsocketData)) { if (empty($connection->context->tmpWebsocketData)) {
$connection->tmpWebsocketData = ''; $connection->context->tmpWebsocketData = '';
} }
// If buffer has already full then discard the current package. // If buffer has already full then discard the current package.
if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if (\strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) {
if ($connection->onError) { if ($connection->onError) {
try { try {
\call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package');
} catch (\Exception $e) { } catch (\Throwable $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e); Worker::stopAll(250, $e);
} }
} }
return ''; return '';
} }
$connection->tmpWebsocketData .= $encode_buffer; $connection->context->tmpWebsocketData .= $encode_buffer;
// Check buffer is full. // Check buffer is full.
if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { if ($connection->maxSendBufferSize <= \strlen($connection->context->tmpWebsocketData)) {
if ($connection->onBufferFull) { if ($connection->onBufferFull) {
try { try {
\call_user_func($connection->onBufferFull, $connection); ($connection->onBufferFull)($connection);
} catch (\Exception $e) { } catch (\Throwable $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e); Worker::stopAll(250, $e);
} }
} }
} }
// Return empty string. // Return empty string.
return ''; return '';
} }
@ -294,7 +308,12 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
*/ */
public static function decode($buffer, ConnectionInterface $connection) public static function decode($buffer, ConnectionInterface $connection)
{ {
$len = \ord($buffer[1]) & 127; $first_byte = \ord($buffer[0]);
$second_byte = \ord($buffer[1]);
$len = $second_byte & 127;
$is_fin_frame = $first_byte >> 7;
$rsv1 = 64 === ($first_byte & 64);
if ($len === 126) { if ($len === 126) {
$masks = \substr($buffer, 4, 4); $masks = \substr($buffer, 4, 4);
$data = \substr($buffer, 8); $data = \substr($buffer, 8);
@ -310,18 +329,74 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
$dataLength = \strlen($data); $dataLength = \strlen($data);
$masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4); $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4);
$decoded = $data ^ $masks; $decoded = $data ^ $masks;
if ($connection->websocketCurrentFrameLength) { if ($connection->context->websocketCurrentFrameLength) {
$connection->websocketDataBuffer .= $decoded; $connection->context->websocketDataBuffer .= $decoded;
return $connection->websocketDataBuffer; if ($rsv1) {
return static::inflate($connection, $connection->context->websocketDataBuffer, $is_fin_frame);
}
return $connection->context->websocketDataBuffer;
} else { } else {
if ($connection->websocketDataBuffer !== '') { if ($connection->context->websocketDataBuffer !== '') {
$decoded = $connection->websocketDataBuffer . $decoded; $decoded = $connection->context->websocketDataBuffer . $decoded;
$connection->websocketDataBuffer = ''; $connection->context->websocketDataBuffer = '';
}
if ($rsv1) {
return static::inflate($connection, $decoded, $is_fin_frame);
} }
return $decoded; return $decoded;
} }
} }
/**
* Inflate.
*
* @param $connection
* @param $buffer
* @param $is_fin_frame
* @return false|string
*/
protected static function inflate($connection, $buffer, $is_fin_frame)
{
if (!isset($connection->context->inflator)) {
$connection->context->inflator = \inflate_init(
\ZLIB_ENCODING_RAW,
[
'level' => -1,
'memory' => 8,
'window' => 9,
'strategy' => \ZLIB_DEFAULT_STRATEGY
]
);
}
if ($is_fin_frame) {
$buffer .= "\x00\x00\xff\xff";
}
return \inflate_add($connection->context->inflator, $buffer);
}
/**
* Deflate.
*
* @param $connection
* @param $buffer
* @return false|string
*/
protected static function deflate($connection, $buffer)
{
if (!isset($connection->context->deflator)) {
$connection->context->deflator = \deflate_init(
\ZLIB_ENCODING_RAW,
[
'level' => -1,
'memory' => 8,
'window' => 9,
'strategy' => \ZLIB_DEFAULT_STRATEGY
]
);
}
return \substr(\deflate_add($connection->context->deflator, $buffer), 0, -4);
}
/** /**
* Websocket handshake. * Websocket handshake.
* *
@ -329,16 +404,16 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
* @param TcpConnection $connection * @param TcpConnection $connection
* @return int * @return int
*/ */
public static function dealHandshake($buffer, TcpConnection $connection) public static function dealHandshake($buffer, $connection)
{ {
// HTTP protocol. // HTTP protocol.
if (0 === \strpos($buffer, 'GET')) { if (0 === \strpos($buffer, 'GET')) {
// Find \r\n\r\n. // Find \r\n\r\n.
$heder_end_pos = \strpos($buffer, "\r\n\r\n"); $header_end_pos = \strpos($buffer, "\r\n\r\n");
if (!$heder_end_pos) { if (!$header_end_pos) {
return 0; return 0;
} }
$header_length = $heder_end_pos + 4; $header_length = $header_end_pos + 4;
// Get Sec-WebSocket-Key. // Get Sec-WebSocket-Key.
$Sec_WebSocket_Key = ''; $Sec_WebSocket_Key = '';
@ -359,14 +434,31 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
. "Sec-WebSocket-Accept: " . $new_key . "\r\n"; . "Sec-WebSocket-Accept: " . $new_key . "\r\n";
// Websocket data buffer. // Websocket data buffer.
$connection->websocketDataBuffer = ''; $connection->context->websocketDataBuffer = '';
// Current websocket frame length. // Current websocket frame length.
$connection->websocketCurrentFrameLength = 0; $connection->context->websocketCurrentFrameLength = 0;
// Current websocket frame data. // Current websocket frame data.
$connection->websocketCurrentFrameBuffer = ''; $connection->context->websocketCurrentFrameBuffer = '';
// Consume handshake data. // Consume handshake data.
$connection->consumeRecvBuffer($header_length); $connection->consumeRecvBuffer($header_length);
// Try to emit onWebSocketConnect callback.
$on_websocket_connect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false;
if ($on_websocket_connect) {
static::parseHttpHeader($buffer);
try {
\call_user_func($on_websocket_connect, $connection, $buffer);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) {
$connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION);
}
$_GET = $_SERVER = $_SESSION = $_COOKIE = array();
}
// blob or arraybuffer // blob or arraybuffer
if (empty($connection->websocketType)) { if (empty($connection->websocketType)) {
$connection->websocketType = static::BINARY_TYPE_BLOB; $connection->websocketType = static::BINARY_TYPE_BLOB;
@ -396,41 +488,17 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
// Send handshake response. // Send handshake response.
$connection->send($handshake_message, true); $connection->send($handshake_message, true);
// Mark handshake complete.. // Mark handshake complete..
$connection->websocketHandshake = true; $connection->context->websocketHandshake = true;
// Try to emit onWebSocketConnect callback.
$on_websocket_connect = isset($connection->onWebSocketConnect) ? $connection->onWebSocketConnect :
(isset($connection->worker->onWebSocketConnect) ? $connection->worker->onWebSocketConnect : false);
if ($on_websocket_connect) {
static::parseHttpHeader($buffer);
try {
\call_user_func($on_websocket_connect, $connection, $buffer);
} catch (\Exception $e) {
Worker::stopAll(250, $e);
} catch (\Error $e) {
Worker::stopAll(250, $e);
}
if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) {
$connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION);
}
$_GET = $_SERVER = $_SESSION = $_COOKIE = array();
}
// There are data waiting to be sent. // There are data waiting to be sent.
if (!empty($connection->tmpWebsocketData)) { if (!empty($connection->context->tmpWebsocketData)) {
$connection->send($connection->tmpWebsocketData, true); $connection->send($connection->context->tmpWebsocketData, true);
$connection->tmpWebsocketData = ''; $connection->context->tmpWebsocketData = '';
} }
if (\strlen($buffer) > $header_length) { if (\strlen($buffer) > $header_length) {
return static::input(\substr($buffer, $header_length), $connection); return static::input(\substr($buffer, $header_length), $connection);
} }
return 0; return 0;
} // Is flash policy-file-request.
elseif (0 === \strpos($buffer, '<polic')) {
$policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . "\0";
$connection->send($policy_xml, true);
$connection->consumeRecvBuffer(\strlen($buffer));
return 0;
} }
// Bad websocket handshake request. // Bad websocket handshake request.
$connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n<div style=\"text-align:center\"><h1>WebSocket</h1><hr>workerman/" . Worker::VERSION . "</div>", $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n<div style=\"text-align:center\"><h1>WebSocket</h1><hr>workerman/" . Worker::VERSION . "</div>",
@ -492,4 +560,5 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
$_SERVER['QUERY_STRING'] = ''; $_SERVER['QUERY_STRING'] = '';
} }
} }
} }

View File

@ -210,7 +210,9 @@ class Timer
public static function delAll() public static function delAll()
{ {
self::$_tasks = self::$_status = array(); self::$_tasks = self::$_status = array();
if (\function_exists('pcntl_alarm')) {
\pcntl_alarm(0); \pcntl_alarm(0);
}
if (self::$_event) { if (self::$_event) {
self::$_event->clearAllTimer(); self::$_event->clearAllTimer();
} }

View File

@ -34,7 +34,7 @@ class Worker
* *
* @var string * @var string
*/ */
const VERSION = '4.1.4'; const VERSION = '4.1.5';
/** /**
* Status starting. * Status starting.
@ -1218,7 +1218,7 @@ class Worker
case \SIGINT: case \SIGINT:
case \SIGTERM: case \SIGTERM:
case \SIGHUP: case \SIGHUP:
case \SIGTSTP; case \SIGTSTP:
static::$_gracefulStop = false; static::$_gracefulStop = false;
static::stopAll(); static::stopAll();
break; break;
@ -1304,7 +1304,7 @@ class Worker
$STDOUT = \fopen(static::$stdoutFile, "a"); $STDOUT = \fopen(static::$stdoutFile, "a");
$STDERR = \fopen(static::$stdoutFile, "a"); $STDERR = \fopen(static::$stdoutFile, "a");
// Fix standard output cannot redirect of PHP 8.1.8's bug // Fix standard output cannot redirect of PHP 8.1.8's bug
if (\posix_isatty(2)) { if (\function_exists('posix_isatty') && \posix_isatty(2)) {
\ob_start(function ($string) { \ob_start(function ($string) {
\file_put_contents(static::$stdoutFile, $string, FILE_APPEND); \file_put_contents(static::$stdoutFile, $string, FILE_APPEND);
}, 1); }, 1);
@ -1610,7 +1610,7 @@ class Worker
// Get uid. // Get uid.
$user_info = \posix_getpwnam($this->user); $user_info = \posix_getpwnam($this->user);
if (!$user_info) { if (!$user_info) {
static::log("Warning: User {$this->user} not exsits"); static::log("Warning: User {$this->user} not exists");
return; return;
} }
$uid = $user_info['uid']; $uid = $user_info['uid'];
@ -1618,7 +1618,7 @@ class Worker
if ($this->group) { if ($this->group) {
$group_info = \posix_getgrnam($this->group); $group_info = \posix_getgrnam($this->group);
if (!$group_info) { if (!$group_info) {
static::log("Warning: Group {$this->group} not exsits"); static::log("Warning: Group {$this->group} not exists");
return; return;
} }
$gid = $group_info['gid']; $gid = $group_info['gid'];

View File

@ -291,7 +291,7 @@ class Request
//请求头 //请求头
$requestHeaders = []; $requestHeaders = [];
foreach ( $request->getHeaders() as $k => $vs ) { foreach ( (array)$request->getHeaders() as $k => $vs ) {
foreach ( $vs as $v ) { foreach ( $vs as $v ) {
$requestHeaders[] = "$k: $v"; $requestHeaders[] = "$k: $v";
} }
@ -300,7 +300,7 @@ class Request
//响应头 //响应头
$responseHeaders = []; $responseHeaders = [];
foreach ( $response->getHeaders() as $k => $vs ) { foreach ( (array)$response->getHeaders() as $k => $vs ) {
foreach ( $vs as $v ) { foreach ( $vs as $v ) {
$responseHeaders[] = "$k: $v"; $responseHeaders[] = "$k: $v";
} }

View File

@ -12,7 +12,6 @@
<div class="layui-form layui-form-pane layui-tab-item layui-show"> <div class="layui-form layui-form-pane layui-tab-item layui-show">
<div class="layui-form-item"> <div class="layui-form-item">
<label for="L_email" class="layui-form-label">邮箱</label> <label for="L_email" class="layui-form-label">邮箱</label>
<input type="hidden" name="user_id" value="{:session('user_id')}">
<div class="layui-input-inline"> <div class="layui-input-inline">
<input type="text" id="L_email" name="email" lay-verify="email" autocomplete="off" value="{$user.email}" class="layui-input" placeholder="{$user.email}"> <input type="text" id="L_email" name="email" lay-verify="email" autocomplete="off" value="{$user.email}" class="layui-input" placeholder="{$user.email}">
</div> </div>