mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°5809 Update laminas/laminas-mail from 2.16.0 to 2.22.0
This commit is contained in:
@@ -817,6 +817,8 @@ return array(
|
||||
'Laminas\\Mail\\Protocol\\Exception\\RuntimeException' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Exception/RuntimeException.php',
|
||||
'Laminas\\Mail\\Protocol\\Imap' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Imap.php',
|
||||
'Laminas\\Mail\\Protocol\\Pop3' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Pop3.php',
|
||||
'Laminas\\Mail\\Protocol\\Pop3\\Response' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Pop3/Response.php',
|
||||
'Laminas\\Mail\\Protocol\\Pop3\\Xoauth2\\Microsoft' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Pop3/Xoauth2/Microsoft.php',
|
||||
'Laminas\\Mail\\Protocol\\ProtocolTrait' => $vendorDir . '/laminas/laminas-mail/src/Protocol/ProtocolTrait.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Smtp.php',
|
||||
'Laminas\\Mail\\Protocol\\SmtpPluginManager' => $vendorDir . '/laminas/laminas-mail/src/Protocol/SmtpPluginManager.php',
|
||||
@@ -824,6 +826,8 @@ return array(
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Crammd5' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Crammd5.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Login' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Login.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Plain' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Plain.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Xoauth2' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Xoauth2.php',
|
||||
'Laminas\\Mail\\Protocol\\Xoauth2\\Xoauth2' => $vendorDir . '/laminas/laminas-mail/src/Protocol/Xoauth2/Xoauth2.php',
|
||||
'Laminas\\Mail\\Storage' => $vendorDir . '/laminas/laminas-mail/src/Storage.php',
|
||||
'Laminas\\Mail\\Storage\\AbstractStorage' => $vendorDir . '/laminas/laminas-mail/src/Storage/AbstractStorage.php',
|
||||
'Laminas\\Mail\\Storage\\Exception\\ExceptionInterface' => $vendorDir . '/laminas/laminas-mail/src/Storage/Exception/ExceptionInterface.php',
|
||||
|
||||
@@ -1192,6 +1192,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Laminas\\Mail\\Protocol\\Exception\\RuntimeException' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Exception/RuntimeException.php',
|
||||
'Laminas\\Mail\\Protocol\\Imap' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Imap.php',
|
||||
'Laminas\\Mail\\Protocol\\Pop3' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Pop3.php',
|
||||
'Laminas\\Mail\\Protocol\\Pop3\\Response' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Pop3/Response.php',
|
||||
'Laminas\\Mail\\Protocol\\Pop3\\Xoauth2\\Microsoft' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Pop3/Xoauth2/Microsoft.php',
|
||||
'Laminas\\Mail\\Protocol\\ProtocolTrait' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/ProtocolTrait.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Smtp.php',
|
||||
'Laminas\\Mail\\Protocol\\SmtpPluginManager' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/SmtpPluginManager.php',
|
||||
@@ -1199,6 +1201,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Crammd5' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Crammd5.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Login' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Login.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Plain' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Plain.php',
|
||||
'Laminas\\Mail\\Protocol\\Smtp\\Auth\\Xoauth2' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Smtp/Auth/Xoauth2.php',
|
||||
'Laminas\\Mail\\Protocol\\Xoauth2\\Xoauth2' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Protocol/Xoauth2/Xoauth2.php',
|
||||
'Laminas\\Mail\\Storage' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Storage.php',
|
||||
'Laminas\\Mail\\Storage\\AbstractStorage' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Storage/AbstractStorage.php',
|
||||
'Laminas\\Mail\\Storage\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/laminas/laminas-mail/src/Storage/Exception/ExceptionInterface.php',
|
||||
|
||||
@@ -557,30 +557,30 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-loader",
|
||||
"version": "2.8.0",
|
||||
"version_normalized": "2.8.0.0",
|
||||
"version": "2.10.0",
|
||||
"version_normalized": "2.10.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-loader.git",
|
||||
"reference": "d0589ec9dd48365fd95ad10d1c906efd7711c16b"
|
||||
"reference": "e6fe952304ef40ce45cd814751ab35d42afdad12"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-loader/zipball/d0589ec9dd48365fd95ad10d1c906efd7711c16b",
|
||||
"reference": "d0589ec9dd48365fd95ad10d1c906efd7711c16b",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-loader/zipball/e6fe952304ef40ce45cd814751ab35d42afdad12",
|
||||
"reference": "e6fe952304ef40ce45cd814751ab35d42afdad12",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0"
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-loader": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.2.1",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
"laminas/laminas-coding-standard": "~2.4.0",
|
||||
"phpunit/phpunit": "~9.5.25"
|
||||
},
|
||||
"time": "2021-09-02T18:30:53+00:00",
|
||||
"time": "2023-10-18T09:58:51+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
@@ -616,48 +616,45 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-mail",
|
||||
"version": "2.16.0",
|
||||
"version_normalized": "2.16.0.0",
|
||||
"version": "2.22.0",
|
||||
"version_normalized": "2.22.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-mail.git",
|
||||
"reference": "1ee1a384b96c8af29ecad9b3a7adc27a150ebc49"
|
||||
"reference": "1d307ff65328c00117c6d90ba0084fdd0fc2bd5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-mail/zipball/1ee1a384b96c8af29ecad9b3a7adc27a150ebc49",
|
||||
"reference": "1ee1a384b96c8af29ecad9b3a7adc27a150ebc49",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-mail/zipball/1d307ff65328c00117c6d90ba0084fdd0fc2bd5c",
|
||||
"reference": "1d307ff65328c00117c6d90ba0084fdd0fc2bd5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"laminas/laminas-loader": "^2.8",
|
||||
"laminas/laminas-mime": "^2.9.1",
|
||||
"laminas/laminas-stdlib": "^3.6",
|
||||
"laminas/laminas-validator": "^2.15",
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0",
|
||||
"symfony/polyfill-intl-idn": "^1.24.0",
|
||||
"symfony/polyfill-mbstring": "^1.12.0",
|
||||
"webmozart/assert": "^1.10"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-mail": "*"
|
||||
"laminas/laminas-loader": "^2.8.0",
|
||||
"laminas/laminas-mime": "^2.10.0",
|
||||
"laminas/laminas-stdlib": "^3.11.0",
|
||||
"laminas/laminas-validator": "^2.23.0",
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0",
|
||||
"symfony/polyfill-intl-idn": "^1.26.0",
|
||||
"symfony/polyfill-mbstring": "^1.16.0",
|
||||
"webmozart/assert": "^1.11.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~1.0.0",
|
||||
"laminas/laminas-crypt": "^2.6 || ^3.4",
|
||||
"laminas/laminas-db": "^2.13.3",
|
||||
"laminas/laminas-servicemanager": "^3.7",
|
||||
"phpunit/phpunit": "^9.5.5",
|
||||
"psalm/plugin-phpunit": "^0.15.1",
|
||||
"symfony/process": "^5.3.7",
|
||||
"vimeo/psalm": "^4.7"
|
||||
"laminas/laminas-coding-standard": "~2.5.0",
|
||||
"laminas/laminas-crypt": "^3.9.0",
|
||||
"laminas/laminas-db": "^2.16",
|
||||
"laminas/laminas-servicemanager": "^3.20",
|
||||
"phpunit/phpunit": "^9.5.26",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"symfony/process": "^6.0.11",
|
||||
"vimeo/psalm": "^5.1"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-crypt": "Crammd5 support in SMTP Auth",
|
||||
"laminas/laminas-servicemanager": "^2.7.10 || ^3.3.1 when using SMTP to deliver messages"
|
||||
"laminas/laminas-crypt": "^3.8 Crammd5 support in SMTP Auth",
|
||||
"laminas/laminas-servicemanager": "^3.16 when using SMTP to deliver messages"
|
||||
},
|
||||
"time": "2022-02-23T21:08:17+00:00",
|
||||
"time": "2023-01-18T08:33:48+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laminas": {
|
||||
@@ -699,35 +696,35 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-mime",
|
||||
"version": "2.9.1",
|
||||
"version_normalized": "2.9.1.0",
|
||||
"version": "2.12.0",
|
||||
"version_normalized": "2.12.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-mime.git",
|
||||
"reference": "72d21a1b4bb7086d4a4d7058c0abca180b209184"
|
||||
"reference": "08cc544778829b7d68d27a097885bd6e7130135e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-mime/zipball/72d21a1b4bb7086d4a4d7058c0abca180b209184",
|
||||
"reference": "72d21a1b4bb7086d4a4d7058c0abca180b209184",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-mime/zipball/08cc544778829b7d68d27a097885bd6e7130135e",
|
||||
"reference": "08cc544778829b7d68d27a097885bd6e7130135e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laminas/laminas-stdlib": "^2.7 || ^3.0",
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0"
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-mime": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.2.1",
|
||||
"laminas/laminas-mail": "^2.12",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
"laminas/laminas-coding-standard": "~2.4.0",
|
||||
"laminas/laminas-mail": "^2.19.0",
|
||||
"phpunit/phpunit": "~9.5.25"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-mail": "Laminas\\Mail component"
|
||||
},
|
||||
"time": "2021-09-20T21:19:24+00:00",
|
||||
"time": "2023-11-02T16:47:19+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
@@ -857,34 +854,33 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-stdlib",
|
||||
"version": "3.12.0",
|
||||
"version_normalized": "3.12.0.0",
|
||||
"version": "3.19.0",
|
||||
"version_normalized": "3.19.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-stdlib.git",
|
||||
"reference": "c5aed3c798018e31fbb7b1e421b8d96bf2cda453"
|
||||
"reference": "6a192dd0882b514e45506f533b833b623b78fff3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/c5aed3c798018e31fbb7b1e421b8d96bf2cda453",
|
||||
"reference": "c5aed3c798018e31fbb7b1e421b8d96bf2cda453",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/6a192dd0882b514e45506f533b833b623b78fff3",
|
||||
"reference": "6a192dd0882b514e45506f533b833b623b78fff3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0"
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-stdlib": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.3.0",
|
||||
"phpbench/phpbench": "^1.2.6",
|
||||
"phpstan/phpdoc-parser": "^0.5.4",
|
||||
"phpunit/phpunit": "^9.5.23",
|
||||
"psalm/plugin-phpunit": "^0.17.0",
|
||||
"vimeo/psalm": "^4.26"
|
||||
"laminas/laminas-coding-standard": "^2.5",
|
||||
"phpbench/phpbench": "^1.2.15",
|
||||
"phpunit/phpunit": "^10.5.8",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"vimeo/psalm": "^5.20.0"
|
||||
},
|
||||
"time": "2022-08-22T22:55:58+00:00",
|
||||
"time": "2024-01-19T12:39:49+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
@@ -920,42 +916,41 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-validator",
|
||||
"version": "2.23.0",
|
||||
"version_normalized": "2.23.0.0",
|
||||
"version": "2.27.0",
|
||||
"version_normalized": "2.27.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-validator.git",
|
||||
"reference": "6d61b6cc3b222f13807a18d9247cdfb084958b03"
|
||||
"reference": "451f5e24574a99b86e8e22f0431ccfc6d5c7318b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-validator/zipball/6d61b6cc3b222f13807a18d9247cdfb084958b03",
|
||||
"reference": "6d61b6cc3b222f13807a18d9247cdfb084958b03",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-validator/zipball/451f5e24574a99b86e8e22f0431ccfc6d5c7318b",
|
||||
"reference": "451f5e24574a99b86e8e22f0431ccfc6d5c7318b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laminas/laminas-servicemanager": "^3.12.0",
|
||||
"laminas/laminas-stdlib": "^3.10",
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0"
|
||||
"laminas/laminas-stdlib": "^3.13",
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-validator": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.3.0",
|
||||
"laminas/laminas-db": "^2.7",
|
||||
"laminas/laminas-filter": "^2.14.0",
|
||||
"laminas/laminas-http": "^2.14.2",
|
||||
"laminas/laminas-i18n": "^2.15.0",
|
||||
"laminas/laminas-session": "^2.12.1",
|
||||
"laminas/laminas-uri": "^2.9.1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.5.21",
|
||||
"psalm/plugin-phpunit": "^0.17.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"vimeo/psalm": "^4.24.0"
|
||||
"laminas/laminas-coding-standard": "^2.4.0",
|
||||
"laminas/laminas-db": "^2.15.0",
|
||||
"laminas/laminas-filter": "^2.23.0",
|
||||
"laminas/laminas-http": "^2.17.0",
|
||||
"laminas/laminas-i18n": "^2.19",
|
||||
"laminas/laminas-session": "^2.13.0",
|
||||
"laminas/laminas-uri": "^2.10.0",
|
||||
"phpunit/phpunit": "^9.5.25",
|
||||
"psalm/plugin-phpunit": "^0.18.0",
|
||||
"psr/http-client": "^1.0.1",
|
||||
"psr/http-factory": "^1.0.1",
|
||||
"psr/http-message": "^1.0.1",
|
||||
"vimeo/psalm": "^4.28"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-db": "Laminas\\Db component, required by the (No)RecordExists validator",
|
||||
@@ -967,7 +962,7 @@
|
||||
"laminas/laminas-uri": "Laminas\\Uri component, required by the Uri and Sitemap\\Loc validators",
|
||||
"psr/http-message": "psr/http-message, required when validating PSR-7 UploadedFileInterface instances via the Upload and UploadFile validators"
|
||||
},
|
||||
"time": "2022-07-27T19:17:59+00:00",
|
||||
"time": "2022-11-12T21:00:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laminas": {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'name' => 'combodo/itop',
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => '3c17b5ed7e1db817b582dbb626be0cc6765e8f67',
|
||||
'reference' => '23a187a4582feb216abfcb822e06e2d9d1cf3705',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -22,7 +22,7 @@
|
||||
'combodo/itop' => array(
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => '3c17b5ed7e1db817b582dbb626be0cc6765e8f67',
|
||||
'reference' => '23a187a4582feb216abfcb822e06e2d9d1cf3705',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -80,27 +80,27 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'laminas/laminas-loader' => array(
|
||||
'pretty_version' => '2.8.0',
|
||||
'version' => '2.8.0.0',
|
||||
'reference' => 'd0589ec9dd48365fd95ad10d1c906efd7711c16b',
|
||||
'pretty_version' => '2.10.0',
|
||||
'version' => '2.10.0.0',
|
||||
'reference' => 'e6fe952304ef40ce45cd814751ab35d42afdad12',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laminas/laminas-loader',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'laminas/laminas-mail' => array(
|
||||
'pretty_version' => '2.16.0',
|
||||
'version' => '2.16.0.0',
|
||||
'reference' => '1ee1a384b96c8af29ecad9b3a7adc27a150ebc49',
|
||||
'pretty_version' => '2.22.0',
|
||||
'version' => '2.22.0.0',
|
||||
'reference' => '1d307ff65328c00117c6d90ba0084fdd0fc2bd5c',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laminas/laminas-mail',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'laminas/laminas-mime' => array(
|
||||
'pretty_version' => '2.9.1',
|
||||
'version' => '2.9.1.0',
|
||||
'reference' => '72d21a1b4bb7086d4a4d7058c0abca180b209184',
|
||||
'pretty_version' => '2.12.0',
|
||||
'version' => '2.12.0.0',
|
||||
'reference' => '08cc544778829b7d68d27a097885bd6e7130135e',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laminas/laminas-mime',
|
||||
'aliases' => array(),
|
||||
@@ -116,18 +116,18 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'laminas/laminas-stdlib' => array(
|
||||
'pretty_version' => '3.12.0',
|
||||
'version' => '3.12.0.0',
|
||||
'reference' => 'c5aed3c798018e31fbb7b1e421b8d96bf2cda453',
|
||||
'pretty_version' => '3.19.0',
|
||||
'version' => '3.19.0.0',
|
||||
'reference' => '6a192dd0882b514e45506f533b833b623b78fff3',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laminas/laminas-stdlib',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'laminas/laminas-validator' => array(
|
||||
'pretty_version' => '2.23.0',
|
||||
'version' => '2.23.0.0',
|
||||
'reference' => '6d61b6cc3b222f13807a18d9247cdfb084958b03',
|
||||
'pretty_version' => '2.27.0',
|
||||
'version' => '2.27.0.0',
|
||||
'reference' => '451f5e24574a99b86e8e22f0431ccfc6d5c7318b',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laminas/laminas-validator',
|
||||
'aliases' => array(),
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ignore_php_platform_requirements": {
|
||||
"8.1": true
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,22 @@
|
||||
# laminas-loader
|
||||
|
||||
> ## 🇷🇺 Русским гражданам
|
||||
>
|
||||
> Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм.
|
||||
>
|
||||
> У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую.
|
||||
>
|
||||
> Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!"
|
||||
>
|
||||
> ## 🇺🇸 To Citizens of Russia
|
||||
>
|
||||
> We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism.
|
||||
>
|
||||
> One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences.
|
||||
>
|
||||
> You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!"
|
||||
|
||||
|
||||
> This package is considered feature-complete, and is now in **security-only** maintenance mode, following a [decision by the Technical Steering Committee](https://github.com/laminas/technical-steering-committee/blob/2b55453e172a1b8c9c4c212be7cf7e7a58b9352c/meetings/minutes/2020-08-03-TSC-Minutes.md#vote-on-components-to-mark-as-security-only).
|
||||
> If you have a security issue, please [follow our security reporting guidelines](https://getlaminas.org/security/).
|
||||
> If you wish to take on the role of maintainer, please [nominate yourself](https://github.com/laminas/technical-steering-committee/issues/new?assignees=&labels=Nomination&template=Maintainer_Nomination.md&title=%5BNOMINATION%5D%5BMAINTAINER%5D%3A+%7Bname+of+person+being+nominated%7D)
|
||||
|
||||
@@ -16,14 +16,17 @@
|
||||
"forum": "https://discourse.laminas.dev"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0"
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.2.1",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
"laminas/laminas-coding-standard": "~2.4.0",
|
||||
"phpunit/phpunit": "~9.5.25"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
714
lib/laminas/laminas-loader/composer.lock
generated
714
lib/laminas/laminas-loader/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="./vendor/squizlabs/php_codesniffer/phpcs.xsd">
|
||||
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="cache" value=".phpcs-cache"/>
|
||||
<arg name="colors"/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="parallel" value="80"/>
|
||||
|
||||
<!-- Show progress -->
|
||||
<arg value="p"/>
|
||||
|
||||
<!-- Paths to check -->
|
||||
<file>src</file>
|
||||
<file>test</file>
|
||||
<exclude-pattern>*/TestAsset/*</exclude-pattern>
|
||||
<exclude-pattern>*/_files/*</exclude-pattern>
|
||||
|
||||
<!-- Include all rules from Laminas Coding Standard -->
|
||||
<rule ref="LaminasCodingStandard"/>
|
||||
|
||||
<rule ref="PSR1.Files.SideEffects">
|
||||
<exclude-pattern>/src/Exception/*</exclude-pattern>
|
||||
<exclude-pattern>/src/SplAutoloader.php</exclude-pattern>
|
||||
<exclude-pattern>/src/AutoloaderFactory.php</exclude-pattern>
|
||||
<exclude-pattern>/src/ClassMapAutoloader.php</exclude-pattern>
|
||||
<exclude-pattern>/src/ModuleAutoloader.php</exclude-pattern>
|
||||
<exclude-pattern>/src/StandardAutoloader.php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ignore_php_platform_requirements": {
|
||||
"8.1": true
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
INTL_EXTENSION=$(php -r 'echo sprintf("php%s.%s-intl",PHP_MAJOR_VERSION,PHP_MINOR_VERSION);')
|
||||
|
||||
echo -e "Removing $INTL_EXTENSION extension:\n"
|
||||
sudo apt remove "$INTL_EXTENSION" -y
|
||||
|
||||
echo -e "Cleaning up:\n"
|
||||
sudo apt autoclean && sudo apt autoremove
|
||||
|
||||
echo -e "Installed extensions:\n"
|
||||
/usr/local/bin/php-extensions-with-version.php
|
||||
@@ -2,6 +2,22 @@
|
||||
|
||||
[](https://github.com/laminas/laminas-mail/actions?query=workflow%3A"Continuous+Integration")
|
||||
|
||||
> ## 🇷🇺 Русским гражданам
|
||||
>
|
||||
> Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм.
|
||||
>
|
||||
> У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую.
|
||||
>
|
||||
> Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!"
|
||||
>
|
||||
> ## 🇺🇸 To Citizens of Russia
|
||||
>
|
||||
> We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism.
|
||||
>
|
||||
> One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences.
|
||||
>
|
||||
> You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!"
|
||||
|
||||
`Laminas\Mail` provides generalized functionality to compose and send both text and
|
||||
MIME-compliant multipart email messages. Mail can be sent with `Laminas\Mail` via
|
||||
the `Mail\Transport\Sendmail`, `Mail\Transport\Smtp` or the `Mail\Transport\File`
|
||||
|
||||
@@ -8,40 +8,38 @@
|
||||
"homepage": "https://laminas.dev",
|
||||
"license": "BSD-3-Clause",
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0",
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0",
|
||||
"ext-iconv": "*",
|
||||
"laminas/laminas-loader": "^2.8",
|
||||
"laminas/laminas-mime": "^2.9.1",
|
||||
"laminas/laminas-stdlib": "^3.6",
|
||||
"laminas/laminas-validator": "^2.15",
|
||||
"symfony/polyfill-mbstring": "^1.12.0",
|
||||
"webmozart/assert": "^1.10",
|
||||
"symfony/polyfill-intl-idn": "^1.24.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-mail": "*"
|
||||
"laminas/laminas-loader": "^2.8.0",
|
||||
"laminas/laminas-mime": "^2.10.0",
|
||||
"laminas/laminas-stdlib": "^3.11.0",
|
||||
"laminas/laminas-validator": "^2.23.0",
|
||||
"symfony/polyfill-mbstring": "^1.16.0",
|
||||
"webmozart/assert": "^1.11.0",
|
||||
"symfony/polyfill-intl-idn": "^1.26.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~1.0.0",
|
||||
"laminas/laminas-crypt": "^2.6 || ^3.4",
|
||||
"laminas/laminas-db": "^2.13.3",
|
||||
"laminas/laminas-servicemanager": "^3.7",
|
||||
"phpunit/phpunit": "^9.5.5",
|
||||
"psalm/plugin-phpunit": "^0.15.1",
|
||||
"symfony/process": "^5.3.7",
|
||||
"vimeo/psalm": "^4.7"
|
||||
"laminas/laminas-coding-standard": "~2.5.0",
|
||||
"laminas/laminas-crypt": "^3.9.0",
|
||||
"laminas/laminas-db": "^2.16",
|
||||
"laminas/laminas-servicemanager": "^3.20",
|
||||
"phpunit/phpunit": "^9.5.26",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"symfony/process": "^6.0.11",
|
||||
"vimeo/psalm": "^5.1"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-crypt": "Crammd5 support in SMTP Auth",
|
||||
"laminas/laminas-servicemanager": "^2.7.10 || ^3.3.1 when using SMTP to deliver messages"
|
||||
"laminas/laminas-crypt": "^3.8 Crammd5 support in SMTP Auth",
|
||||
"laminas/laminas-servicemanager": "^3.16 when using SMTP to deliver messages"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
},
|
||||
"platform": {
|
||||
"php": "7.3.99"
|
||||
"php": "8.0.99"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
|
||||
1783
lib/laminas/laminas-mail/composer.lock
generated
1783
lib/laminas/laminas-mail/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,19 @@ namespace Laminas\Mail;
|
||||
use Laminas\Validator\EmailAddress as EmailAddressValidator;
|
||||
use Laminas\Validator\Hostname;
|
||||
|
||||
use function array_shift;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function trim;
|
||||
|
||||
class Address implements Address\AddressInterface
|
||||
{
|
||||
/** @var null|string */
|
||||
protected $comment;
|
||||
/** @var string */
|
||||
protected $email;
|
||||
/** @var null|string */
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
@@ -149,7 +158,7 @@ class Address implements Address\AddressInterface
|
||||
*/
|
||||
private function constructName()
|
||||
{
|
||||
$name = $this->getName();
|
||||
$name = $this->getName();
|
||||
$comment = $this->getComment();
|
||||
|
||||
if ($comment === null || $comment === '') {
|
||||
|
||||
@@ -4,24 +4,43 @@ namespace Laminas\Mail;
|
||||
|
||||
use Countable;
|
||||
use Iterator;
|
||||
use Laminas\Mail\Address\AddressInterface;
|
||||
use ReturnTypeWillChange;
|
||||
|
||||
use function count;
|
||||
use function current;
|
||||
use function gettype;
|
||||
use function is_int;
|
||||
use function is_numeric;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function key;
|
||||
use function next;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* @implements Iterator<string, AddressInterface>
|
||||
* @final
|
||||
*/
|
||||
class AddressList implements Countable, Iterator
|
||||
{
|
||||
/**
|
||||
* List of Address objects we're managing
|
||||
*
|
||||
* @var array
|
||||
* @var array<string, AddressInterface>
|
||||
*/
|
||||
protected $addresses = [];
|
||||
|
||||
/**
|
||||
* Add an address to the list
|
||||
*
|
||||
* @param string|Address\AddressInterface $emailOrAddress
|
||||
* @param string|AddressInterface $emailOrAddress
|
||||
* @param null|string $name
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function add($emailOrAddress, $name = null)
|
||||
{
|
||||
@@ -29,12 +48,12 @@ class AddressList implements Countable, Iterator
|
||||
$emailOrAddress = $this->createAddress($emailOrAddress, $name);
|
||||
}
|
||||
|
||||
if (! $emailOrAddress instanceof Address\AddressInterface) {
|
||||
if (! $emailOrAddress instanceof AddressInterface) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects an email address or %s\Address object as its first argument; received "%s"',
|
||||
__METHOD__,
|
||||
__NAMESPACE__,
|
||||
(is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
|
||||
is_object($emailOrAddress) ? $emailOrAddress::class : gettype($emailOrAddress)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -56,7 +75,7 @@ class AddressList implements Countable, Iterator
|
||||
*
|
||||
* @param array $addresses
|
||||
* @throws Exception\RuntimeException
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function addMany(array $addresses)
|
||||
{
|
||||
@@ -69,7 +88,7 @@ class AddressList implements Countable, Iterator
|
||||
if (! is_string($key)) {
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
'Invalid key type in provided addresses array ("%s")',
|
||||
(is_object($key) ? get_class($key) : var_export($key, 1))
|
||||
is_object($key) ? $key::class : var_export($key, true)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -86,7 +105,7 @@ class AddressList implements Countable, Iterator
|
||||
* @param string $address
|
||||
* @param null|string $comment Comment associated with the address, if any.
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function addFromString($address, $comment = null)
|
||||
{
|
||||
@@ -97,8 +116,7 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Merge another address list into this one
|
||||
*
|
||||
* @param AddressList $addressList
|
||||
* @return AddressList
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(self $addressList)
|
||||
{
|
||||
@@ -124,7 +142,7 @@ class AddressList implements Countable, Iterator
|
||||
* Get an address by email
|
||||
*
|
||||
* @param string $email
|
||||
* @return bool|Address\AddressInterface
|
||||
* @return false|AddressInterface
|
||||
*/
|
||||
public function get($email)
|
||||
{
|
||||
@@ -167,9 +185,10 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Rewind iterator
|
||||
*
|
||||
* @return mixed the value of the first addresses element, or false if the addresses is
|
||||
* empty.
|
||||
* @see addresses
|
||||
*
|
||||
* @return false|AddressInterface the value of the first addresses element, or false if the addresses is
|
||||
* empty.
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
@@ -180,7 +199,7 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Return current item in iteration
|
||||
*
|
||||
* @return Address
|
||||
* @return AddressInterface
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -202,9 +221,10 @@ class AddressList implements Countable, Iterator
|
||||
/**
|
||||
* Move to next item
|
||||
*
|
||||
* @return mixed the addresses value in the next place that's pointed to by the
|
||||
* internal array pointer, or false if there are no more elements.
|
||||
* @see addresses
|
||||
*
|
||||
* @return false|AddressInterface the addresses value in the next place that's pointed to by the
|
||||
* internal array pointer, or false if there are no more elements.
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
@@ -221,7 +241,7 @@ class AddressList implements Countable, Iterator
|
||||
public function valid()
|
||||
{
|
||||
$key = key($this->addresses);
|
||||
return ($key !== null && $key !== false);
|
||||
return $key !== null && $key !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,8 +25,8 @@ class ConfigProvider
|
||||
{
|
||||
return [
|
||||
// Legacy Zend Framework aliases
|
||||
'aliases' => [
|
||||
\Zend\Mail\Protocol\SmtpPluginManager::class => Protocol\SmtpPluginManager::class,
|
||||
'aliases' => [
|
||||
'Zend\Mail\Protocol\SmtpPluginManager' => Protocol\SmtpPluginManager::class,
|
||||
],
|
||||
'factories' => [
|
||||
Protocol\SmtpPluginManager::class => Protocol\SmtpPluginManagerFactory::class,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Laminas\Mail\Exception;
|
||||
|
||||
interface ExceptionInterface
|
||||
use Throwable;
|
||||
|
||||
interface ExceptionInterface extends Throwable
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6,7 +6,39 @@ use Laminas\Mail\Address;
|
||||
use Laminas\Mail\AddressList;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mail\Storage\Exception\RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function idn_to_ascii;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function preg_match_all;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
use const IDNA_DEFAULT;
|
||||
use const IDNA_ERROR_BIDI;
|
||||
use const IDNA_ERROR_CONTEXTJ;
|
||||
use const IDNA_ERROR_DISALLOWED;
|
||||
use const IDNA_ERROR_DOMAIN_NAME_TOO_LONG;
|
||||
use const IDNA_ERROR_EMPTY_LABEL;
|
||||
use const IDNA_ERROR_HYPHEN_3_4;
|
||||
use const IDNA_ERROR_INVALID_ACE_LABEL;
|
||||
use const IDNA_ERROR_LABEL_HAS_DOT;
|
||||
use const IDNA_ERROR_LABEL_TOO_LONG;
|
||||
use const IDNA_ERROR_LEADING_COMBINING_MARK;
|
||||
use const IDNA_ERROR_LEADING_HYPHEN;
|
||||
use const IDNA_ERROR_PUNYCODE;
|
||||
use const IDNA_ERROR_TRAILING_HYPHEN;
|
||||
use const INTL_IDNA_VARIANT_UTS46;
|
||||
|
||||
/**
|
||||
* Base class for headers composing address lists (to, from, cc, bcc, reply-to)
|
||||
@@ -14,29 +46,25 @@ use Throwable;
|
||||
abstract class AbstractAddressList implements HeaderInterface
|
||||
{
|
||||
private const IDNA_ERROR_MAP = [
|
||||
IDNA_ERROR_EMPTY_LABEL => 'empty label',
|
||||
IDNA_ERROR_LABEL_TOO_LONG => 'label too long',
|
||||
IDNA_ERROR_DOMAIN_NAME_TOO_LONG => 'domain name too long',
|
||||
IDNA_ERROR_LEADING_HYPHEN => 'leading hyphen',
|
||||
IDNA_ERROR_TRAILING_HYPHEN => 'trailing hyphen',
|
||||
IDNA_ERROR_HYPHEN_3_4 => 'consecutive hyphens',
|
||||
IDNA_ERROR_EMPTY_LABEL => 'empty label',
|
||||
IDNA_ERROR_LABEL_TOO_LONG => 'label too long',
|
||||
IDNA_ERROR_DOMAIN_NAME_TOO_LONG => 'domain name too long',
|
||||
IDNA_ERROR_LEADING_HYPHEN => 'leading hyphen',
|
||||
IDNA_ERROR_TRAILING_HYPHEN => 'trailing hyphen',
|
||||
IDNA_ERROR_HYPHEN_3_4 => 'consecutive hyphens',
|
||||
IDNA_ERROR_LEADING_COMBINING_MARK => 'leading combining mark',
|
||||
IDNA_ERROR_DISALLOWED => 'disallowed',
|
||||
IDNA_ERROR_PUNYCODE => 'invalid punycode encoding',
|
||||
IDNA_ERROR_LABEL_HAS_DOT => 'has dot',
|
||||
IDNA_ERROR_INVALID_ACE_LABEL => 'label not in ASCII encoding',
|
||||
IDNA_ERROR_BIDI => 'fails bidirectional criteria',
|
||||
IDNA_ERROR_CONTEXTJ => 'one or more characters fail CONTEXTJ rule',
|
||||
IDNA_ERROR_DISALLOWED => 'disallowed',
|
||||
IDNA_ERROR_PUNYCODE => 'invalid punycode encoding',
|
||||
IDNA_ERROR_LABEL_HAS_DOT => 'has dot',
|
||||
IDNA_ERROR_INVALID_ACE_LABEL => 'label not in ASCII encoding',
|
||||
IDNA_ERROR_BIDI => 'fails bidirectional criteria',
|
||||
IDNA_ERROR_CONTEXTJ => 'one or more characters fail CONTEXTJ rule',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var AddressList
|
||||
*/
|
||||
/** @var AddressList */
|
||||
protected $addressList;
|
||||
|
||||
/**
|
||||
* @var string Normalized field name
|
||||
*/
|
||||
/** @var string Normalized field name */
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
@@ -46,40 +74,42 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
*/
|
||||
protected $encoding = 'ASCII';
|
||||
|
||||
/**
|
||||
* @var string lower case field name
|
||||
*/
|
||||
/** @var string lower case field name */
|
||||
protected static $type;
|
||||
|
||||
/** @var string[] lower case aliases for the field name */
|
||||
protected static $typeAliases = [];
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
|
||||
if (strtolower($fieldName) !== static::$type) {
|
||||
[$fieldName, $fieldValue] = GenericHeader::splitHeaderLine($headerLine);
|
||||
if ((strtolower($fieldName) !== static::$type) && ! in_array(strtolower($fieldName), static::$typeAliases)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Invalid header line for "%s" string',
|
||||
__CLASS__
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
// split value on ","
|
||||
$fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue);
|
||||
$fieldValue = preg_replace('/[^:]+:([^;]*);/', '$1,', $fieldValue);
|
||||
$values = ListParser::parse($fieldValue);
|
||||
$values = ListParser::parse($fieldValue);
|
||||
|
||||
$wasEncoded = false;
|
||||
$addresses = array_map(
|
||||
function ($value) use (&$wasEncoded) {
|
||||
$addresses = array_map(
|
||||
static function ($value) use (&$wasEncoded): ?Address {
|
||||
$decodedValue = HeaderWrap::mimeDecodeValue($value);
|
||||
$wasEncoded = $wasEncoded || ($decodedValue !== $value);
|
||||
|
||||
$value = trim($decodedValue);
|
||||
|
||||
$comments = self::getComments($value);
|
||||
$value = self::stripComments($value);
|
||||
|
||||
$value = preg_replace(
|
||||
$wasEncoded = $wasEncoded || ($decodedValue !== $value);
|
||||
$value = trim($decodedValue);
|
||||
$comments = self::getComments($value);
|
||||
$value = self::stripComments($value);
|
||||
$value = preg_replace(
|
||||
[
|
||||
'#(?<!\\\)"(.*)(?<!\\\)"#', // quoted-text
|
||||
'#(?<!\\\)"(.*)(?<!\\\)"#', // quoted-text
|
||||
'#\\\([\x01-\x09\x0b\x0c\x0e-\x7f])#', // quoted-pair
|
||||
],
|
||||
[
|
||||
@@ -88,12 +118,11 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
],
|
||||
$value
|
||||
);
|
||||
|
||||
return empty($value) ? null : Address::fromString($value, $comments);
|
||||
},
|
||||
$values
|
||||
);
|
||||
$addresses = array_filter($addresses);
|
||||
$addresses = array_filter($addresses);
|
||||
|
||||
$header = new static();
|
||||
if ($wasEncoded) {
|
||||
@@ -109,6 +138,9 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return $this->fieldName;
|
||||
@@ -116,18 +148,21 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
|
||||
/**
|
||||
* Safely convert UTF-8 encoded domain name to ASCII
|
||||
*
|
||||
* @param string $domainName the UTF-8 encoded email
|
||||
* @return string
|
||||
*/
|
||||
protected function idnToAscii($domainName): string
|
||||
{
|
||||
/** @psalm-var string|false $ascii */
|
||||
$ascii = idn_to_ascii($domainName, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $conversionInfo);
|
||||
if (false !== $ascii) {
|
||||
if (is_string($ascii)) {
|
||||
return $ascii;
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
$errors = (int) $conversionInfo['errors'];
|
||||
assert(is_array($conversionInfo));
|
||||
/* @psalm-var array{errors: numeric-string} $conversionInfo */
|
||||
$errors = (int) $conversionInfo['errors'];
|
||||
|
||||
foreach (self::IDNA_ERROR_MAP as $flag => $message) {
|
||||
if (($flag & $errors) === $flag) {
|
||||
@@ -141,6 +176,9 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
$emails = [];
|
||||
@@ -151,12 +189,13 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
$name = $address->getName();
|
||||
|
||||
// quote $name if value requires so
|
||||
if (! empty($name) && (false !== strpos($name, ',') || false !== strpos($name, ';'))) {
|
||||
if (! empty($name) && (str_contains($name, ',') || str_contains($name, ';'))) {
|
||||
// FIXME: what if name contains double quote?
|
||||
$name = sprintf('"%s"', $name);
|
||||
}
|
||||
|
||||
if ($format === HeaderInterface::FORMAT_ENCODED
|
||||
if (
|
||||
$format === HeaderInterface::FORMAT_ENCODED
|
||||
&& 'ASCII' !== $encoding
|
||||
) {
|
||||
if (! empty($name)) {
|
||||
@@ -166,7 +205,7 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
if (preg_match('/^(.+)@([^@]+)$/', $email, $matches)) {
|
||||
$localPart = $matches[1];
|
||||
$hostname = $this->idnToAscii($matches[2]);
|
||||
$email = sprintf('%s@%s', $localPart, $hostname);
|
||||
$email = sprintf('%s@%s', $localPart, $hostname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,12 +226,19 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
return implode(',' . Headers::FOLDING, $emails);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return $this->encoding;
|
||||
@@ -200,8 +246,6 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
|
||||
/**
|
||||
* Set address list for this header
|
||||
*
|
||||
* @param AddressList $addressList
|
||||
*/
|
||||
public function setAddressList(AddressList $addressList)
|
||||
{
|
||||
@@ -221,11 +265,14 @@ abstract class AbstractAddressList implements HeaderInterface
|
||||
return $this->addressList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
$name = $this->getFieldName();
|
||||
$value = $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
return (empty($value)) ? '' : sprintf('%s: %s', $name, $value);
|
||||
return empty($value) ? '' : sprintf('%s: %s', $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,9 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class Bcc extends AbstractAddressList
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldName = 'Bcc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected static $type = 'bcc';
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class Cc extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'Cc';
|
||||
/** @var string */
|
||||
protected static $type = 'cc';
|
||||
}
|
||||
|
||||
@@ -5,6 +5,21 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function count;
|
||||
use function explode;
|
||||
use function gettype;
|
||||
use function in_array;
|
||||
use function is_numeric;
|
||||
use function mb_strlen;
|
||||
use function mb_substr;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
use function var_export;
|
||||
|
||||
class ContentDisposition implements UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
@@ -14,9 +29,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
public const MAX_PARAMETER_LENGTH = 76;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $disposition = 'inline';
|
||||
|
||||
/**
|
||||
@@ -26,9 +39,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
protected $encoding = 'ASCII';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
@@ -36,32 +47,32 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'content-disposition') {
|
||||
if (! in_array(strtolower($name), ['contentdisposition', 'content_disposition', 'content-disposition'])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Content-Disposition string');
|
||||
}
|
||||
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$parts = explode(';', $value, 2);
|
||||
|
||||
$header = new static();
|
||||
$header->setDisposition($parts[0]);
|
||||
|
||||
if (isset($parts[1])) {
|
||||
$values = ListParser::parse(trim($parts[1]), [';', '=']);
|
||||
$length = count($values);
|
||||
$values = ListParser::parse(trim($parts[1]), [';', '=']);
|
||||
$length = count($values);
|
||||
$continuedValues = [];
|
||||
|
||||
for ($i = 0; $i < $length; $i += 2) {
|
||||
$value = $values[$i + 1];
|
||||
$value = trim($value, "'\" \t\n\r\0\x0B");
|
||||
$name = trim($values[$i], "'\" \t\n\r\0\x0B");
|
||||
$name = trim($values[$i], "'\" \t\n\r\0\x0B");
|
||||
|
||||
if (strpos($name, '*')) {
|
||||
list($name, $count) = explode('*', $name);
|
||||
[$name, $count] = explode('*', $name);
|
||||
// allow optional count:
|
||||
// Content-Disposition: attachment; filename*=UTF-8''%64%61%61%6D%69%2D%6D%C3%B5%72%76%2E%6A%70%67
|
||||
if ($count === "") {
|
||||
@@ -69,11 +80,11 @@ class ContentDisposition implements UnstructuredInterface
|
||||
}
|
||||
|
||||
if (! is_numeric($count)) {
|
||||
$type = gettype($count);
|
||||
$value = var_export($count, 1);
|
||||
$type = gettype($count);
|
||||
$value = var_export($count, true);
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
"Invalid header line for Content-Disposition string".
|
||||
" - count expected to be numeric, got %s with value %s",
|
||||
"Invalid header line for Content-Disposition string"
|
||||
. " - count expected to be numeric, got %s with value %s",
|
||||
$type,
|
||||
$value
|
||||
));
|
||||
@@ -92,8 +103,8 @@ class ContentDisposition implements UnstructuredInterface
|
||||
for ($i = 0, $iMax = count($values); $i < $iMax; $i++) {
|
||||
if (! isset($values[$i])) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
'Invalid header line for Content-Disposition string - incomplete continuation'.
|
||||
'; HeaderLine: '.$headerLine
|
||||
'Invalid header line for Content-Disposition string - incomplete continuation'
|
||||
. '; HeaderLine: ' . $headerLine
|
||||
);
|
||||
}
|
||||
$value .= $values[$i];
|
||||
@@ -126,7 +137,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
foreach ($this->parameters as $attribute => $value) {
|
||||
$valueIsEncoded = false;
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) {
|
||||
$value = $this->getEncodedValue($value);
|
||||
$value = $this->getEncodedValue($value);
|
||||
$valueIsEncoded = true;
|
||||
}
|
||||
|
||||
@@ -152,13 +163,13 @@ class ContentDisposition implements UnstructuredInterface
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$i = 0;
|
||||
$fullLength = mb_strlen($value, 'UTF-8');
|
||||
while ($fullLength > 0) {
|
||||
$attributePart = $attribute . '*' . $i++ . '="';
|
||||
$attLen = mb_strlen($attributePart, 'UTF-8');
|
||||
$attLen = mb_strlen($attributePart, 'UTF-8');
|
||||
|
||||
$subPos = 1;
|
||||
$subPos = 1;
|
||||
$valuePart = '';
|
||||
while ($subPos <= $fullLength) {
|
||||
$sub = mb_substr($value, 0, $subPos, 'UTF-8');
|
||||
@@ -173,9 +184,9 @@ class ContentDisposition implements UnstructuredInterface
|
||||
$valuePart = $sub;
|
||||
}
|
||||
|
||||
$value = mb_substr($value, $subPos, null, 'UTF-8');
|
||||
$value = mb_substr($value, $subPos, null, 'UTF-8');
|
||||
$fullLength = mb_strlen($value, 'UTF-8');
|
||||
$result .= ';' . Headers::FOLDING . $attributePart . $valuePart . '"';
|
||||
$result .= ';' . Headers::FOLDING . $attributePart . $valuePart . '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,9 +201,9 @@ class ContentDisposition implements UnstructuredInterface
|
||||
protected function getEncodedValue($value)
|
||||
{
|
||||
$configuredEncoding = $this->encoding;
|
||||
$this->encoding = 'UTF-8';
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$this->encoding = $configuredEncoding;
|
||||
$this->encoding = 'UTF-8';
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$this->encoding = $configuredEncoding;
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -253,7 +264,7 @@ class ContentDisposition implements UnstructuredInterface
|
||||
*/
|
||||
public function setParameter($name, $value)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
$name = strtolower($name);
|
||||
|
||||
if (! HeaderValue::isValid($name)) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
class ContentTransferEncoding implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* Allowed Content-Transfer-Encoding parameters specified by RFC 1521
|
||||
* (reduced set)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $allowedTransferEncodings = [
|
||||
@@ -21,23 +27,28 @@ class ContentTransferEncoding implements HeaderInterface
|
||||
*/
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $transferEncoding;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'content-transfer-encoding') {
|
||||
if (
|
||||
! in_array(
|
||||
strtolower($name),
|
||||
['contenttransferencoding', 'content_transfer_encoding', 'content-transfer-encoding']
|
||||
)
|
||||
) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Content-Transfer-Encoding string');
|
||||
}
|
||||
|
||||
@@ -47,27 +58,43 @@ class ContentTransferEncoding implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Content-Transfer-Encoding';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->transferEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// Header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Content-Transfer-Encoding: ' . $this->getFieldValue();
|
||||
@@ -87,7 +114,7 @@ class ContentTransferEncoding implements HeaderInterface
|
||||
|
||||
if (! in_array($transferEncoding, static::$allowedTransferEncodings)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects one of "'. implode(', ', static::$allowedTransferEncodings) . '"; received "%s"',
|
||||
'%s expects one of "' . implode(', ', static::$allowedTransferEncodings) . '"; received "%s"',
|
||||
__METHOD__,
|
||||
(string) $transferEncoding
|
||||
));
|
||||
|
||||
@@ -5,11 +5,19 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function count;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
class ContentType implements UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
@@ -19,22 +27,24 @@ class ContentType implements UnstructuredInterface
|
||||
*/
|
||||
protected $encoding = 'ASCII';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'content-type') {
|
||||
if (! in_array(strtolower($name), ['contenttype', 'content_type', 'content-type'])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Content-Type string');
|
||||
}
|
||||
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$value = str_replace(Headers::FOLDING, ' ', $value);
|
||||
$parts = explode(';', $value, 2);
|
||||
|
||||
$header = new static();
|
||||
@@ -54,11 +64,17 @@ class ContentType implements UnstructuredInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Content-Type';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
$prepared = $this->type;
|
||||
@@ -70,7 +86,7 @@ class ContentType implements UnstructuredInterface
|
||||
foreach ($this->parameters as $attribute => $value) {
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) {
|
||||
$this->encoding = 'UTF-8';
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$value = HeaderWrap::wrap($value, $this);
|
||||
$this->encoding = 'ASCII';
|
||||
}
|
||||
|
||||
@@ -80,17 +96,27 @@ class ContentType implements UnstructuredInterface
|
||||
return implode(';' . Headers::FOLDING, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Content-Type: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
@@ -132,8 +158,8 @@ class ContentType implements UnstructuredInterface
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @return ContentType
|
||||
* @throws Exception\InvalidArgumentException for parameter names that do not follow RFC 2822
|
||||
* @throws Exception\InvalidArgumentException for parameter values that do not follow RFC 2822
|
||||
* @throws Exception\InvalidArgumentException For parameter names that do not follow RFC 2822.
|
||||
* @throws Exception\InvalidArgumentException For parameter values that do not follow RFC 2822.
|
||||
*/
|
||||
public function addParameter($name, $value)
|
||||
{
|
||||
|
||||
@@ -2,31 +2,36 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* @todo Add accessors for setting date from DateTime, Laminas\Date, or a string
|
||||
*/
|
||||
class Date implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'date') {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Date string');
|
||||
}
|
||||
|
||||
$header = new static($value);
|
||||
|
||||
return $header;
|
||||
return new static($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
if (! HeaderValue::isValid($value)) {
|
||||
@@ -35,27 +40,43 @@ class Date implements HeaderInterface
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Date';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Date: ' . $this->getFieldValue();
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class From extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'From';
|
||||
/** @var string */
|
||||
protected static $type = 'from';
|
||||
}
|
||||
|
||||
@@ -5,16 +5,20 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Header\Exception\InvalidArgumentException;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function count;
|
||||
use function explode;
|
||||
use function is_string;
|
||||
use function ltrim;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use function ucwords;
|
||||
|
||||
class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldValue = '';
|
||||
|
||||
/**
|
||||
@@ -30,11 +34,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = self::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
$header = new static($name, $value);
|
||||
|
||||
return $header;
|
||||
[$name, $value] = self::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
return new static($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,21 +44,21 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
*
|
||||
* @param string $headerLine
|
||||
* @return string[] `name` in the first index and `value` in the second.
|
||||
* @throws Exception\InvalidArgumentException If header does not match with the format ``name:value``
|
||||
* @throws InvalidArgumentException If header does not match with the format ``name:value``.
|
||||
*/
|
||||
public static function splitHeaderLine($headerLine)
|
||||
{
|
||||
$parts = explode(':', $headerLine, 2);
|
||||
if (count($parts) !== 2) {
|
||||
throw new Exception\InvalidArgumentException('Header must match with the format "name:value"');
|
||||
throw new InvalidArgumentException('Header must match with the format "name:value"');
|
||||
}
|
||||
|
||||
if (! HeaderName::isValid($parts[0])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header name detected');
|
||||
throw new InvalidArgumentException('Invalid header name detected');
|
||||
}
|
||||
|
||||
if (! HeaderValue::isValid($parts[1])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header value detected');
|
||||
throw new InvalidArgumentException('Invalid header value detected');
|
||||
}
|
||||
|
||||
$parts[1] = ltrim($parts[1]);
|
||||
@@ -93,14 +95,14 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
public function setFieldName($fieldName)
|
||||
{
|
||||
if (! is_string($fieldName) || empty($fieldName)) {
|
||||
throw new Exception\InvalidArgumentException('Header name must be a string');
|
||||
throw new InvalidArgumentException('Header name must be a string');
|
||||
}
|
||||
|
||||
// Pre-filter to normalize valid characters, change underscore to dash
|
||||
$fieldName = str_replace(' ', '-', ucwords(str_replace(['_', '-'], ' ', $fieldName)));
|
||||
|
||||
if (! HeaderName::isValid($fieldName)) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
throw new InvalidArgumentException(
|
||||
'Header name must be composed of printable US-ASCII characters, except colon.'
|
||||
);
|
||||
}
|
||||
@@ -109,6 +111,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return $this->fieldName;
|
||||
@@ -126,7 +131,7 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
$fieldValue = (string) $fieldValue;
|
||||
|
||||
if (! HeaderWrap::canBeEncoded($fieldValue)) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
throw new InvalidArgumentException(
|
||||
'Header value must be composed of printable US-ASCII characters and valid folding sequences.'
|
||||
);
|
||||
}
|
||||
@@ -137,6 +142,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format) {
|
||||
@@ -146,6 +154,10 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this->fieldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
if ($encoding === $this->encoding) {
|
||||
@@ -173,6 +185,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
if (! $this->encoding) {
|
||||
@@ -182,6 +197,9 @@ class GenericHeader implements HeaderInterface, UnstructuredInterface
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
$name = $this->getFieldName();
|
||||
|
||||
@@ -2,15 +2,23 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function strpos;
|
||||
|
||||
/**
|
||||
* Generic class for Headers with multiple occurs in the same message
|
||||
*/
|
||||
class GenericMultiHeader extends GenericHeader implements MultipleHeadersInterface
|
||||
{
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return array|GenericHeader|GenericMultiHeader|static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$fieldValue = HeaderWrap::mimeDecodeValue($fieldValue);
|
||||
[$fieldName, $fieldValue] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$fieldValue = HeaderWrap::mimeDecodeValue($fieldValue);
|
||||
|
||||
if (strpos($fieldValue, ',')) {
|
||||
$headers = [];
|
||||
|
||||
@@ -16,15 +16,16 @@ interface HeaderInterface
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public const FORMAT_RAW = false;
|
||||
public const FORMAT_RAW = false;
|
||||
|
||||
/**
|
||||
* Factory to generate a header object from a string
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc2822#section-2.2
|
||||
*
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
* @throws Exception\InvalidArgumentException If the header does not match with RFC 2822 definition.
|
||||
* @see http://tools.ietf.org/html/rfc2822#section-2.2
|
||||
*/
|
||||
public static function fromString($headerLine);
|
||||
|
||||
@@ -38,7 +39,7 @@ interface HeaderInterface
|
||||
/**
|
||||
* Retrieve header value
|
||||
*
|
||||
* @param bool $format Return the value in Mime::Encoded or in Raw format
|
||||
* @param HeaderInterface::FORMAT_* $format Return the value in Mime::Encoded or in Raw format
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldValue($format = self::FORMAT_RAW);
|
||||
|
||||
@@ -9,9 +9,7 @@ use Laminas\Loader\PluginClassLoader;
|
||||
*/
|
||||
class HeaderLoader extends PluginClassLoader
|
||||
{
|
||||
/**
|
||||
* @var array Pre-aliased Header plugins
|
||||
*/
|
||||
/** @var array Pre-aliased Header plugins */
|
||||
protected $plugins = [
|
||||
'bcc' => Bcc::class,
|
||||
'cc' => Cc::class,
|
||||
|
||||
@@ -4,15 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* Plugin Class Loader implementation for HTTP headers
|
||||
*/
|
||||
final class HeaderLocator implements HeaderLocatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array Pre-aliased Header plugins
|
||||
*/
|
||||
private $plugins = [
|
||||
/** @var array Pre-aliased Header plugins */
|
||||
private array $plugins = [
|
||||
'bcc' => Bcc::class,
|
||||
'cc' => Cc::class,
|
||||
'contentdisposition' => ContentDisposition::class,
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function ord;
|
||||
use function strlen;
|
||||
|
||||
final class HeaderName
|
||||
{
|
||||
/**
|
||||
@@ -15,6 +18,7 @@ final class HeaderName
|
||||
* Filter the header name according to RFC 2822
|
||||
*
|
||||
* @see http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function in_array;
|
||||
use function ord;
|
||||
use function strlen;
|
||||
|
||||
final class HeaderValue
|
||||
{
|
||||
/**
|
||||
@@ -15,6 +19,7 @@ final class HeaderValue
|
||||
* Filter the header value according to RFC 2822
|
||||
*
|
||||
* @see http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
@@ -44,7 +49,7 @@ final class HeaderValue
|
||||
}
|
||||
|
||||
$result .= "\r\n ";
|
||||
$i += 2;
|
||||
$i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -58,6 +63,7 @@ final class HeaderValue
|
||||
* Determine if the header value contains any invalid characters.
|
||||
*
|
||||
* @see http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
|
||||
*
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -5,17 +5,35 @@ namespace Laminas\Mail\Header;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function array_reduce;
|
||||
use function explode;
|
||||
use function extension_loaded;
|
||||
use function iconv_mime_decode;
|
||||
use function iconv_mime_encode;
|
||||
use function imap_mime_header_decode;
|
||||
use function imap_utf8;
|
||||
use function implode;
|
||||
use function str_contains;
|
||||
use function str_pad;
|
||||
use function str_starts_with;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use function wordwrap;
|
||||
|
||||
use const ICONV_MIME_DECODE_CONTINUE_ON_ERROR;
|
||||
|
||||
/**
|
||||
* Utility class used for creating wrapped or MIME-encoded versions of header
|
||||
* values.
|
||||
*/
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.AbstractClass.Prefix
|
||||
abstract class HeaderWrap
|
||||
{
|
||||
/**
|
||||
* Wrap a long header line
|
||||
*
|
||||
* @param string $value
|
||||
* @param HeaderInterface $header
|
||||
* @return string
|
||||
*/
|
||||
public static function wrap($value, HeaderInterface $header)
|
||||
@@ -34,23 +52,33 @@ abstract class HeaderWrap
|
||||
* Wrap at 78 characters or before, based on whitespace.
|
||||
*
|
||||
* @param string $value
|
||||
* @param HeaderInterface $header
|
||||
* @return string
|
||||
*/
|
||||
protected static function wrapUnstructuredHeader($value, HeaderInterface $header)
|
||||
{
|
||||
$encoding = $header->getEncoding();
|
||||
$headerNameColonSize = strlen($header->getFieldName() . ': ');
|
||||
$encoding = $header->getEncoding();
|
||||
|
||||
if ($encoding == 'ASCII') {
|
||||
return wordwrap($value, 78, Headers::FOLDING);
|
||||
/*
|
||||
* Before folding the header line, it is necessary to calculate the length of the
|
||||
* entire header (including the name and colon). We need to put a stub at the
|
||||
* beginning of the value so that the folding is performed correctly.
|
||||
*/
|
||||
$headerLine = str_pad('0', $headerNameColonSize, '0') . $value;
|
||||
$foldedHeaderLine = wordwrap($headerLine, 78, Headers::FOLDING);
|
||||
|
||||
// Remove the stub and return the header folded value.
|
||||
return substr($foldedHeaderLine, $headerNameColonSize);
|
||||
}
|
||||
return static::mimeEncodeValue($value, $encoding, 78);
|
||||
|
||||
return static::mimeEncodeValue($value, $encoding, 78, $headerNameColonSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a structured header line
|
||||
*
|
||||
* @param string $value
|
||||
* @param StructuredInterface $header
|
||||
* @return string
|
||||
*/
|
||||
protected static function wrapStructuredHeader($value, StructuredInterface $header)
|
||||
@@ -76,14 +104,19 @@ abstract class HeaderWrap
|
||||
* Performs quoted-printable encoding on a value, setting maximum
|
||||
* line-length to 998.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $encoding
|
||||
* @param int $lineLength maximum line-length, by default 998
|
||||
* @param string $value
|
||||
* @param string $encoding
|
||||
* @param int $lineLength Maximum line-length, by default 998
|
||||
* @param positive-int|0 $firstLineGapSize When folding a line, it is necessary to calculate
|
||||
* the length of the entire line (together with the
|
||||
* header name). Therefore, you can specify the header
|
||||
* name and colon length in this argument to fold the
|
||||
* string properly.
|
||||
* @return string Returns the mime encode value without the last line ending
|
||||
*/
|
||||
public static function mimeEncodeValue($value, $encoding, $lineLength = 998)
|
||||
public static function mimeEncodeValue($value, $encoding, $lineLength = 998, $firstLineGapSize = 0)
|
||||
{
|
||||
return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL);
|
||||
return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL, $firstLineGapSize);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,9 +142,7 @@ abstract class HeaderWrap
|
||||
if (self::isNotDecoded($value, $decodedValue) && extension_loaded('imap')) {
|
||||
return array_reduce(
|
||||
imap_mime_header_decode(imap_utf8($value)),
|
||||
function ($accumulator, $headerPart) {
|
||||
return $accumulator . $headerPart->text;
|
||||
},
|
||||
static fn($accumulator, $headerPart) => $accumulator . $headerPart->text,
|
||||
''
|
||||
);
|
||||
}
|
||||
@@ -119,11 +150,11 @@ abstract class HeaderWrap
|
||||
return $decodedValue;
|
||||
}
|
||||
|
||||
private static function isNotDecoded($originalValue, $value)
|
||||
private static function isNotDecoded(string $originalValue, string $value): bool
|
||||
{
|
||||
return 0 === strpos($value, '=?')
|
||||
return str_starts_with($value, '=?')
|
||||
&& strlen($value) - 2 === strpos($value, '?=')
|
||||
&& false !== strpos($originalValue, $value);
|
||||
&& str_contains($originalValue, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,18 +169,18 @@ abstract class HeaderWrap
|
||||
// "test" -> 4
|
||||
// "x-test: =?ISO-8859-1?B?dGVzdA==?=" -> 33
|
||||
// 8 +2 +3 +3 -> 16
|
||||
$charset = 'UTF-8';
|
||||
$charset = 'UTF-8';
|
||||
$lineLength = strlen($value) * 4 + strlen($charset) + 16;
|
||||
|
||||
$preferences = [
|
||||
'scheme' => 'Q',
|
||||
'input-charset' => $charset,
|
||||
'scheme' => 'Q',
|
||||
'input-charset' => $charset,
|
||||
'output-charset' => $charset,
|
||||
'line-length' => $lineLength,
|
||||
'line-length' => $lineLength,
|
||||
];
|
||||
|
||||
$encoded = iconv_mime_encode('x-test', $value, $preferences);
|
||||
|
||||
return (false !== $encoded);
|
||||
return false !== $encoded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,24 +4,27 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mail\Headers;
|
||||
|
||||
use function array_map;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* @see https://tools.ietf.org/html/rfc5322#section-3.6.4
|
||||
*/
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.AbstractClass.Prefix
|
||||
abstract class IdentificationField implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string lower case field name
|
||||
*/
|
||||
/** @var string lower case field name */
|
||||
protected static $type;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
protected $messageIds;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
@@ -30,11 +33,11 @@ abstract class IdentificationField implements HeaderInterface
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
if (strtolower($name) !== static::$type) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Invalid header line for "%s" string',
|
||||
__CLASS__
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
@@ -69,14 +72,11 @@ abstract class IdentificationField implements HeaderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $format
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return implode(Headers::FOLDING, array_map(function ($id) {
|
||||
return sprintf('<%s>', $id);
|
||||
}, $this->messageIds));
|
||||
return implode(Headers::FOLDING, array_map(static fn($id) => sprintf('<%s>', $id), $this->messageIds));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +114,8 @@ abstract class IdentificationField implements HeaderInterface
|
||||
public function setIds($ids)
|
||||
{
|
||||
foreach ($ids as $id) {
|
||||
if (! HeaderValue::isValid($id)
|
||||
if (
|
||||
! HeaderValue::isValid($id)
|
||||
|| preg_match("/[\r\n]/", $id)
|
||||
) {
|
||||
throw new Exception\InvalidArgumentException('Invalid ID detected');
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class InReplyTo extends IdentificationField
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'In-Reply-To';
|
||||
/** @var string */
|
||||
protected static $type = 'in-reply-to';
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function in_array;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -35,14 +36,14 @@ class ListParser
|
||||
// If we are in an escape sequence, append the character and continue.
|
||||
if ($inEscape) {
|
||||
$currentValue .= $char;
|
||||
$inEscape = false;
|
||||
$inEscape = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we are not in a quoted string, and have a delimiter, append
|
||||
// the current value to the list, and reset the current value.
|
||||
if (in_array($char, $delims, true) && ! $inQuote) {
|
||||
$values [] = $currentValue;
|
||||
$values [] = $currentValue;
|
||||
$currentValue = '';
|
||||
continue;
|
||||
}
|
||||
@@ -66,7 +67,7 @@ class ListParser
|
||||
// we reset our quote status and the currently opened quote
|
||||
// delimiter.
|
||||
if ($char === $currentQuoteDelim) {
|
||||
$inQuote = false;
|
||||
$inQuote = false;
|
||||
$currentQuoteDelim = null;
|
||||
continue;
|
||||
}
|
||||
@@ -78,7 +79,7 @@ class ListParser
|
||||
}
|
||||
|
||||
// Otherwise, we're starting a quoted string.
|
||||
$inQuote = true;
|
||||
$inQuote = true;
|
||||
$currentQuoteDelim = $char;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,29 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function getmypid;
|
||||
use function mt_rand;
|
||||
use function php_uname;
|
||||
use function preg_match;
|
||||
use function sha1;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function time;
|
||||
use function trim;
|
||||
|
||||
class MessageId implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $messageId;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'message-id') {
|
||||
@@ -25,27 +37,43 @@ class MessageId implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Message-ID';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->messageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Message-ID: ' . $this->getFieldValue();
|
||||
@@ -65,7 +93,8 @@ class MessageId implements HeaderInterface
|
||||
$id = trim($id, '<>');
|
||||
}
|
||||
|
||||
if (! HeaderValue::isValid($id)
|
||||
if (
|
||||
! HeaderValue::isValid($id)
|
||||
|| preg_match("/[\r\n]/", $id)
|
||||
) {
|
||||
throw new Exception\InvalidArgumentException('Invalid ID detected');
|
||||
|
||||
@@ -2,20 +2,26 @@
|
||||
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function strtolower;
|
||||
|
||||
class MimeVersion implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var string Version string
|
||||
*/
|
||||
/** @var string Version string */
|
||||
protected $version = '1.0';
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'mime-version') {
|
||||
if (! in_array(strtolower($name), ['mimeversion', 'mime_version', 'mime-version'])) {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for MIME-Version string');
|
||||
}
|
||||
|
||||
@@ -28,27 +34,43 @@ class MimeVersion implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'MIME-Version';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'MIME-Version: ' . $this->getFieldValue();
|
||||
|
||||
@@ -4,31 +4,37 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mail\Headers;
|
||||
|
||||
use function implode;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* @todo Allow setting date from DateTime, Laminas\Date, or string
|
||||
*/
|
||||
class Received implements HeaderInterface, MultipleHeadersInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'received') {
|
||||
throw new Exception\InvalidArgumentException('Invalid header line for Received string');
|
||||
}
|
||||
|
||||
$header = new static($value);
|
||||
|
||||
return $header;
|
||||
return new static($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct($value = '')
|
||||
{
|
||||
if (! HeaderValue::isValid($value)) {
|
||||
@@ -37,27 +43,43 @@ class Received implements HeaderInterface, MultipleHeadersInterface
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Received';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
// This header must be always in US-ASCII
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
return 'ASCII';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Received: ' . $this->getFieldValue();
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class References extends IdentificationField
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'References';
|
||||
/** @var string */
|
||||
protected static $type = 'references';
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class ReplyTo extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'Reply-To';
|
||||
/** @var string */
|
||||
protected static $type = 'reply-to';
|
||||
/** @var string[] */
|
||||
protected static $typeAliases = ['replyto', 'reply_to'];
|
||||
}
|
||||
|
||||
@@ -3,8 +3,17 @@
|
||||
namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Address\AddressInterface;
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Sender header class methods.
|
||||
*
|
||||
@@ -13,9 +22,7 @@ use Laminas\Mime\Mime;
|
||||
*/
|
||||
class Sender implements HeaderInterface
|
||||
{
|
||||
/**
|
||||
* @var \Laminas\Mail\Address\AddressInterface
|
||||
*/
|
||||
/** @var AddressInterface */
|
||||
protected $address;
|
||||
|
||||
/**
|
||||
@@ -25,21 +32,26 @@ class Sender implements HeaderInterface
|
||||
*/
|
||||
protected $encoding;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'sender') {
|
||||
throw new Exception\InvalidArgumentException('Invalid header name for Sender string');
|
||||
}
|
||||
|
||||
$header = new static();
|
||||
$header = new static();
|
||||
|
||||
/**
|
||||
* matches the header value so that the email must be enclosed by < > when a name is present
|
||||
* 'name' and 'email' capture groups correspond respectively to 'display-name' and 'addr-spec' in the ABNF
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc5322#section-3.4
|
||||
*/
|
||||
$hasMatches = preg_match(
|
||||
@@ -63,11 +75,17 @@ class Sender implements HeaderInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Sender';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
if (! $this->address instanceof Mail\Address\AddressInterface) {
|
||||
@@ -81,7 +99,7 @@ class Sender implements HeaderInterface
|
||||
if ($format == HeaderInterface::FORMAT_ENCODED) {
|
||||
$encoding = $this->getEncoding();
|
||||
if ('ASCII' !== $encoding) {
|
||||
$name = HeaderWrap::mimeEncodeValue($name, $encoding);
|
||||
$name = HeaderWrap::mimeEncodeValue($name, $encoding);
|
||||
}
|
||||
}
|
||||
$email = sprintf('%s %s', $name, $email);
|
||||
@@ -90,12 +108,19 @@ class Sender implements HeaderInterface
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
if (! $this->encoding) {
|
||||
@@ -107,6 +132,9 @@ class Sender implements HeaderInterface
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Sender: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
@@ -115,7 +143,7 @@ class Sender implements HeaderInterface
|
||||
/**
|
||||
* Set the address used in this header
|
||||
*
|
||||
* @param string|\Laminas\Mail\Address\AddressInterface $emailOrAddress
|
||||
* @param string|AddressInterface $emailOrAddress
|
||||
* @param null|string $name
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return Sender
|
||||
@@ -128,7 +156,7 @@ class Sender implements HeaderInterface
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects a string or AddressInterface object; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
|
||||
is_object($emailOrAddress) ? $emailOrAddress::class : gettype($emailOrAddress)
|
||||
));
|
||||
}
|
||||
$this->address = $emailOrAddress;
|
||||
@@ -138,7 +166,7 @@ class Sender implements HeaderInterface
|
||||
/**
|
||||
* Retrieve the internal address from this header
|
||||
*
|
||||
* @return \Laminas\Mail\Address\AddressInterface|null
|
||||
* @return AddressInterface|null
|
||||
*/
|
||||
public function getAddress()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
use Laminas\Mime\Mime;
|
||||
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
|
||||
/**
|
||||
* Subject header class methods.
|
||||
*
|
||||
@@ -12,9 +15,7 @@ use Laminas\Mime\Mime;
|
||||
*/
|
||||
class Subject implements UnstructuredInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $subject = '';
|
||||
|
||||
/**
|
||||
@@ -24,10 +25,14 @@ class Subject implements UnstructuredInterface
|
||||
*/
|
||||
protected $encoding;
|
||||
|
||||
/**
|
||||
* @param string $headerLine
|
||||
* @return static
|
||||
*/
|
||||
public static function fromString($headerLine)
|
||||
{
|
||||
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
[$name, $value] = GenericHeader::splitHeaderLine($headerLine);
|
||||
$value = HeaderWrap::mimeDecodeValue($value);
|
||||
|
||||
// check to ensure proper header type for this factory
|
||||
if (strtolower($name) !== 'subject') {
|
||||
@@ -40,11 +45,17 @@ class Subject implements UnstructuredInterface
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName()
|
||||
{
|
||||
return 'Subject';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
if (HeaderInterface::FORMAT_ENCODED === $format) {
|
||||
@@ -54,6 +65,10 @@ class Subject implements UnstructuredInterface
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
* @return self
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
if ($encoding === $this->encoding) {
|
||||
@@ -81,6 +96,9 @@ class Subject implements UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncoding()
|
||||
{
|
||||
if (! $this->encoding) {
|
||||
@@ -90,6 +108,10 @@ class Subject implements UnstructuredInterface
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $subject
|
||||
* @return self
|
||||
*/
|
||||
public function setSubject($subject)
|
||||
{
|
||||
$subject = (string) $subject;
|
||||
@@ -106,6 +128,9 @@ class Subject implements UnstructuredInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return 'Subject: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Laminas\Mail\Header;
|
||||
|
||||
class To extends AbstractAddressList
|
||||
{
|
||||
/** @var string */
|
||||
protected $fieldName = 'To';
|
||||
/** @var string */
|
||||
protected static $type = 'to';
|
||||
}
|
||||
|
||||
@@ -10,13 +10,40 @@ use Iterator;
|
||||
use Laminas\Loader\PluginClassLocator;
|
||||
use Laminas\Mail\Header\GenericHeader;
|
||||
use Laminas\Mail\Header\HeaderInterface;
|
||||
use Laminas\Mail\Header\HeaderLocatorInterface;
|
||||
use ReturnTypeWillChange;
|
||||
use Traversable;
|
||||
|
||||
use function array_keys;
|
||||
use function array_shift;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function current;
|
||||
use function explode;
|
||||
use function gettype;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function key;
|
||||
use function next;
|
||||
use function preg_match;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function trigger_error;
|
||||
use function trim;
|
||||
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Basic mail headers collection functionality
|
||||
*
|
||||
* Handles aggregation of headers
|
||||
*
|
||||
* @implements Iterator<int, HeaderInterface>
|
||||
*/
|
||||
class Headers implements Countable, Iterator
|
||||
{
|
||||
@@ -26,10 +53,7 @@ class Headers implements Countable, Iterator
|
||||
/** @var string Start of Line when folding */
|
||||
public const FOLDING = "\r\n ";
|
||||
|
||||
/**
|
||||
* @var null|Header\HeaderLocatorInterface
|
||||
*/
|
||||
private $headerLocator;
|
||||
private ?HeaderLocatorInterface $headerLocator = null;
|
||||
|
||||
/**
|
||||
* @todo Remove for 3.0.0.
|
||||
@@ -37,14 +61,10 @@ class Headers implements Countable, Iterator
|
||||
*/
|
||||
protected $pluginClassLoader;
|
||||
|
||||
/**
|
||||
* @var array key names for $headers array
|
||||
*/
|
||||
/** @var list<string> key names for $headers array */
|
||||
protected $headersKeys = [];
|
||||
|
||||
/**
|
||||
* @var Header\HeaderInterface[] instances
|
||||
*/
|
||||
/** @var list<HeaderInterface> instances */
|
||||
protected $headers = [];
|
||||
|
||||
/**
|
||||
@@ -62,18 +82,18 @@ class Headers implements Countable, Iterator
|
||||
* will be lazy loaded)
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $EOL EOL string; defaults to {@link EOL}
|
||||
* @throws Exception\RuntimeException
|
||||
* @param string $eol EOL string; defaults to {@link EOL}
|
||||
* @return Headers
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public static function fromString($string, $EOL = self::EOL)
|
||||
public static function fromString($string, $eol = self::EOL)
|
||||
{
|
||||
$headers = new static();
|
||||
$currentLine = '';
|
||||
$emptyLine = 0;
|
||||
|
||||
// iterate the header lines, some might be continuations
|
||||
$lines = explode($EOL, $string);
|
||||
$lines = explode($eol, $string);
|
||||
$total = count($lines);
|
||||
for ($i = 0; $i < $total; $i += 1) {
|
||||
$line = $lines[$i];
|
||||
@@ -128,6 +148,7 @@ class Headers implements Countable, Iterator
|
||||
* Set an alternate PluginClassLocator implementation for loading header classes.
|
||||
*
|
||||
* @deprecated since 2.12.0
|
||||
*
|
||||
* @todo Remove for version 3.0.0
|
||||
* @return $this
|
||||
*/
|
||||
@@ -137,7 +158,7 @@ class Headers implements Countable, Iterator
|
||||
@trigger_error(sprintf(
|
||||
'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::setHeaderLocator() instead',
|
||||
__METHOD__,
|
||||
__CLASS__
|
||||
self::class
|
||||
), E_USER_DEPRECATED);
|
||||
|
||||
$this->pluginClassLoader = $pluginClassLoader;
|
||||
@@ -150,6 +171,7 @@ class Headers implements Countable, Iterator
|
||||
* Lazyloads a Header\HeaderLoader if necessary.
|
||||
*
|
||||
* @deprecated since 2.12.0
|
||||
*
|
||||
* @todo Remove for version 3.0.0
|
||||
* @return PluginClassLocator
|
||||
*/
|
||||
@@ -159,7 +181,7 @@ class Headers implements Countable, Iterator
|
||||
@trigger_error(sprintf(
|
||||
'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::getHeaderLocator() instead',
|
||||
__METHOD__,
|
||||
__CLASS__
|
||||
self::class
|
||||
), E_USER_DEPRECATED);
|
||||
|
||||
if (! $this->pluginClassLoader) {
|
||||
@@ -174,11 +196,14 @@ class Headers implements Countable, Iterator
|
||||
*
|
||||
* Lazyloads a Header\HeaderLocator instance if necessary.
|
||||
*/
|
||||
public function getHeaderLocator(): Header\HeaderLocatorInterface
|
||||
public function getHeaderLocator(): HeaderLocatorInterface
|
||||
{
|
||||
if (! $this->headerLocator) {
|
||||
$this->setHeaderLocator(new Header\HeaderLocator());
|
||||
}
|
||||
|
||||
assert($this->headerLocator instanceof HeaderLocatorInterface);
|
||||
|
||||
return $this->headerLocator;
|
||||
}
|
||||
|
||||
@@ -186,7 +211,7 @@ class Headers implements Countable, Iterator
|
||||
* @todo Return self when we update to 7.4 or later as minimum PHP version.
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeaderLocator(Header\HeaderLocatorInterface $headerLocator)
|
||||
public function setHeaderLocator(HeaderLocatorInterface $headerLocator)
|
||||
{
|
||||
$this->headerLocator = $headerLocator;
|
||||
return $this;
|
||||
@@ -231,7 +256,7 @@ class Headers implements Countable, Iterator
|
||||
if (! is_array($headers) && ! $headers instanceof Traversable) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Expected array or Traversable; received "%s"',
|
||||
(is_object($headers) ? get_class($headers) : gettype($headers))
|
||||
is_object($headers) ? $headers::class : gettype($headers)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -271,9 +296,9 @@ class Headers implements Countable, Iterator
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects its first argument to be a string; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($headerFieldNameOrLine)
|
||||
? get_class($headerFieldNameOrLine)
|
||||
: gettype($headerFieldNameOrLine))
|
||||
is_object($headerFieldNameOrLine)
|
||||
? $headerFieldNameOrLine::class
|
||||
: gettype($headerFieldNameOrLine)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -288,7 +313,7 @@ class Headers implements Countable, Iterator
|
||||
$this->addHeader(Header\GenericMultiHeader::fromString($headerFieldNameOrLine . ':' . $i));
|
||||
}
|
||||
} else {
|
||||
$this->addHeader(Header\GenericHeader::fromString($headerFieldNameOrLine . ':' . $fieldValue));
|
||||
$this->addHeader(GenericHeader::fromString($headerFieldNameOrLine . ':' . $fieldValue));
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -297,14 +322,13 @@ class Headers implements Countable, Iterator
|
||||
/**
|
||||
* Add a Header\Interface to this container, for raw values see {@link addHeaderLine()} and {@link addHeaders()}
|
||||
*
|
||||
* @param Header\HeaderInterface $header
|
||||
* @return Headers
|
||||
*/
|
||||
public function addHeader(Header\HeaderInterface $header)
|
||||
public function addHeader(HeaderInterface $header)
|
||||
{
|
||||
$key = $this->normalizeFieldName($header->getFieldName());
|
||||
$key = $this->normalizeFieldName($header->getFieldName());
|
||||
$this->headersKeys[] = $key;
|
||||
$this->headers[] = $header;
|
||||
$this->headers[] = $header;
|
||||
if ($this->getEncoding() !== 'ASCII') {
|
||||
$header->setEncoding($this->getEncoding());
|
||||
}
|
||||
@@ -314,7 +338,7 @@ class Headers implements Countable, Iterator
|
||||
/**
|
||||
* Remove a Header from the container
|
||||
*
|
||||
* @param string|Header\HeaderInterface field name or specific header instance to remove
|
||||
* @param string|HeaderInterface $instanceOrFieldName field name or specific header instance to remove
|
||||
* @return bool
|
||||
*/
|
||||
public function removeHeader($instanceOrFieldName)
|
||||
@@ -323,8 +347,8 @@ class Headers implements Countable, Iterator
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s requires a string or %s instance; received %s',
|
||||
__METHOD__,
|
||||
Header\HeaderInterface::class,
|
||||
is_object($instanceOrFieldName) ? get_class($instanceOrFieldName) : gettype($instanceOrFieldName)
|
||||
HeaderInterface::class,
|
||||
is_object($instanceOrFieldName) ? $instanceOrFieldName::class : gettype($instanceOrFieldName)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -333,7 +357,7 @@ class Headers implements Countable, Iterator
|
||||
}
|
||||
|
||||
if (is_string($instanceOrFieldName)) {
|
||||
$key = $this->normalizeFieldName($instanceOrFieldName);
|
||||
$key = $this->normalizeFieldName($instanceOrFieldName);
|
||||
$indexes = array_keys($this->headersKeys, $key, true);
|
||||
}
|
||||
|
||||
@@ -365,13 +389,13 @@ class Headers implements Countable, Iterator
|
||||
* Get all headers of a certain name/type
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool|ArrayIterator|Header\HeaderInterface Returns false if there is no headers with $name in this
|
||||
* @return false|ArrayIterator|HeaderInterface Returns false if there is no headers with $name in this
|
||||
* contain, an ArrayIterator if the header is a MultipleHeadersInterface instance and finally returns
|
||||
* HeaderInterface for the rest of cases.
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$key = $this->normalizeFieldName($name);
|
||||
$key = $this->normalizeFieldName($name);
|
||||
$results = [];
|
||||
|
||||
foreach (array_keys($this->headersKeys, $key, true) as $index) {
|
||||
@@ -409,7 +433,6 @@ class Headers implements Countable, Iterator
|
||||
|
||||
/**
|
||||
* Advance the pointer for this object as an iterator
|
||||
*
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
@@ -436,12 +459,11 @@ class Headers implements Countable, Iterator
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
{
|
||||
return (current($this->headers) !== false);
|
||||
return current($this->headers) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the internal pointer for this object as an iterator
|
||||
*
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
@@ -452,7 +474,7 @@ class Headers implements Countable, Iterator
|
||||
/**
|
||||
* Return the current value for this iterator, lazy loading it if need be
|
||||
*
|
||||
* @return Header\HeaderInterface
|
||||
* @return HeaderInterface
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -500,13 +522,12 @@ class Headers implements Countable, Iterator
|
||||
* Return the headers container as an array
|
||||
*
|
||||
* @param bool $format Return the values in Mime::Encoded or in Raw format
|
||||
* @return array
|
||||
* @return array<string, list<string>|string>
|
||||
* @todo determine how to produce single line headers, if they are supported
|
||||
*/
|
||||
public function toArray($format = Header\HeaderInterface::FORMAT_RAW)
|
||||
public function toArray($format = HeaderInterface::FORMAT_RAW)
|
||||
{
|
||||
$headers = [];
|
||||
/* @var $header Header\HeaderInterface */
|
||||
foreach ($this->headers as $header) {
|
||||
if ($header instanceof Header\MultipleHeadersInterface) {
|
||||
$name = $header->getFieldName();
|
||||
@@ -528,6 +549,7 @@ class Headers implements Countable, Iterator
|
||||
*/
|
||||
public function forceLoading()
|
||||
{
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedForeach
|
||||
foreach ($this as $item) {
|
||||
// $item should now be loaded
|
||||
}
|
||||
@@ -538,11 +560,11 @@ class Headers implements Countable, Iterator
|
||||
* Create Header object from header line
|
||||
*
|
||||
* @param string $headerLine
|
||||
* @return Header\HeaderInterface|Header\HeaderInterface[]
|
||||
* @return HeaderInterface|HeaderInterface[]
|
||||
*/
|
||||
public function loadHeader($headerLine)
|
||||
{
|
||||
list($name) = Header\GenericHeader::splitHeaderLine($headerLine);
|
||||
[$name] = GenericHeader::splitHeaderLine($headerLine);
|
||||
|
||||
/** @var HeaderInterface $class */
|
||||
$class = $this->resolveHeaderClass($name);
|
||||
@@ -550,14 +572,14 @@ class Headers implements Countable, Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @param array-key $index
|
||||
* @return mixed
|
||||
*/
|
||||
protected function lazyLoadHeader($index)
|
||||
{
|
||||
$current = $this->headers[$index];
|
||||
|
||||
$key = $this->headersKeys[$index];
|
||||
$key = $this->headersKeys[$index];
|
||||
|
||||
/** @var GenericHeader $class */
|
||||
$class = $this->resolveHeaderClass($key);
|
||||
@@ -595,13 +617,13 @@ class Headers implements Countable, Iterator
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @return null|string
|
||||
*/
|
||||
private function resolveHeaderClass($key)
|
||||
{
|
||||
if ($this->pluginClassLoader) {
|
||||
return $this->pluginClassLoader->load($key) ?: Header\GenericHeader::class;
|
||||
return $this->pluginClassLoader->load($key) ?: GenericHeader::class;
|
||||
}
|
||||
return $this->getHeaderLocator()->get($key, Header\GenericHeader::class);
|
||||
return $this->getHeaderLocator()->get($key, GenericHeader::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Laminas\Mail;
|
||||
|
||||
use ArrayIterator;
|
||||
use Laminas\Mail\Header\Bcc;
|
||||
use Laminas\Mail\Header\Cc;
|
||||
use Laminas\Mail\Header\ContentType;
|
||||
@@ -13,6 +14,16 @@ use Laminas\Mail\Header\To;
|
||||
use Laminas\Mime;
|
||||
use Traversable;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function date;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
class Message
|
||||
{
|
||||
/**
|
||||
@@ -22,9 +33,7 @@ class Message
|
||||
*/
|
||||
protected $body;
|
||||
|
||||
/**
|
||||
* @var Headers
|
||||
*/
|
||||
/** @var Headers */
|
||||
protected $headers;
|
||||
|
||||
/**
|
||||
@@ -78,7 +87,6 @@ class Message
|
||||
/**
|
||||
* Compose headers
|
||||
*
|
||||
* @param Headers $headers
|
||||
* @return Message
|
||||
*/
|
||||
public function setHeaders(Headers $headers)
|
||||
@@ -297,11 +305,9 @@ class Message
|
||||
/**
|
||||
* setSender
|
||||
*
|
||||
* @param mixed $emailOrAddress
|
||||
* @param mixed $name
|
||||
* @return Message
|
||||
*/
|
||||
public function setSender($emailOrAddress, $name = null)
|
||||
public function setSender(mixed $emailOrAddress, mixed $name = null)
|
||||
{
|
||||
/** @var Sender $header */
|
||||
$header = $this->getHeaderByName('sender', Sender::class);
|
||||
@@ -385,7 +391,7 @@ class Message
|
||||
. ' object of type "%s" received',
|
||||
__METHOD__,
|
||||
Mime\Message::class,
|
||||
get_class($body)
|
||||
$body::class
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -402,7 +408,7 @@ class Message
|
||||
|
||||
// Multipart content headers
|
||||
if ($this->body->isMultiPart()) {
|
||||
$mime = $this->body->getMime();
|
||||
$mime = $this->body->getMime();
|
||||
|
||||
/** @var ContentType $header */
|
||||
$header = $this->getHeaderByName('content-type', ContentType::class);
|
||||
@@ -451,7 +457,7 @@ class Message
|
||||
*
|
||||
* @param string $headerName
|
||||
* @param string $headerClass
|
||||
* @return Header\HeaderInterface|\ArrayIterator header instance or collection of headers
|
||||
* @return Header\HeaderInterface|ArrayIterator header instance or collection of headers
|
||||
*/
|
||||
protected function getHeaderByName($headerName, $headerClass)
|
||||
{
|
||||
@@ -492,7 +498,7 @@ class Message
|
||||
if (! $header instanceof Header\AbstractAddressList) {
|
||||
throw new Exception\DomainException(sprintf(
|
||||
'Cannot grab address list from header of type "%s"; not an AbstractAddressList implementation',
|
||||
get_class($header)
|
||||
$header::class
|
||||
));
|
||||
}
|
||||
return $header->getAddressList();
|
||||
@@ -503,7 +509,6 @@ class Message
|
||||
*
|
||||
* Proxied to this from addFrom, addTo, addCc, addBcc, and addReplyTo.
|
||||
*
|
||||
* @param AddressList $addressList
|
||||
* @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
|
||||
* @param null|string $name
|
||||
* @param string $callingMethod
|
||||
@@ -526,7 +531,7 @@ class Message
|
||||
'%s expects a string, AddressInterface, array, AddressList, or Traversable as its first argument;'
|
||||
. ' received "%s"',
|
||||
$callingMethod,
|
||||
(is_object($emailOrAddressOrList) ? get_class($emailOrAddressOrList) : gettype($emailOrAddressOrList))
|
||||
is_object($emailOrAddressOrList) ? $emailOrAddressOrList::class : gettype($emailOrAddressOrList)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -566,9 +571,9 @@ class Message
|
||||
$headers = null;
|
||||
$content = null;
|
||||
Mime\Decode::splitMessage($rawMessage, $headers, $content, Headers::EOL);
|
||||
if ($headers->has('mime-version')) {
|
||||
// if ($headers->has('mime-version')) {
|
||||
// todo - restore body to mime\message
|
||||
}
|
||||
// }
|
||||
$message->setHeaders($headers);
|
||||
$message->setBody($content);
|
||||
return $message;
|
||||
|
||||
@@ -4,6 +4,15 @@ namespace Laminas\Mail;
|
||||
|
||||
use Traversable;
|
||||
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strtr;
|
||||
use function ucwords;
|
||||
|
||||
class MessageFactory
|
||||
{
|
||||
/**
|
||||
@@ -16,7 +25,7 @@ class MessageFactory
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'"%s" expects an array or Traversable; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($options) ? get_class($options) : gettype($options))
|
||||
is_object($options) ? $options::class : gettype($options)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Validator;
|
||||
use Laminas\Validator\ValidatorChain;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_resource;
|
||||
use function preg_split;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
use function sprintf;
|
||||
use function str_starts_with;
|
||||
use function stream_get_meta_data;
|
||||
use function stream_set_timeout;
|
||||
use function stream_socket_client;
|
||||
|
||||
use const E_WARNING;
|
||||
use const PREG_SPLIT_DELIM_CAPTURE;
|
||||
|
||||
/**
|
||||
* Provides low-level methods for concrete adapters to communicate with a
|
||||
@@ -24,60 +46,57 @@ abstract class AbstractProtocol
|
||||
|
||||
/**
|
||||
* Maximum of the transaction log
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maximumLog = 64;
|
||||
|
||||
/**
|
||||
* Hostname or IP address of remote server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $host;
|
||||
|
||||
/**
|
||||
* Port number of connection
|
||||
* @var int
|
||||
*/
|
||||
protected $port;
|
||||
|
||||
/**
|
||||
* Instance of Laminas\Validator\ValidatorChain to check hostnames
|
||||
* @var \Laminas\Validator\ValidatorChain
|
||||
*
|
||||
* @var ValidatorChain
|
||||
*/
|
||||
protected $validHost;
|
||||
|
||||
/**
|
||||
* Socket connection resource
|
||||
*
|
||||
* @var null|resource
|
||||
*/
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* Last request sent to server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Array of server responses to last request
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Log of mail requests and server responses for a session
|
||||
* @var array
|
||||
*/
|
||||
private $log = [];
|
||||
private array $log = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
|
||||
* @param int $port OPTIONAL Port number (default: null)
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function __construct($host = '127.0.0.1', $port = null)
|
||||
public function __construct($host = '127.0.0.1', protected $port = null)
|
||||
{
|
||||
$this->validHost = new Validator\ValidatorChain();
|
||||
$this->validHost->attach(new Validator\Hostname(Validator\Hostname::ALLOW_ALL));
|
||||
@@ -87,12 +106,10 @@ abstract class AbstractProtocol
|
||||
}
|
||||
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class destructor to cleanup open resources
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
@@ -159,7 +176,6 @@ abstract class AbstractProtocol
|
||||
|
||||
/**
|
||||
* Reset the transaction log
|
||||
*
|
||||
*/
|
||||
public function resetLog()
|
||||
{
|
||||
@@ -187,6 +203,7 @@ abstract class AbstractProtocol
|
||||
* An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
|
||||
*
|
||||
* @deprecated Since 1.12.0. Implementations should use the ProtocolTrait::setupSocket() method instead.
|
||||
*
|
||||
* @todo Remove for 3.0.0.
|
||||
* @param string $remote Remote
|
||||
* @throws Exception\RuntimeException
|
||||
@@ -200,7 +217,7 @@ abstract class AbstractProtocol
|
||||
|
||||
// open connection
|
||||
set_error_handler(
|
||||
function ($error, $message = '') {
|
||||
static function ($error, $message = '') {
|
||||
throw new Exception\RuntimeException(sprintf('Could not open socket: %s', $message), $error);
|
||||
},
|
||||
E_WARNING
|
||||
@@ -224,7 +241,6 @@ abstract class AbstractProtocol
|
||||
|
||||
/**
|
||||
* Disconnect from remote host and free resource
|
||||
*
|
||||
*/
|
||||
// @codingStandardsIgnoreLine PSR2.Methods.MethodDeclaration.Underscore
|
||||
protected function _disconnect()
|
||||
@@ -316,15 +332,15 @@ abstract class AbstractProtocol
|
||||
protected function _expect($code, $timeout = null)
|
||||
{
|
||||
$this->response = [];
|
||||
$errMsg = '';
|
||||
$errMsg = '';
|
||||
|
||||
if (! is_array($code)) {
|
||||
$code = [$code];
|
||||
}
|
||||
|
||||
do {
|
||||
$this->response[] = $result = $this->_receive($timeout);
|
||||
list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$this->response[] = $result = $this->_receive($timeout);
|
||||
[$cmd, $more, $msg] = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
if ($errMsg !== '') {
|
||||
$errMsg .= ' ' . $msg;
|
||||
@@ -333,7 +349,7 @@ abstract class AbstractProtocol
|
||||
}
|
||||
|
||||
// The '-' message prefix indicates an information string instead of a response string.
|
||||
} while (strpos($more, '-') === 0);
|
||||
} while (str_starts_with($more, '-'));
|
||||
|
||||
if ($errMsg !== '') {
|
||||
throw new Exception\RuntimeException($errMsg);
|
||||
|
||||
@@ -2,6 +2,40 @@
|
||||
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Mail\Protocol\Exception\ExceptionInterface;
|
||||
|
||||
use function array_merge;
|
||||
use function array_pop;
|
||||
use function array_push;
|
||||
use function array_search;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function current;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function func_get_args;
|
||||
use function func_num_args;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
use function key;
|
||||
use function next;
|
||||
use function preg_match;
|
||||
use function rtrim;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function str_starts_with;
|
||||
use function stream_socket_enable_crypto;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
use const INF;
|
||||
|
||||
class Imap
|
||||
{
|
||||
use ProtocolTrait;
|
||||
@@ -11,13 +45,12 @@ class Imap
|
||||
*/
|
||||
public const TIMEOUT_CONNECTION = 30;
|
||||
|
||||
/**
|
||||
* @var null|resource
|
||||
*/
|
||||
/** @var null|resource */
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* counter for request tag
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $tagCount = 0;
|
||||
@@ -29,7 +62,7 @@ class Imap
|
||||
* @param int|null $port port of IMAP server, null for default (143 or 993 for ssl)
|
||||
* @param string|bool $ssl use ssl? 'SSL', 'TLS' or false
|
||||
* @param bool $novalidatecert set to true to skip SSL certificate validation
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function __construct($host = '', $port = null, $ssl = false, $novalidatecert = false)
|
||||
{
|
||||
@@ -60,7 +93,7 @@ class Imap
|
||||
public function connect($host, $port = null, $ssl = false)
|
||||
{
|
||||
$transport = 'tcp';
|
||||
$isTls = false;
|
||||
$isTls = false;
|
||||
|
||||
if ($ssl) {
|
||||
$ssl = strtolower($ssl);
|
||||
@@ -123,7 +156,7 @@ class Imap
|
||||
protected function assumedNextLine($start)
|
||||
{
|
||||
$line = $this->nextLine();
|
||||
return strpos($line, $start) === 0;
|
||||
return str_starts_with($line, $start);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +170,7 @@ class Imap
|
||||
$line = $this->nextLine();
|
||||
|
||||
// separate tag from line
|
||||
list($tag, $line) = explode(' ', $line, 2);
|
||||
[$tag, $line] = explode(' ', $line, 2);
|
||||
|
||||
return $line;
|
||||
}
|
||||
@@ -151,7 +184,7 @@ class Imap
|
||||
protected function decodeLine($line)
|
||||
{
|
||||
$tokens = [];
|
||||
$stack = [];
|
||||
$stack = [];
|
||||
|
||||
/*
|
||||
We start to decode the response here. The understood tokens are:
|
||||
@@ -177,18 +210,18 @@ class Imap
|
||||
while ($token[0] == '(') {
|
||||
array_push($stack, $tokens);
|
||||
$tokens = [];
|
||||
$token = substr($token, 1);
|
||||
$token = substr($token, 1);
|
||||
}
|
||||
if ($token[0] == '"') {
|
||||
if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
|
||||
$tokens[] = $matches[1];
|
||||
$line = substr($line, strlen($matches[0]));
|
||||
$line = substr($line, strlen($matches[0]));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($token[0] == '{') {
|
||||
$endPos = strpos($token, '}');
|
||||
$chars = substr($token, 1, $endPos - 1);
|
||||
$chars = substr($token, 1, $endPos - 1);
|
||||
if (is_numeric($chars)) {
|
||||
$token = '';
|
||||
while (strlen($token) < $chars) {
|
||||
@@ -196,43 +229,43 @@ class Imap
|
||||
}
|
||||
$line = '';
|
||||
if (strlen($token) > $chars) {
|
||||
$line = substr($token, $chars);
|
||||
$line = substr($token, $chars);
|
||||
$token = substr($token, 0, $chars);
|
||||
} else {
|
||||
$line .= $this->nextLine();
|
||||
}
|
||||
$tokens[] = $token;
|
||||
$line = trim($line) . ' ';
|
||||
$line = trim($line) . ' ';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($stack && $token[strlen($token) - 1] == ')') {
|
||||
// closing braces are not separated by spaces, so we need to count them
|
||||
$braces = strlen($token);
|
||||
$token = rtrim($token, ')');
|
||||
$token = rtrim($token, ')');
|
||||
// only count braces if more than one
|
||||
$braces -= strlen($token) + 1;
|
||||
// only add if token had more than just closing braces
|
||||
if (rtrim($token) != '') {
|
||||
$tokens[] = rtrim($token);
|
||||
}
|
||||
$token = $tokens;
|
||||
$token = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
// special handline if more than one closing brace
|
||||
while ($braces-- > 0) {
|
||||
$tokens[] = $token;
|
||||
$token = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
$token = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
}
|
||||
}
|
||||
$tokens[] = $token;
|
||||
$line = substr($line, $pos + 1);
|
||||
$line = substr($line, $pos + 1);
|
||||
}
|
||||
|
||||
// maybe the server forgot to send some closing braces
|
||||
while ($stack) {
|
||||
$child = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
$child = $tokens;
|
||||
$tokens = array_pop($stack);
|
||||
$tokens[] = $child;
|
||||
}
|
||||
|
||||
@@ -274,7 +307,7 @@ class Imap
|
||||
*/
|
||||
public function readResponse($tag, $dontParse = false)
|
||||
{
|
||||
$lines = [];
|
||||
$lines = [];
|
||||
$tokens = null; // define $tokens variable before first use
|
||||
while (! $this->readLine($tokens, $tag, $dontParse)) {
|
||||
$lines[] = $tokens;
|
||||
@@ -287,7 +320,7 @@ class Imap
|
||||
|
||||
// last line has response code
|
||||
if ($tokens[0] == 'OK') {
|
||||
return $lines ? $lines : true;
|
||||
return $lines ?: true;
|
||||
} elseif ($tokens[0] == 'NO') {
|
||||
return false;
|
||||
}
|
||||
@@ -341,9 +374,7 @@ class Imap
|
||||
{
|
||||
$tag = null; // define $tag variable before first use
|
||||
$this->sendRequest($command, $tokens, $tag);
|
||||
$response = $this->readResponse($tag, $dontParse);
|
||||
|
||||
return $response;
|
||||
return $this->readResponse($tag, $dontParse);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,7 +387,7 @@ class Imap
|
||||
public function escapeString($string)
|
||||
{
|
||||
if (func_num_args() < 2) {
|
||||
if (strpos($string, "\n") !== false) {
|
||||
if (str_contains($string, "\n")) {
|
||||
return ['{' . strlen($string) . '}', $string];
|
||||
}
|
||||
|
||||
@@ -412,7 +443,7 @@ class Imap
|
||||
if ($this->socket) {
|
||||
try {
|
||||
$result = $this->requestAndResponse('LOGOUT', [], true);
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
// ignoring exception
|
||||
}
|
||||
fclose($this->socket);
|
||||
@@ -425,7 +456,7 @@ class Imap
|
||||
* Get capabilities from IMAP server
|
||||
*
|
||||
* @return array list of capabilities
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function capability()
|
||||
{
|
||||
@@ -450,7 +481,7 @@ class Imap
|
||||
* @param string $box which folder to change to or examine
|
||||
* @return bool|array false if error, array with returned information
|
||||
* otherwise (flags, exists, recent, uidvalidity)
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
|
||||
{
|
||||
@@ -489,7 +520,7 @@ class Imap
|
||||
*
|
||||
* @param string $box change to this folder
|
||||
* @return bool|array see examineOrselect()
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function select($box = 'INBOX')
|
||||
{
|
||||
@@ -501,7 +532,7 @@ class Imap
|
||||
*
|
||||
* @param string $box examine this folder
|
||||
* @return bool|array see examineOrselect()
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function examine($box = 'INBOX')
|
||||
{
|
||||
@@ -535,7 +566,7 @@ class Imap
|
||||
$set = (int) $from . ':' . (int) $to;
|
||||
}
|
||||
|
||||
$items = (array) $items;
|
||||
$items = (array) $items;
|
||||
$itemList = $this->escapeList($items);
|
||||
|
||||
$tag = null; // define $tag variable before first use
|
||||
@@ -593,6 +624,7 @@ class Imap
|
||||
// if we want only one message we can ignore everything else and just return
|
||||
if ($to === null && ! is_array($from) && ($uid ? $tokens[2][$uidKey] == $from : $tokens[0] == $from)) {
|
||||
// we still need to read all lines
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedWhile
|
||||
while (! $this->readLine($tokens, $tag)) {
|
||||
}
|
||||
return $data;
|
||||
@@ -615,12 +647,12 @@ class Imap
|
||||
* @param string $reference mailbox reference for list
|
||||
* @param string $mailbox mailbox name match with wildcards
|
||||
* @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function listMailbox($reference = '', $mailbox = '*')
|
||||
{
|
||||
$result = [];
|
||||
$list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
|
||||
$list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
|
||||
if (! $list || $list === true) {
|
||||
return $result;
|
||||
}
|
||||
@@ -645,7 +677,7 @@ class Imap
|
||||
* @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
|
||||
* @param bool $silent if false the return values are the new flags for the wanted messages
|
||||
* @return bool|array new flags if $silent is false, else true or false depending on success
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
|
||||
{
|
||||
@@ -658,7 +690,7 @@ class Imap
|
||||
}
|
||||
|
||||
$flags = $this->escapeList($flags);
|
||||
$set = (int) $from;
|
||||
$set = (int) $from;
|
||||
if ($to !== null) {
|
||||
$set .= ':' . ($to == INF ? '*' : (int) $to);
|
||||
}
|
||||
@@ -689,11 +721,11 @@ class Imap
|
||||
* @param array $flags flags for new message
|
||||
* @param string $date date for new message
|
||||
* @return bool success
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function append($folder, $message, $flags = null, $date = null)
|
||||
{
|
||||
$tokens = [];
|
||||
$tokens = [];
|
||||
$tokens[] = $this->escapeString($folder);
|
||||
if ($flags !== null) {
|
||||
$tokens[] = $this->escapeList($flags);
|
||||
@@ -710,14 +742,14 @@ class Imap
|
||||
* copy message set from current folder to other folder
|
||||
*
|
||||
* @param string $folder destination folder
|
||||
* @param $from
|
||||
* @param int $from
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @return bool success
|
||||
*/
|
||||
public function copy($folder, $from, $to = null)
|
||||
{
|
||||
$set = (int) $from;
|
||||
$set = (string) $from;
|
||||
if ($to !== null) {
|
||||
$set .= ':' . ($to == INF ? '*' : (int) $to);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,23 @@
|
||||
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Mail\Protocol\Pop3\Response;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function fwrite;
|
||||
use function is_string;
|
||||
use function md5;
|
||||
use function rtrim;
|
||||
use function stream_socket_enable_crypto;
|
||||
use function strpos;
|
||||
use function strtok;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
class Pop3
|
||||
{
|
||||
use ProtocolTrait;
|
||||
@@ -15,17 +30,17 @@ class Pop3
|
||||
|
||||
/**
|
||||
* saves if server supports top
|
||||
*
|
||||
* @var null|bool
|
||||
*/
|
||||
public $hasTop = null;
|
||||
public $hasTop;
|
||||
|
||||
/**
|
||||
* @var null|resource
|
||||
*/
|
||||
/** @var null|resource */
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* greeting timestamp for apop
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $timestamp;
|
||||
@@ -67,7 +82,7 @@ class Pop3
|
||||
public function connect($host, $port = null, $ssl = false)
|
||||
{
|
||||
$transport = 'tcp';
|
||||
$isTls = false;
|
||||
$isTls = false;
|
||||
|
||||
if ($ssl) {
|
||||
$ssl = strtolower($ssl);
|
||||
@@ -136,6 +151,37 @@ class Pop3
|
||||
* @return string response
|
||||
*/
|
||||
public function readResponse($multiline = false)
|
||||
{
|
||||
$response = $this->readRemoteResponse();
|
||||
|
||||
if ($response->status() != '+OK') {
|
||||
throw new Exception\RuntimeException('last request failed');
|
||||
}
|
||||
|
||||
$message = $response->message();
|
||||
|
||||
if ($multiline) {
|
||||
$message = '';
|
||||
$line = fgets($this->socket);
|
||||
while ($line && rtrim($line, "\r\n") != '.') {
|
||||
if ($line[0] == '.') {
|
||||
$line = substr($line, 1);
|
||||
}
|
||||
$message .= $line;
|
||||
$line = fgets($this->socket);
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a response
|
||||
* return extracted status / message from response
|
||||
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
protected function readRemoteResponse(): Response
|
||||
{
|
||||
ErrorHandler::start();
|
||||
$result = fgets($this->socket);
|
||||
@@ -146,29 +192,13 @@ class Pop3
|
||||
|
||||
$result = trim($result);
|
||||
if (strpos($result, ' ')) {
|
||||
list($status, $message) = explode(' ', $result, 2);
|
||||
[$status, $message] = explode(' ', $result, 2);
|
||||
} else {
|
||||
$status = $result;
|
||||
$status = $result;
|
||||
$message = '';
|
||||
}
|
||||
|
||||
if ($status != '+OK') {
|
||||
throw new Exception\RuntimeException('last request failed');
|
||||
}
|
||||
|
||||
if ($multiline) {
|
||||
$message = '';
|
||||
$line = fgets($this->socket);
|
||||
while ($line && rtrim($line, "\r\n") != '.') {
|
||||
if ($line[0] == '.') {
|
||||
$line = substr($line, 1);
|
||||
}
|
||||
$message .= $line;
|
||||
$line = fgets($this->socket);
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
return new Response($status, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,6 +206,7 @@ class Pop3
|
||||
*
|
||||
* @see sendRequest()
|
||||
* @see readResponse()
|
||||
*
|
||||
* @param string $request request
|
||||
* @param bool $multiline multiline response?
|
||||
* @return string result from readResponse()
|
||||
@@ -194,7 +225,7 @@ class Pop3
|
||||
if ($this->socket) {
|
||||
try {
|
||||
$this->request('QUIT');
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
// ignore error - we're closing the socket anyway
|
||||
}
|
||||
|
||||
@@ -227,7 +258,7 @@ class Pop3
|
||||
try {
|
||||
$this->request("APOP $user " . md5($this->timestamp . $password));
|
||||
return;
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
@@ -245,10 +276,10 @@ class Pop3
|
||||
public function status(&$messages, &$octets)
|
||||
{
|
||||
$messages = 0;
|
||||
$octets = 0;
|
||||
$result = $this->request('STAT');
|
||||
$octets = 0;
|
||||
$result = $this->request('STAT');
|
||||
|
||||
list($messages, $octets) = explode(' ', $result);
|
||||
[$messages, $octets] = explode(' ', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,17 +293,17 @@ class Pop3
|
||||
if ($msgno !== null) {
|
||||
$result = $this->request("LIST $msgno");
|
||||
|
||||
list(, $result) = explode(' ', $result);
|
||||
[, $result] = explode(' ', $result);
|
||||
return (int) $result;
|
||||
}
|
||||
|
||||
$result = $this->request('LIST', true);
|
||||
$result = $this->request('LIST', true);
|
||||
$messages = [];
|
||||
$line = strtok($result, "\n");
|
||||
$line = strtok($result, "\n");
|
||||
while ($line) {
|
||||
list($no, $size) = explode(' ', trim($line));
|
||||
[$no, $size] = explode(' ', trim($line));
|
||||
$messages[(int) $no] = (int) $size;
|
||||
$line = strtok("\n");
|
||||
$line = strtok("\n");
|
||||
}
|
||||
|
||||
return $messages;
|
||||
@@ -289,19 +320,19 @@ class Pop3
|
||||
if ($msgno !== null) {
|
||||
$result = $this->request("UIDL $msgno");
|
||||
|
||||
list(, $result) = explode(' ', $result);
|
||||
[, $result] = explode(' ', $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = $this->request('UIDL', true);
|
||||
|
||||
$result = explode("\n", $result);
|
||||
$result = explode("\n", $result);
|
||||
$messages = [];
|
||||
foreach ($result as $line) {
|
||||
if (! $line) {
|
||||
continue;
|
||||
}
|
||||
list($no, $id) = explode(' ', trim($line), 2);
|
||||
[$no, $id] = explode(' ', trim($line), 2);
|
||||
$messages[(int) $no] = $id;
|
||||
}
|
||||
|
||||
@@ -333,7 +364,7 @@ class Pop3
|
||||
}
|
||||
$this->hasTop = true;
|
||||
|
||||
$lines = (! $lines || $lines < 1) ? 0 : (int) $lines;
|
||||
$lines = ! $lines || $lines < 1 ? 0 : (int) $lines;
|
||||
|
||||
try {
|
||||
$result = $this->request("TOP $msgno $lines", true);
|
||||
@@ -357,8 +388,7 @@ class Pop3
|
||||
*/
|
||||
public function retrieve($msgno)
|
||||
{
|
||||
$result = $this->request("RETR $msgno", true);
|
||||
return $result;
|
||||
return $this->request("RETR $msgno", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,7 +402,7 @@ class Pop3
|
||||
/**
|
||||
* Make a DELE count to remove a message
|
||||
*
|
||||
* @param $msgno
|
||||
* @param int $msgno
|
||||
*/
|
||||
public function delete($msgno)
|
||||
{
|
||||
|
||||
35
lib/laminas/laminas-mail/src/Protocol/Pop3/Response.php
Normal file
35
lib/laminas/laminas-mail/src/Protocol/Pop3/Response.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Mail\Protocol\Pop3;
|
||||
|
||||
/**
|
||||
* POP3 response value object
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class Response
|
||||
{
|
||||
/** @var string $status */
|
||||
private $status;
|
||||
|
||||
/** @var string $message */
|
||||
private $message;
|
||||
|
||||
public function __construct(string $status, string $message)
|
||||
{
|
||||
$this->status = $status;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
public function status(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function message(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Laminas\Mail\Protocol\Pop3\Xoauth2;
|
||||
|
||||
use Laminas\Mail\Protocol\Exception\RuntimeException;
|
||||
use Laminas\Mail\Protocol\Pop3;
|
||||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class Microsoft extends Pop3
|
||||
{
|
||||
protected const AUTH_INITIALIZE_REQUEST = 'AUTH XOAUTH2';
|
||||
protected const AUTH_RESPONSE_INITIALIZED_OK = '+';
|
||||
|
||||
/**
|
||||
* @param string $user the target mailbox to access
|
||||
* @param string $password OAUTH2 accessToken
|
||||
* @param bool $tryApop obsolete parameter not used here
|
||||
*/
|
||||
public function login($user, $password, $tryApop = true): void
|
||||
{
|
||||
$this->sendRequest(self::AUTH_INITIALIZE_REQUEST);
|
||||
|
||||
$response = $this->readRemoteResponse();
|
||||
|
||||
if ($response->status() != self::AUTH_RESPONSE_INITIALIZED_OK) {
|
||||
throw new RuntimeException($response->message());
|
||||
}
|
||||
|
||||
$this->request(Xoauth2::encodeXoauth2Sasl($user, $password));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,17 @@ namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function defined;
|
||||
use function sprintf;
|
||||
use function stream_context_create;
|
||||
use function stream_set_timeout;
|
||||
use function stream_socket_client;
|
||||
|
||||
use const STREAM_CLIENT_CONNECT;
|
||||
use const STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||
use const STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
|
||||
use const STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
|
||||
|
||||
/**
|
||||
* https://bugs.php.net/bug.php?id=69195
|
||||
*/
|
||||
@@ -11,6 +22,7 @@ trait ProtocolTrait
|
||||
{
|
||||
/**
|
||||
* If set to true, do not validate the SSL certificate
|
||||
*
|
||||
* @var null|bool
|
||||
*/
|
||||
protected $novalidatecert;
|
||||
@@ -45,8 +57,6 @@ trait ProtocolTrait
|
||||
|
||||
/**
|
||||
* Should we validate SSL certificate?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateCert(): bool
|
||||
{
|
||||
@@ -94,7 +104,7 @@ trait ProtocolTrait
|
||||
STREAM_CLIENT_CONNECT,
|
||||
stream_context_create($this->prepareSocketOptions())
|
||||
);
|
||||
$error = ErrorHandler::stop();
|
||||
$error = ErrorHandler::stop();
|
||||
|
||||
if (! $socket) {
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
|
||||
@@ -5,6 +5,23 @@ namespace Laminas\Mail\Protocol;
|
||||
use Generator;
|
||||
use Laminas\Mail\Headers;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_replace_recursive;
|
||||
use function chunk_split;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function ini_get;
|
||||
use function is_array;
|
||||
use function rewind;
|
||||
use function rtrim;
|
||||
use function stream_socket_enable_crypto;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* SMTP implementation of Laminas\Mail\Protocol\AbstractProtocol
|
||||
*
|
||||
@@ -18,6 +35,7 @@ class Smtp extends AbstractProtocol
|
||||
/**
|
||||
* RFC 5322 section-2.2.3 specifies maximum of 998 bytes per line.
|
||||
* This may not be exceeded.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc5322#section-2.2.3
|
||||
*/
|
||||
public const SMTP_LINE_LIMIT = 998;
|
||||
@@ -69,7 +87,7 @@ class Smtp extends AbstractProtocol
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $data = null;
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Whether or not send QUIT command
|
||||
@@ -79,8 +97,6 @@ class Smtp extends AbstractProtocol
|
||||
protected $useCompleteQuit = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The first argument may be an array of all options. If so, it must include
|
||||
* the 'host' and 'port' keys in order to ensure that all required values
|
||||
* are present.
|
||||
@@ -90,7 +106,7 @@ class Smtp extends AbstractProtocol
|
||||
* @param null|array $config
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function __construct($host = '127.0.0.1', $port = null, array $config = null)
|
||||
public function __construct($host = '127.0.0.1', $port = null, ?array $config = null)
|
||||
{
|
||||
// Did we receive a configuration array?
|
||||
if (is_array($host)) {
|
||||
@@ -129,7 +145,7 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
case 'ssl':
|
||||
$this->transport = 'ssl';
|
||||
$this->secure = 'ssl';
|
||||
$this->secure = 'ssl';
|
||||
if ($port === null) {
|
||||
$port = 465;
|
||||
}
|
||||
@@ -177,10 +193,7 @@ class Smtp extends AbstractProtocol
|
||||
/**
|
||||
* Read $data as lines terminated by "\n"
|
||||
*
|
||||
* @param string $data
|
||||
* @param int $chunkSize
|
||||
* @return Generator|string[]
|
||||
* @author Elan Ruusamäe <glen@pld-linux.org>
|
||||
*/
|
||||
private static function chunkedReader(string $data, int $chunkSize = 4096): Generator
|
||||
{
|
||||
@@ -305,7 +318,7 @@ class Smtp extends AbstractProtocol
|
||||
* Send EHLO or HELO depending on capabilities of smtp host
|
||||
*
|
||||
* @param string $host The client hostname or IP address (default: 127.0.0.1)
|
||||
* @throws \Exception|Exception\ExceptionInterface
|
||||
* @throws Exception\ExceptionInterface
|
||||
*/
|
||||
protected function ehlo($host)
|
||||
{
|
||||
@@ -313,7 +326,7 @@ class Smtp extends AbstractProtocol
|
||||
try {
|
||||
$this->_send('EHLO ' . $host);
|
||||
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
$this->_send('HELO ' . $host);
|
||||
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
|
||||
}
|
||||
@@ -388,7 +401,7 @@ class Smtp extends AbstractProtocol
|
||||
// Add "-1" to stay within limits,
|
||||
// because Headers::FOLDING includes a byte for space character after \r\n
|
||||
$chunks = chunk_split($line, self::SMTP_LINE_LIMIT - 1, Headers::FOLDING);
|
||||
$line = substr($chunks, 0, -strlen(Headers::FOLDING));
|
||||
$line = substr($chunks, 0, -strlen(Headers::FOLDING));
|
||||
}
|
||||
|
||||
$this->_send($line);
|
||||
@@ -420,7 +433,6 @@ class Smtp extends AbstractProtocol
|
||||
* Issues the NOOP command end validates answer
|
||||
*
|
||||
* Not used by Laminas\Mail, could be used to keep a connection alive or check if it is still open.
|
||||
*
|
||||
*/
|
||||
public function noop()
|
||||
{
|
||||
@@ -443,7 +455,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Issues the QUIT command and clears the current session
|
||||
*
|
||||
*/
|
||||
public function quit()
|
||||
{
|
||||
@@ -475,7 +486,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Closes connection
|
||||
*
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
@@ -488,7 +498,6 @@ class Smtp extends AbstractProtocol
|
||||
// @codingStandardsIgnoreLine PSR2.Methods.MethodDeclaration.Underscore
|
||||
protected function _disconnect()
|
||||
{
|
||||
|
||||
// Make sure the session gets closed
|
||||
$this->quit();
|
||||
parent::_disconnect();
|
||||
@@ -496,7 +505,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Start mail session
|
||||
*
|
||||
*/
|
||||
protected function startSession()
|
||||
{
|
||||
@@ -505,7 +513,6 @@ class Smtp extends AbstractProtocol
|
||||
|
||||
/**
|
||||
* Stop mail session
|
||||
*
|
||||
*/
|
||||
protected function stopSession()
|
||||
{
|
||||
|
||||
@@ -5,24 +5,23 @@ namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
use Laminas\Crypt\Hmac;
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function base64_decode;
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs CRAM-MD5 authentication
|
||||
*/
|
||||
class Crammd5 extends Smtp
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $username;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* All parameters may be passed as an array to the first argument of the
|
||||
* constructor. If so,
|
||||
*
|
||||
@@ -67,7 +66,7 @@ class Crammd5 extends Smtp
|
||||
$this->_send('AUTH CRAM-MD5');
|
||||
$challenge = $this->_expect(334);
|
||||
$challenge = base64_decode($challenge);
|
||||
$digest = $this->hmacMd5($this->getPassword(), $challenge);
|
||||
$digest = $this->hmacMd5($this->getPassword(), $challenge);
|
||||
$this->_send(base64_encode($this->getUsername() . ' ' . $digest));
|
||||
$this->_expect(235);
|
||||
$this->auth = true;
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs LOGIN authentication
|
||||
*/
|
||||
@@ -24,8 +28,6 @@ class Login extends Smtp
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $host (Default: 127.0.0.1)
|
||||
* @param int $port (Default: null)
|
||||
* @param array $config Auth-specific parameters
|
||||
@@ -58,7 +60,6 @@ class Login extends Smtp
|
||||
|
||||
/**
|
||||
* Perform LOGIN authentication with supplied credentials
|
||||
*
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs PLAIN authentication
|
||||
*/
|
||||
@@ -24,8 +28,6 @@ class Plain extends Smtp
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $host (Default: 127.0.0.1)
|
||||
* @param int $port (Default: null)
|
||||
* @param array $config Auth-specific parameters
|
||||
@@ -58,7 +60,6 @@ class Plain extends Smtp
|
||||
|
||||
/**
|
||||
* Perform PLAIN authentication with supplied credentials
|
||||
*
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
|
||||
123
lib/laminas/laminas-mail/src/Protocol/Smtp/Auth/Xoauth2.php
Normal file
123
lib/laminas/laminas-mail/src/Protocol/Smtp/Auth/Xoauth2.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Laminas\Mail\Protocol\Smtp\Auth;
|
||||
|
||||
use Laminas\Mail\Protocol\Smtp;
|
||||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2 as Xoauth2AuthEncoder;
|
||||
|
||||
use function array_replace_recursive;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Performs Xoauth2 authentication
|
||||
*
|
||||
* @psalm-suppress PropertyNotSetInConstructor
|
||||
*/
|
||||
final class Xoauth2 extends Smtp
|
||||
{
|
||||
/**
|
||||
* SMTP username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $username;
|
||||
|
||||
/**
|
||||
* Xoauth2 access token
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @param string|array $host (Default: 127.0.0.1)
|
||||
* @param int|null $port (Default: null)
|
||||
* @param array|null $config Auth-specific parameters
|
||||
*/
|
||||
public function __construct($host = '127.0.0.1', $port = null, ?array $config = null)
|
||||
{
|
||||
// Did we receive a configuration array?
|
||||
$origConfig = $config;
|
||||
if (is_array($host)) {
|
||||
// Merge config array with principal array, if provided
|
||||
if (is_array($config)) {
|
||||
$config = array_replace_recursive($host, $config);
|
||||
} else {
|
||||
$config = $host;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($config)) {
|
||||
if (isset($config['username'])) {
|
||||
$this->setUsername((string) $config['username']);
|
||||
}
|
||||
if (isset($config['access_token'])) {
|
||||
$this->setAccessToken((string) $config['access_token']);
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent with original arguments
|
||||
parent::__construct($host, $port, $origConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform XOAUTH2 authentication with supplied credentials
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
// Ensure AUTH has not already been initiated.
|
||||
parent::auth();
|
||||
|
||||
$this->_send('AUTH XOAUTH2');
|
||||
$this->_expect('334');
|
||||
$this->_send(Xoauth2AuthEncoder::encodeXoauth2Sasl($this->getUsername(), $this->getAccessToken()));
|
||||
$this->_expect('235');
|
||||
$this->auth = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value for username
|
||||
*
|
||||
* @param string $username
|
||||
* @return Xoauth2
|
||||
*/
|
||||
public function setUsername($username)
|
||||
{
|
||||
$this->username = $username;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get username
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value for access token
|
||||
*
|
||||
* @param string $token
|
||||
* @return Xoauth2
|
||||
*/
|
||||
public function setAccessToken($token)
|
||||
{
|
||||
$this->accessToken = $token;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,33 @@
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
use Laminas\ServiceManager\AbstractPluginManager;
|
||||
use Laminas\ServiceManager\ConfigInterface;
|
||||
use Laminas\ServiceManager\Exception\InvalidServiceException;
|
||||
use Laminas\ServiceManager\Factory\InvokableFactory;
|
||||
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Plugin manager implementation for SMTP extensions.
|
||||
*
|
||||
* Enforces that SMTP extensions retrieved are instances of Smtp. Additionally,
|
||||
* it registers a number of default extensions available.
|
||||
*
|
||||
* @link ConfigInterface
|
||||
*
|
||||
* @psalm-import-type FactoriesConfigurationType from ConfigInterface
|
||||
*
|
||||
* @extends AbstractPluginManager<Smtp>
|
||||
* @final
|
||||
*/
|
||||
class SmtpPluginManager extends AbstractPluginManager
|
||||
{
|
||||
/**
|
||||
* Service aliases
|
||||
*
|
||||
* @var array<array-key, class-string>
|
||||
*/
|
||||
protected $aliases = [
|
||||
'crammd5' => Smtp\Auth\Crammd5::class,
|
||||
@@ -27,61 +41,58 @@ class SmtpPluginManager extends AbstractPluginManager
|
||||
'Login' => Smtp\Auth\Login::class,
|
||||
'plain' => Smtp\Auth\Plain::class,
|
||||
'Plain' => Smtp\Auth\Plain::class,
|
||||
'xoauth2' => Smtp\Auth\Xoauth2::class,
|
||||
'Xoauth2' => Smtp\Auth\Xoauth2::class,
|
||||
'smtp' => Smtp::class,
|
||||
'Smtp' => Smtp::class,
|
||||
'SMTP' => Smtp::class,
|
||||
|
||||
// Legacy Zend Framework aliases
|
||||
\Zend\Mail\Protocol\Smtp\Auth\Crammd5::class => Smtp\Auth\Crammd5::class,
|
||||
\Zend\Mail\Protocol\Smtp\Auth\Login::class => Smtp\Auth\Login::class,
|
||||
\Zend\Mail\Protocol\Smtp\Auth\Plain::class => Smtp\Auth\Plain::class,
|
||||
\Zend\Mail\Protocol\Smtp::class => Smtp::class,
|
||||
|
||||
'Zend\Mail\Protocol\Smtp\Auth\Crammd5' => Smtp\Auth\Crammd5::class,
|
||||
'Zend\Mail\Protocol\Smtp\Auth\Login' => Smtp\Auth\Login::class,
|
||||
'Zend\Mail\Protocol\Smtp\Auth\Plain' => Smtp\Auth\Plain::class,
|
||||
'Zend\Mail\Protocol\Smtp' => Smtp::class,
|
||||
// v2 normalized FQCNs
|
||||
'zendmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
|
||||
'zendmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
|
||||
'zendmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
|
||||
'zendmailprotocolsmtp' => Smtp::class,
|
||||
'zendmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
|
||||
'zendmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
|
||||
'zendmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
|
||||
'zendmailprotocolsmtp' => Smtp::class,
|
||||
'laminasmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
|
||||
'laminasmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
|
||||
'laminasmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
|
||||
'laminasmailprotocolsmtp' => Smtp::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Service factories
|
||||
*
|
||||
* @var array
|
||||
* @var FactoriesConfigurationType
|
||||
*/
|
||||
protected $factories = [
|
||||
Smtp\Auth\Crammd5::class => InvokableFactory::class,
|
||||
Smtp\Auth\Login::class => InvokableFactory::class,
|
||||
Smtp\Auth\Plain::class => InvokableFactory::class,
|
||||
Smtp\Auth\Xoauth2::class => InvokableFactory::class,
|
||||
Smtp::class => InvokableFactory::class,
|
||||
|
||||
// v2 normalized service names
|
||||
|
||||
'laminasmailprotocolsmtpauthcrammd5' => InvokableFactory::class,
|
||||
'laminasmailprotocolsmtpauthlogin' => InvokableFactory::class,
|
||||
'laminasmailprotocolsmtpauthplain' => InvokableFactory::class,
|
||||
'laminasmailprotocolsmtp' => InvokableFactory::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Plugins must be an instance of the Smtp class
|
||||
*
|
||||
* @var string
|
||||
* @var class-string<Smtp>
|
||||
*/
|
||||
protected $instanceOf = Smtp::class;
|
||||
|
||||
/**
|
||||
* Validate a retrieved plugin instance (v3).
|
||||
*
|
||||
* @param object|array $instance
|
||||
* @throws InvalidServiceException
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($instance)
|
||||
public function validate(mixed $instance)
|
||||
{
|
||||
if (! $instance instanceof $this->instanceOf) {
|
||||
throw new InvalidServiceException(sprintf(
|
||||
'Plugin of type %s is invalid; must extend %s',
|
||||
(is_object($instance) ? get_class($instance) : gettype($instance)),
|
||||
is_object($instance) ? $instance::class : gettype($instance),
|
||||
$this->instanceOf
|
||||
));
|
||||
}
|
||||
@@ -90,10 +101,12 @@ class SmtpPluginManager extends AbstractPluginManager
|
||||
/**
|
||||
* Validate a retrieved plugin instance (v2).
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param object $plugin
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function validatePlugin($plugin)
|
||||
public function validatePlugin(mixed $plugin)
|
||||
{
|
||||
try {
|
||||
$this->validate($plugin);
|
||||
|
||||
@@ -2,25 +2,34 @@
|
||||
|
||||
namespace Laminas\Mail\Protocol;
|
||||
|
||||
// phpcs:ignore WebimpressCodingStandard.PHP.CorrectClassNameCase.Invalid
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Laminas\ServiceManager\FactoryInterface;
|
||||
use Laminas\ServiceManager\ServiceLocatorInterface;
|
||||
use Laminas\ServiceManager\ServiceManager;
|
||||
|
||||
/**
|
||||
* @link ServiceManager
|
||||
*
|
||||
* @psalm-import-type ServiceManagerConfiguration from ServiceManager
|
||||
*/
|
||||
class SmtpPluginManagerFactory implements FactoryInterface
|
||||
{
|
||||
/**
|
||||
* laminas-servicemanager v2 support for invocation options.
|
||||
*
|
||||
* @param array
|
||||
* @var array
|
||||
* @psalm-var ServiceManagerConfiguration
|
||||
*/
|
||||
protected $creationOptions;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param ServiceManagerConfiguration $options
|
||||
* @return SmtpPluginManager
|
||||
*/
|
||||
public function __invoke(ContainerInterface $container, $name, array $options = null)
|
||||
public function __invoke(ContainerInterface $container, $name, ?array $options = null)
|
||||
{
|
||||
return new SmtpPluginManager($container, $options ?: []);
|
||||
}
|
||||
@@ -38,7 +47,7 @@ class SmtpPluginManagerFactory implements FactoryInterface
|
||||
/**
|
||||
* laminas-servicemanager v2 support for invocation options.
|
||||
*
|
||||
* @param array $options
|
||||
* @psalm-param ServiceManagerConfiguration $options
|
||||
* @return void
|
||||
*/
|
||||
public function setCreationOptions(array $options)
|
||||
|
||||
32
lib/laminas/laminas-mail/src/Protocol/Xoauth2/Xoauth2.php
Normal file
32
lib/laminas/laminas-mail/src/Protocol/Xoauth2/Xoauth2.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Mail\Protocol\Xoauth2;
|
||||
|
||||
use function base64_encode;
|
||||
use function chr;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Xoauth2
|
||||
{
|
||||
/**
|
||||
* encodes accessToken and target mailbox to Xoauth2 SASL base64 encoded string
|
||||
*/
|
||||
public static function encodeXoauth2Sasl(string $targetMailbox, string $accessToken): string
|
||||
{
|
||||
return base64_encode(
|
||||
sprintf(
|
||||
"user=%s%sauth=Bearer %s%s%s",
|
||||
$targetMailbox,
|
||||
chr(0x01),
|
||||
$accessToken,
|
||||
chr(0x01),
|
||||
chr(0x01)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,14 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use Laminas\Mail\Storage\Message;
|
||||
use ReturnTypeWillChange;
|
||||
use SeekableIterator;
|
||||
|
||||
use function str_starts_with;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
abstract class AbstractStorage implements
|
||||
ArrayAccess,
|
||||
Countable,
|
||||
@@ -14,6 +19,7 @@ abstract class AbstractStorage implements
|
||||
{
|
||||
/**
|
||||
* class capabilities with default values
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $has = [
|
||||
@@ -27,19 +33,22 @@ abstract class AbstractStorage implements
|
||||
|
||||
/**
|
||||
* current iteration position
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $iterationPos = 0;
|
||||
|
||||
/**
|
||||
* maximum iteration position (= message count)
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
protected $iterationMax = null;
|
||||
protected $iterationMax;
|
||||
|
||||
/**
|
||||
* used message class, change it in an extended class to extend the returned message class
|
||||
* @var string
|
||||
*
|
||||
* @var class-string<Message\MessageInterface>
|
||||
*/
|
||||
protected $messageClass = Message::class;
|
||||
|
||||
@@ -54,13 +63,13 @@ abstract class AbstractStorage implements
|
||||
*
|
||||
* @param string $var property name
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return bool supported or not
|
||||
* @return null|bool supported or not
|
||||
*/
|
||||
public function __get($var)
|
||||
{
|
||||
if (strpos($var, 'has') === 0) {
|
||||
if (str_starts_with($var, 'has')) {
|
||||
$var = strtolower(substr($var, 3));
|
||||
return isset($this->has[$var]) ? $this->has[$var] : null;
|
||||
return $this->has[$var] ?? null;
|
||||
}
|
||||
|
||||
throw new Exception\InvalidArgumentException($var . ' not found');
|
||||
@@ -95,8 +104,8 @@ abstract class AbstractStorage implements
|
||||
/**
|
||||
* Get a message with headers and body
|
||||
*
|
||||
* @param $id int number of message
|
||||
* @return Message
|
||||
* @param int $id number of message
|
||||
* @return Message\MessageInterface
|
||||
*/
|
||||
abstract public function getMessage($id);
|
||||
|
||||
@@ -149,7 +158,7 @@ abstract class AbstractStorage implements
|
||||
/**
|
||||
* delete a message from current box/folder
|
||||
*
|
||||
* @param $id
|
||||
* @param int $id message number
|
||||
*/
|
||||
abstract public function removeMessage($id);
|
||||
|
||||
@@ -202,7 +211,7 @@ abstract class AbstractStorage implements
|
||||
if ($this->getMessage($id)) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -212,7 +221,7 @@ abstract class AbstractStorage implements
|
||||
* ArrayAccess::offsetGet()
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Laminas\Mail\Storage\Message message object
|
||||
* @return Message message object
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetGet($id)
|
||||
@@ -223,12 +232,10 @@ abstract class AbstractStorage implements
|
||||
/**
|
||||
* ArrayAccess::offsetSet()
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param mixed $value
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetSet($id, $value)
|
||||
public function offsetSet(mixed $id, mixed $value)
|
||||
{
|
||||
throw new Exception\RuntimeException('cannot write mail messages via array access');
|
||||
}
|
||||
|
||||
@@ -4,48 +4,39 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use RecursiveIterator;
|
||||
use ReturnTypeWillChange;
|
||||
use Stringable;
|
||||
|
||||
class Folder implements RecursiveIterator
|
||||
use function current;
|
||||
use function key;
|
||||
use function next;
|
||||
use function reset;
|
||||
|
||||
class Folder implements RecursiveIterator, Stringable
|
||||
{
|
||||
/**
|
||||
* subfolders of folder array(localName => \Laminas\Mail\Storage\Folder folder)
|
||||
* @var array
|
||||
*/
|
||||
protected $folders;
|
||||
|
||||
/**
|
||||
* local name (name of folder in parent folder)
|
||||
* @var string
|
||||
*/
|
||||
protected $localName;
|
||||
|
||||
/**
|
||||
* global name (absolute name of folder)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $globalName;
|
||||
|
||||
/**
|
||||
* folder is selectable if folder is able to hold messages, otherwise it is a parent folder
|
||||
* @var bool
|
||||
*/
|
||||
protected $selectable = true;
|
||||
|
||||
/**
|
||||
* create a new mail folder instance
|
||||
*
|
||||
* @param string $localName name of folder in current subdirectory
|
||||
* @param string $localName local name (name of folder in parent folder)
|
||||
* @param string $globalName absolute name of folder
|
||||
* @param bool $selectable if true folder holds messages, if false it's
|
||||
* just a parent for subfolders (Default: true)
|
||||
* @param array $folders init with given instances of Folder as subfolders
|
||||
* @param array<string, Folder> $folders subfolders of
|
||||
* folder array(localName => \Laminas\Mail\Storage\Folder folder)
|
||||
*/
|
||||
public function __construct($localName, $globalName = '', $selectable = true, array $folders = [])
|
||||
{
|
||||
$this->localName = $localName;
|
||||
$this->globalName = $globalName ? $globalName : $localName;
|
||||
$this->selectable = $selectable;
|
||||
$this->folders = $folders;
|
||||
public function __construct(
|
||||
protected $localName,
|
||||
$globalName = '',
|
||||
protected $selectable = true,
|
||||
protected array $folders = []
|
||||
) {
|
||||
$this->globalName = $globalName ?: $localName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +54,7 @@ class Folder implements RecursiveIterator
|
||||
/**
|
||||
* implements RecursiveIterator::getChildren()
|
||||
*
|
||||
* @return \Laminas\Mail\Storage\Folder same as self::current()
|
||||
* @return Folder same as self::current()
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function getChildren()
|
||||
@@ -105,7 +96,7 @@ class Folder implements RecursiveIterator
|
||||
/**
|
||||
* implements Iterator::current()
|
||||
*
|
||||
* @return \Laminas\Mail\Storage\Folder current folder
|
||||
* @return Folder current folder
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -127,7 +118,7 @@ class Folder implements RecursiveIterator
|
||||
*
|
||||
* @param string $name wanted subfolder
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return \Laminas\Mail\Storage\Folder folder named $folder
|
||||
* @return Folder folder named $folder
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
@@ -142,7 +133,7 @@ class Folder implements RecursiveIterator
|
||||
* add or replace subfolder named $name
|
||||
*
|
||||
* @param string $name local name of subfolder
|
||||
* @param \Laminas\Mail\Storage\Folder $folder instance for new subfolder
|
||||
* @param Folder $folder instance for new subfolder
|
||||
*/
|
||||
public function __set($name, self $folder)
|
||||
{
|
||||
@@ -164,7 +155,7 @@ class Folder implements RecursiveIterator
|
||||
*
|
||||
* @return string global name of folder
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->getGlobalName();
|
||||
}
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
|
||||
namespace Laminas\Mail\Storage\Folder;
|
||||
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Folder;
|
||||
|
||||
interface FolderInterface
|
||||
{
|
||||
/**
|
||||
* get root folder or given folder
|
||||
*
|
||||
* @param string $rootFolder get folder structure for given folder, else root
|
||||
* @return FolderInterface root or wanted folder
|
||||
* @return Folder root or wanted folder
|
||||
*/
|
||||
public function getFolders($rootFolder = null);
|
||||
|
||||
@@ -17,16 +20,16 @@ interface FolderInterface
|
||||
*
|
||||
* folder must be selectable!
|
||||
*
|
||||
* @param FolderInterface|string $globalName global name of folder or instance for subfolder
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @param Folder|string $globalName global name of folder or instance for subfolder
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function selectFolder($globalName);
|
||||
|
||||
/**
|
||||
* get Laminas\Mail\Storage\Folder instance for current folder
|
||||
*
|
||||
* @return FolderInterface instance of current folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @return string instance of current folder
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getCurrentFolder();
|
||||
}
|
||||
|
||||
@@ -4,31 +4,55 @@ namespace Laminas\Mail\Storage\Folder;
|
||||
|
||||
use Laminas\Mail\Storage;
|
||||
use Laminas\Mail\Storage\Exception;
|
||||
use Laminas\Mail\Storage\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Storage\Folder;
|
||||
use Laminas\Mail\Storage\ParamsNormalizer;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_pop;
|
||||
use function array_push;
|
||||
use function closedir;
|
||||
use function explode;
|
||||
use function is_dir;
|
||||
use function opendir;
|
||||
use function readdir;
|
||||
use function rtrim;
|
||||
use function sort;
|
||||
use function str_contains;
|
||||
use function str_starts_with;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_WARNING;
|
||||
|
||||
class Maildir extends Storage\Maildir implements FolderInterface
|
||||
{
|
||||
/**
|
||||
* root folder for folder structure
|
||||
*
|
||||
* @var Storage\Folder
|
||||
*/
|
||||
protected $rootFolder;
|
||||
|
||||
/**
|
||||
* rootdir of folder structure
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rootdir;
|
||||
|
||||
/**
|
||||
* name of current folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentFolder;
|
||||
|
||||
/**
|
||||
* delim char for subfolders
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $delim;
|
||||
@@ -42,7 +66,7 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
* - delim delim char for folder structure, default is '.'
|
||||
* - folder initial selected folder, default is 'INBOX'
|
||||
*
|
||||
* @param $params array mail reader specific parameters
|
||||
* @param object|array $params mail reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function __construct($params)
|
||||
@@ -61,14 +85,14 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
|
||||
$this->rootdir = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$delim = $params['delim'] ?? '.';
|
||||
$delim = $params['delim'] ?? '.';
|
||||
$this->delim = (string) $delim;
|
||||
|
||||
$folder = $params['folder'] ?? 'INBOX';
|
||||
|
||||
$this->buildFolderTree();
|
||||
$this->selectFolder((string) $folder);
|
||||
$this->has['top'] = true;
|
||||
$this->has['top'] = true;
|
||||
$this->has['flags'] = true;
|
||||
}
|
||||
|
||||
@@ -82,7 +106,7 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
*/
|
||||
protected function buildFolderTree()
|
||||
{
|
||||
$this->rootFolder = new Storage\Folder('/', '/', false);
|
||||
$this->rootFolder = new Storage\Folder('/', '/', false);
|
||||
$this->rootFolder->INBOX = new Storage\Folder('INBOX', 'INBOX', true);
|
||||
|
||||
ErrorHandler::start(E_WARNING);
|
||||
@@ -106,27 +130,27 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
closedir($dh);
|
||||
|
||||
sort($dirs);
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$parentFolder = $this->rootFolder;
|
||||
$parent = '.';
|
||||
$parent = '.';
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
do {
|
||||
if (strpos($dir, $parent) === 0) {
|
||||
$local = substr($dir, strlen($parent));
|
||||
if (strpos($local, $this->delim) !== false) {
|
||||
if (str_starts_with($dir, $parent)) {
|
||||
$local = substr($dir, strlen((string) $parent));
|
||||
if (str_contains($local, $this->delim)) {
|
||||
throw new Exception\RuntimeException('error while reading maildir');
|
||||
}
|
||||
array_push($stack, $parent);
|
||||
$parent = $dir . $this->delim;
|
||||
$folder = new Storage\Folder($local, substr($dir, 1), true);
|
||||
$parent = $dir . $this->delim;
|
||||
$folder = new Storage\Folder($local, substr($dir, 1), true);
|
||||
$parentFolder->$local = $folder;
|
||||
array_push($folderStack, $parentFolder);
|
||||
$parentFolder = $folder;
|
||||
break;
|
||||
} elseif ($stack) {
|
||||
$parent = array_pop($stack);
|
||||
$parent = array_pop($stack);
|
||||
$parentFolder = array_pop($folderStack);
|
||||
}
|
||||
} while ($stack);
|
||||
@@ -140,8 +164,8 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
* get root folder or given folder
|
||||
*
|
||||
* @param string $rootFolder get folder structure for given folder, else root
|
||||
* @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
|
||||
* @return \Laminas\Mail\Storage\Folder root or wanted folder
|
||||
* @throws InvalidArgumentException
|
||||
* @return Folder root or wanted folder
|
||||
*/
|
||||
public function getFolders($rootFolder = null)
|
||||
{
|
||||
@@ -150,15 +174,15 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
}
|
||||
|
||||
// rootdir is same as INBOX in maildir
|
||||
if (strpos($rootFolder, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($rootFolder, 'INBOX' . $this->delim)) {
|
||||
$rootFolder = substr($rootFolder, 6);
|
||||
}
|
||||
$currentFolder = $this->rootFolder;
|
||||
$subname = trim($rootFolder, $this->delim);
|
||||
$subname = trim($rootFolder, $this->delim);
|
||||
|
||||
while ($currentFolder) {
|
||||
if (false !== strpos($subname, $this->delim)) {
|
||||
list($entry, $subname) = explode($this->delim, $subname, 2);
|
||||
if (str_contains($subname, $this->delim)) {
|
||||
[$entry, $subname] = explode($this->delim, $subname, 2);
|
||||
} else {
|
||||
$entry = $subname;
|
||||
$subname = null;
|
||||
@@ -214,7 +238,7 @@ class Maildir extends Storage\Maildir implements FolderInterface
|
||||
/**
|
||||
* get Storage\Folder instance for current folder
|
||||
*
|
||||
* @return Storage\Folder instance of current folder
|
||||
* @return string instance of current folder
|
||||
*/
|
||||
public function getCurrentFolder()
|
||||
{
|
||||
|
||||
@@ -7,22 +7,40 @@ use Laminas\Mail\Storage\Exception;
|
||||
use Laminas\Mail\Storage\ParamsNormalizer;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_merge;
|
||||
use function closedir;
|
||||
use function explode;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function opendir;
|
||||
use function readdir;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function trim;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_WARNING;
|
||||
|
||||
class Mbox extends Storage\Mbox implements FolderInterface
|
||||
{
|
||||
/**
|
||||
* Storage\Folder root folder for folder structure
|
||||
*
|
||||
* @var Storage\Folder
|
||||
*/
|
||||
protected $rootFolder;
|
||||
|
||||
/**
|
||||
* rootdir of folder structure
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rootdir;
|
||||
|
||||
/**
|
||||
* name of current folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentFolder;
|
||||
@@ -38,7 +56,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
* - dirname rootdir of mbox structure
|
||||
* - folder initial selected folder, default is 'INBOX'
|
||||
*
|
||||
* @param $params array|object Array, iterable object, or stdClass object
|
||||
* @param array|object $params Array, iterable object, or stdClass object
|
||||
* with reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
@@ -61,7 +79,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
}
|
||||
|
||||
$this->rootdir = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$folder = $params['folder'] ?? 'INBOX';
|
||||
$folder = $params['folder'] ?? 'INBOX';
|
||||
|
||||
$this->buildFolderTree($this->rootdir);
|
||||
$this->selectFolder((string) $folder);
|
||||
@@ -84,7 +102,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
{
|
||||
if (! $parentFolder) {
|
||||
$this->rootFolder = new Storage\Folder('/', '/', false);
|
||||
$parentFolder = $this->rootFolder;
|
||||
$parentFolder = $this->rootFolder;
|
||||
}
|
||||
|
||||
ErrorHandler::start(E_WARNING);
|
||||
@@ -99,15 +117,15 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
continue;
|
||||
}
|
||||
$absoluteEntry = $currentDir . $entry;
|
||||
$globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
|
||||
$globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
|
||||
if (is_file($absoluteEntry) && $this->isMboxFile($absoluteEntry)) {
|
||||
$parentFolder->$entry = new Storage\Folder($entry, $globalName);
|
||||
continue;
|
||||
}
|
||||
if (! is_dir($absoluteEntry) /* || $entry == '.' || $entry == '..' */) {
|
||||
if (! is_dir($absoluteEntry)) { /* || $entry == '.' || $entry == '..' */
|
||||
continue;
|
||||
}
|
||||
$folder = new Storage\Folder($entry, $globalName, false);
|
||||
$folder = new Storage\Folder($entry, $globalName, false);
|
||||
$parentFolder->$entry = $folder;
|
||||
$this->buildFolderTree($absoluteEntry . DIRECTORY_SEPARATOR, $folder, $globalName);
|
||||
}
|
||||
@@ -129,10 +147,10 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
}
|
||||
|
||||
$currentFolder = $this->rootFolder;
|
||||
$subname = trim($rootFolder, DIRECTORY_SEPARATOR);
|
||||
$subname = trim($rootFolder, DIRECTORY_SEPARATOR);
|
||||
while ($currentFolder) {
|
||||
if (false !== strpos($subname, DIRECTORY_SEPARATOR)) {
|
||||
list($entry, $subname) = explode(DIRECTORY_SEPARATOR, $subname, 2);
|
||||
if (str_contains($subname, DIRECTORY_SEPARATOR)) {
|
||||
[$entry, $subname] = explode(DIRECTORY_SEPARATOR, $subname, 2);
|
||||
} else {
|
||||
$entry = $subname;
|
||||
$subname = null;
|
||||
@@ -188,7 +206,7 @@ class Mbox extends Storage\Mbox implements FolderInterface
|
||||
/**
|
||||
* get Storage\Folder instance for current folder
|
||||
*
|
||||
* @return Storage\Folder instance of current folder
|
||||
* @return string instance of current folder
|
||||
* @throws Exception\ExceptionInterface
|
||||
*/
|
||||
public function getCurrentFolder()
|
||||
|
||||
@@ -5,6 +5,20 @@ namespace Laminas\Mail\Storage;
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Protocol;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_pop;
|
||||
use function array_push;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function ksort;
|
||||
use function str_starts_with;
|
||||
use function strrpos;
|
||||
use function substr;
|
||||
|
||||
use const INF;
|
||||
use const SORT_STRING;
|
||||
|
||||
class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\WritableInterface
|
||||
{
|
||||
// TODO: with an internal cache we could optimize this class, or create an extra class with
|
||||
@@ -12,24 +26,28 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
|
||||
/**
|
||||
* protocol handler
|
||||
*
|
||||
* @var null|Protocol\Imap
|
||||
*/
|
||||
protected $protocol;
|
||||
|
||||
/**
|
||||
* name of current folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentFolder = '';
|
||||
|
||||
/**
|
||||
* IMAP folder delimiter character
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $delimiter;
|
||||
|
||||
/**
|
||||
* IMAP flags to constants translation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $knownFlags = [
|
||||
@@ -44,6 +62,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
|
||||
/**
|
||||
* IMAP flags to search criteria
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $searchFlags = [
|
||||
@@ -110,7 +129,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
|
||||
$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
|
||||
$header = $data['RFC822.HEADER'];
|
||||
|
||||
$flags = [];
|
||||
@@ -121,13 +140,12 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
return new $this->messageClass(['handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param null|array|string $part path to part or null for message header
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @return string raw header
|
||||
* @throws Exception\RuntimeException
|
||||
* @throws Protocol\Exception\RuntimeException
|
||||
@@ -143,7 +161,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
return $this->protocol->fetch('RFC822.HEADER', $id);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -331,16 +349,16 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
}
|
||||
|
||||
ksort($folders, SORT_STRING);
|
||||
$root = new Folder('/', '/', false);
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$root = new Folder('/', '/', false);
|
||||
$stack = [null];
|
||||
$folderStack = [null];
|
||||
$parentFolder = $root;
|
||||
$parent = '';
|
||||
$parent = '';
|
||||
|
||||
foreach ($folders as $globalName => $data) {
|
||||
do {
|
||||
if (! $parent || strpos($globalName, $parent) === 0) {
|
||||
$pos = strrpos($globalName, $data['delim']);
|
||||
if (! $parent || str_starts_with($globalName, ! is_string($parent) ? (string) $parent : $parent)) {
|
||||
$pos = strrpos($globalName, (string) $data['delim']);
|
||||
if ($pos === false) {
|
||||
$localName = $globalName;
|
||||
} else {
|
||||
@@ -349,15 +367,15 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
$selectable = ! $data['flags'] || ! in_array('\\Noselect', $data['flags']);
|
||||
|
||||
array_push($stack, $parent);
|
||||
$parent = $globalName . $data['delim'];
|
||||
$folder = new Folder($localName, $globalName, $selectable);
|
||||
$parent = $globalName . $data['delim'];
|
||||
$folder = new Folder($localName, $globalName, $selectable);
|
||||
$parentFolder->$localName = $folder;
|
||||
array_push($folderStack, $parentFolder);
|
||||
$parentFolder = $folder;
|
||||
$parentFolder = $folder;
|
||||
$this->delimiter = $data['delim'];
|
||||
break;
|
||||
} elseif ($stack) {
|
||||
$parent = array_pop($stack);
|
||||
$parent = array_pop($stack);
|
||||
$parentFolder = array_pop($folderStack);
|
||||
}
|
||||
} while ($stack);
|
||||
@@ -380,7 +398,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
*/
|
||||
public function selectFolder($globalName)
|
||||
{
|
||||
$this->currentFolder = $globalName;
|
||||
$this->currentFolder = (string) $globalName;
|
||||
if (! $this->protocol->select($this->currentFolder)) {
|
||||
$this->currentFolder = '';
|
||||
throw new Exception\RuntimeException('cannot change folder, maybe it does not exist');
|
||||
@@ -390,7 +408,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W
|
||||
/**
|
||||
* get Folder instance for current folder
|
||||
*
|
||||
* @return Folder instance of current folder
|
||||
* @return string instance of current folder
|
||||
*/
|
||||
public function getCurrentFolder()
|
||||
{
|
||||
|
||||
@@ -3,18 +3,50 @@
|
||||
namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Message\File;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_flip;
|
||||
use function closedir;
|
||||
use function count;
|
||||
use function ctype_digit;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function feof;
|
||||
use function fgets;
|
||||
use function file_exists;
|
||||
use function filesize;
|
||||
use function fopen;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_subclass_of;
|
||||
use function opendir;
|
||||
use function readdir;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function strcmp;
|
||||
use function stream_get_contents;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use function usort;
|
||||
|
||||
use const E_WARNING;
|
||||
|
||||
class Maildir extends AbstractStorage
|
||||
{
|
||||
/**
|
||||
* used message class, change it in an extended class to extend the returned message class
|
||||
* @var string
|
||||
*
|
||||
* @var class-string<Mail\Storage\Message\MessageInterface>
|
||||
*/
|
||||
protected $messageClass = Message\File::class;
|
||||
protected $messageClass = File::class;
|
||||
|
||||
/**
|
||||
* data of found message files in maildir dir
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $files = [];
|
||||
@@ -121,14 +153,15 @@ class Maildir extends AbstractStorage
|
||||
* Fetch a message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @return \Laminas\Mail\Storage\Message\File
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @return File
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
// TODO that's ugly, would be better to let the message class decide
|
||||
if (\trim($this->messageClass, '\\') === Message\File::class
|
||||
|| is_subclass_of($this->messageClass, Message\File::class)
|
||||
if (
|
||||
trim($this->messageClass, '\\') === File::class
|
||||
|| is_subclass_of($this->messageClass, File::class)
|
||||
) {
|
||||
return new $this->messageClass([
|
||||
'file' => $this->getFileData($id, 'filename'),
|
||||
@@ -144,7 +177,7 @@ class Maildir extends AbstractStorage
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -175,7 +208,7 @@ class Maildir extends AbstractStorage
|
||||
return $content;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -209,7 +242,7 @@ class Maildir extends AbstractStorage
|
||||
* Supported parameters are:
|
||||
* - dirname dirname of mbox file
|
||||
*
|
||||
* @param $params array|object Array, iterable object, or stdClass object
|
||||
* @param array|object $params Array, iterable object, or stdClass object
|
||||
* with reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
@@ -221,7 +254,7 @@ class Maildir extends AbstractStorage
|
||||
throw new Exception\InvalidArgumentException('no dirname provided in params');
|
||||
}
|
||||
|
||||
$dirname = (string) $params['dirname'] ;
|
||||
$dirname = (string) $params['dirname'];
|
||||
|
||||
if (! is_dir($dirname)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf('Maildir "%s" is not a directory', $dirname));
|
||||
@@ -231,7 +264,7 @@ class Maildir extends AbstractStorage
|
||||
throw new Exception\InvalidArgumentException('invalid maildir given');
|
||||
}
|
||||
|
||||
$this->has['top'] = true;
|
||||
$this->has['top'] = true;
|
||||
$this->has['flags'] = true;
|
||||
$this->openMaildir($dirname);
|
||||
}
|
||||
@@ -299,15 +332,15 @@ class Maildir extends AbstractStorage
|
||||
continue;
|
||||
}
|
||||
|
||||
if (false !== strpos($entry, ':')) {
|
||||
list($uniq, $info) = explode(':', $entry, 2);
|
||||
if (str_contains($entry, ':')) {
|
||||
[$uniq, $info] = explode(':', $entry, 2);
|
||||
} else {
|
||||
$uniq = $entry;
|
||||
$info = '';
|
||||
}
|
||||
|
||||
if (false !== strpos($uniq, ',')) {
|
||||
list(, $size) = explode(',', $uniq, 2);
|
||||
if (str_contains($uniq, ',')) {
|
||||
[, $size] = explode(',', $uniq, 2);
|
||||
} else {
|
||||
$size = '';
|
||||
}
|
||||
@@ -320,8 +353,8 @@ class Maildir extends AbstractStorage
|
||||
$size = null;
|
||||
}
|
||||
|
||||
if (false !== strpos($info, ',')) {
|
||||
list($version, $flags) = explode(',', $info, 2);
|
||||
if (str_contains($info, ',')) {
|
||||
[$version, $flags] = explode(',', $info, 2);
|
||||
} else {
|
||||
$version = $info;
|
||||
$flags = '';
|
||||
@@ -332,9 +365,9 @@ class Maildir extends AbstractStorage
|
||||
}
|
||||
|
||||
$namedFlags = $defaultFlags;
|
||||
$length = strlen($flags);
|
||||
$length = strlen($flags);
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$flag = $flags[$i];
|
||||
$flag = $flags[$i];
|
||||
$namedFlags[$flag] = static::$knownFlags[$flag] ?? $flag;
|
||||
}
|
||||
|
||||
@@ -350,15 +383,12 @@ class Maildir extends AbstractStorage
|
||||
$this->files[] = $data;
|
||||
}
|
||||
|
||||
\usort($this->files, function ($a, $b): int {
|
||||
return \strcmp($a['filename'], $b['filename']);
|
||||
});
|
||||
usort($this->files, static fn($a, $b): int => strcmp($a['filename'], $b['filename']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close resource for mail lib. If you need to control, when the resource
|
||||
* is closed. Otherwise the destructor would call this.
|
||||
*
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -378,7 +408,7 @@ class Maildir extends AbstractStorage
|
||||
/**
|
||||
* stub for not supported message deletion
|
||||
*
|
||||
* @param $id
|
||||
* @param int $id
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
|
||||
@@ -2,52 +2,81 @@
|
||||
|
||||
namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Message\File;
|
||||
use Laminas\Mail\Storage\Message\MessageInterface;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_combine;
|
||||
use function count;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function filemtime;
|
||||
use function fopen;
|
||||
use function fseek;
|
||||
use function ftell;
|
||||
use function is_dir;
|
||||
use function is_resource;
|
||||
use function is_subclass_of;
|
||||
use function range;
|
||||
use function str_starts_with;
|
||||
use function stream_get_contents;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
use const E_WARNING;
|
||||
|
||||
class Mbox extends AbstractStorage
|
||||
{
|
||||
/**
|
||||
* file handle to mbox file
|
||||
*
|
||||
* @var null|resource
|
||||
*/
|
||||
protected $fh;
|
||||
|
||||
/**
|
||||
* filename of mbox file for __wakeup
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* modification date of mbox file for __wakeup
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $filemtime;
|
||||
|
||||
/**
|
||||
* start and end position of messages as array('start' => start, 'separator' => headersep, 'end' => end)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $positions;
|
||||
|
||||
/**
|
||||
* used message class, change it in an extended class to extend the returned message class
|
||||
* @var string
|
||||
*
|
||||
* @var class-string<MessageInterface>
|
||||
*/
|
||||
protected $messageClass = Message\File::class;
|
||||
protected $messageClass = File::class;
|
||||
|
||||
/**
|
||||
* end of Line for messages
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.ValidVariableName.NotCamelCapsProperty
|
||||
protected $messageEOL;
|
||||
|
||||
/**
|
||||
* Count messages all messages in current box
|
||||
*
|
||||
* @return int number of messages
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function countMessages()
|
||||
{
|
||||
@@ -95,21 +124,23 @@ class Mbox extends AbstractStorage
|
||||
* Fetch a message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @return \Laminas\Mail\Storage\Message\File
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @return File
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
// TODO that's ugly, would be better to let the message class decide
|
||||
if (is_subclass_of($this->messageClass, Message\File::class)
|
||||
|| strtolower($this->messageClass) === strtolower(Message\File::class)) {
|
||||
if (
|
||||
is_subclass_of($this->messageClass, File::class)
|
||||
|| strtolower($this->messageClass) === strtolower(File::class)
|
||||
) {
|
||||
// TODO top/body lines
|
||||
$messagePos = $this->getPos($id);
|
||||
|
||||
$messageClassParams = [
|
||||
'file' => $this->fh,
|
||||
'file' => $this->fh,
|
||||
'startPos' => $messagePos['start'],
|
||||
'endPos' => $messagePos['end'],
|
||||
'endPos' => $messagePos['end'],
|
||||
];
|
||||
|
||||
if (isset($this->messageEOL)) {
|
||||
@@ -138,7 +169,7 @@ class Mbox extends AbstractStorage
|
||||
return new $this->messageClass(['handler' => $this, 'id' => $id, 'headers' => $message]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -146,7 +177,7 @@ class Mbox extends AbstractStorage
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @return string raw header
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawHeader($id, $part = null, $topLines = 0)
|
||||
{
|
||||
@@ -159,14 +190,14 @@ class Mbox extends AbstractStorage
|
||||
return stream_get_contents($this->fh, $messagePos['separator'] - $messagePos['start'], $messagePos['start']);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param null|array|string $part path to part or null for message content
|
||||
* @return string raw content
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawContent($id, $part = null)
|
||||
{
|
||||
@@ -183,7 +214,7 @@ class Mbox extends AbstractStorage
|
||||
* Supported parameters are:
|
||||
* - filename filename of mbox file
|
||||
*
|
||||
* @param $params array|object|Config mail reader specific parameters
|
||||
* @param array|object|Config $params mail reader specific parameters
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*/
|
||||
public function __construct($params)
|
||||
@@ -228,7 +259,7 @@ class Mbox extends AbstractStorage
|
||||
$result = false;
|
||||
|
||||
$line = fgets($file) ?: '';
|
||||
if (strpos($line, 'From ') === 0) {
|
||||
if (str_starts_with($line, 'From ')) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
@@ -260,11 +291,11 @@ class Mbox extends AbstractStorage
|
||||
|
||||
ErrorHandler::start();
|
||||
$this->fh = fopen($filename, 'r');
|
||||
$error = ErrorHandler::stop();
|
||||
$error = ErrorHandler::stop();
|
||||
if (! $this->fh) {
|
||||
throw new Exception\RuntimeException('cannot open mbox file', 0, $error);
|
||||
}
|
||||
$this->filename = $filename;
|
||||
$this->filename = $filename;
|
||||
$this->filemtime = filemtime($this->filename);
|
||||
|
||||
if (! $this->isMboxFile($this->fh, false)) {
|
||||
@@ -276,13 +307,13 @@ class Mbox extends AbstractStorage
|
||||
|
||||
$messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
|
||||
while (($line = fgets($this->fh)) !== false) {
|
||||
if (strpos($line, 'From ') === 0) {
|
||||
if (str_starts_with($line, 'From ')) {
|
||||
$messagePos['end'] = ftell($this->fh) - strlen($line) - 2; // + newline
|
||||
if (! $messagePos['separator']) {
|
||||
$messagePos['separator'] = $messagePos['end'];
|
||||
}
|
||||
$this->positions[] = $messagePos;
|
||||
$messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
|
||||
$messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
|
||||
}
|
||||
if (! $messagePos['separator'] && ! trim($line)) {
|
||||
$messagePos['separator'] = ftell($this->fh);
|
||||
@@ -299,7 +330,6 @@ class Mbox extends AbstractStorage
|
||||
/**
|
||||
* Close resource for mail lib. If you need to control, when the resource
|
||||
* is closed. Otherwise the destructor would call this.
|
||||
*
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -322,7 +352,7 @@ class Mbox extends AbstractStorage
|
||||
/**
|
||||
* stub for not supported message deletion
|
||||
*
|
||||
* @param $id
|
||||
* @param int $id message number
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
@@ -339,7 +369,7 @@ class Mbox extends AbstractStorage
|
||||
*
|
||||
* @param int|null $id message number
|
||||
* @return array|string message number for given message or all messages as array
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getUniqueId($id = null)
|
||||
{
|
||||
@@ -361,7 +391,7 @@ class Mbox extends AbstractStorage
|
||||
*
|
||||
* @param string $id unique id
|
||||
* @return int message number
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getNumberByUniqueId($id)
|
||||
{
|
||||
|
||||
@@ -4,10 +4,17 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
use function array_combine;
|
||||
use function file_get_contents;
|
||||
use function is_resource;
|
||||
use function ltrim;
|
||||
use function stream_get_contents;
|
||||
|
||||
class Message extends Part implements Message\MessageInterface
|
||||
{
|
||||
/**
|
||||
* flags for this message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $flags = [];
|
||||
@@ -28,7 +35,7 @@ class Message extends Part implements Message\MessageInterface
|
||||
if (! is_resource($params['file'])) {
|
||||
ErrorHandler::start();
|
||||
$params['raw'] = file_get_contents($params['file']);
|
||||
$error = ErrorHandler::stop();
|
||||
$error = ErrorHandler::stop();
|
||||
if ($params['raw'] === false) {
|
||||
throw new Exception\RuntimeException('could not open file', 0, $error);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
namespace Laminas\Mail\Storage\Message;
|
||||
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Part;
|
||||
|
||||
use function array_combine;
|
||||
|
||||
class File extends Part\File implements MessageInterface
|
||||
{
|
||||
/**
|
||||
* flags for this message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $flags = [];
|
||||
@@ -19,7 +23,7 @@ class File extends Part\File implements MessageInterface
|
||||
* - flags array with flags for message, keys are ignored, use constants defined in Laminas\Mail\Storage
|
||||
*
|
||||
* @param array $params
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function __construct(array $params)
|
||||
{
|
||||
|
||||
@@ -5,16 +5,22 @@ namespace Laminas\Mail\Storage;
|
||||
use Traversable;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
use function get_object_vars;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function iterator_to_array;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ParamsNormalizer
|
||||
{
|
||||
/**
|
||||
* @param mixed $params
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function normalizeParams($params): array
|
||||
public static function normalizeParams(mixed $params): array
|
||||
{
|
||||
if ($params instanceof Traversable) {
|
||||
$params = iterator_to_array($params);
|
||||
|
||||
@@ -2,58 +2,81 @@
|
||||
|
||||
namespace Laminas\Mail\Storage;
|
||||
|
||||
use ArrayIterator;
|
||||
use Laminas\Mail\Header\HeaderInterface;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mime;
|
||||
use Laminas\Mime\Exception\RuntimeException;
|
||||
use RecursiveIterator;
|
||||
use ReturnTypeWillChange;
|
||||
use Stringable;
|
||||
|
||||
class Part implements RecursiveIterator, Part\PartInterface
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function current;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function iterator_to_array;
|
||||
use function preg_replace;
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
class Part implements RecursiveIterator, Part\PartInterface, Stringable
|
||||
{
|
||||
/**
|
||||
* Headers of the part
|
||||
*
|
||||
* @var Headers|null
|
||||
*/
|
||||
protected $headers;
|
||||
|
||||
/**
|
||||
* raw part body
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* toplines as fetched with headers
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $topLines = '';
|
||||
|
||||
/**
|
||||
* parts of multipart message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parts = [];
|
||||
|
||||
/**
|
||||
* count of parts of a multipart message
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
protected $countParts;
|
||||
|
||||
/**
|
||||
* current position of iterator
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $iterationPos = 1;
|
||||
|
||||
/**
|
||||
* mail handler, if late fetch is active
|
||||
*
|
||||
* @var null|AbstractStorage
|
||||
*/
|
||||
protected $mail;
|
||||
|
||||
/**
|
||||
* message number for mail handler
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $messageNum = 0;
|
||||
@@ -87,7 +110,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
$this->messageNum = $params['id'];
|
||||
}
|
||||
|
||||
$params['strict'] = $params['strict'] ?? false;
|
||||
$params['strict'] ??= false;
|
||||
|
||||
if (isset($params['raw'])) {
|
||||
Mime\Decode::splitMessage(
|
||||
@@ -124,7 +147,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
{
|
||||
try {
|
||||
return stripos($this->contentType, 'multipart/') === 0;
|
||||
} catch (Exception\ExceptionInterface $e) {
|
||||
} catch (Exception\ExceptionInterface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -211,10 +234,10 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
throw new Exception\RuntimeException('part not found');
|
||||
}
|
||||
|
||||
if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// TODO: fetch part
|
||||
// return
|
||||
}
|
||||
// }
|
||||
|
||||
$this->cacheContent();
|
||||
|
||||
@@ -241,10 +264,10 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
return $this->countParts;
|
||||
}
|
||||
|
||||
if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// if ($this->mail && $this->mail->hasFetchPart) {
|
||||
// TODO: fetch part
|
||||
// return
|
||||
}
|
||||
// }
|
||||
|
||||
$this->cacheContent();
|
||||
|
||||
@@ -264,7 +287,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
{
|
||||
if (null === $this->headers) {
|
||||
if ($this->mail) {
|
||||
$part = $this->mail->getRawHeader($this->messageNum);
|
||||
$part = $this->mail->getRawHeader($this->messageNum);
|
||||
$this->headers = Headers::fromString($part);
|
||||
} else {
|
||||
$this->headers = new Headers();
|
||||
@@ -288,14 +311,14 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
* @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes
|
||||
* @param string $format change type of return value to 'string' or 'array'
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return string|array|HeaderInterface|\ArrayIterator value of header in wanted or internal format
|
||||
* @return string|array|HeaderInterface|ArrayIterator value of header in wanted or internal format
|
||||
*/
|
||||
public function getHeader($name, $format = null)
|
||||
{
|
||||
$header = $this->getHeaders()->get($name);
|
||||
if ($header === false) {
|
||||
$lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
|
||||
$header = $this->getHeaders()->get($lowerName);
|
||||
$header = $this->getHeaders()->get($lowerName);
|
||||
if ($header === false) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
"Header with Name $name or $lowerName not found"
|
||||
@@ -310,9 +333,8 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
} else {
|
||||
$return = trim(implode(
|
||||
Mime\Mime::LINEEND,
|
||||
array_map(static function ($header): string {
|
||||
return $header->getFieldValue(HeaderInterface::FORMAT_RAW);
|
||||
}, iterator_to_array($header))
|
||||
array_map(static fn($header): string
|
||||
=> $header->getFieldValue(HeaderInterface::FORMAT_RAW), iterator_to_array($header))
|
||||
), Mime\Mime::LINEEND);
|
||||
}
|
||||
break;
|
||||
@@ -346,7 +368,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
* @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned
|
||||
* @param string $firstName key name for the first part
|
||||
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
|
||||
* @throws \Laminas\Mime\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getHeaderField($name, $wantedPart = '0', $firstName = '0')
|
||||
{
|
||||
@@ -376,7 +398,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
*
|
||||
* @see Part::hasHeader
|
||||
*
|
||||
* @param string
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
@@ -389,7 +411,7 @@ class Part implements RecursiveIterator, Part\PartInterface
|
||||
*
|
||||
* @return string content
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,26 @@ namespace Laminas\Mail\Storage\Part;
|
||||
use Laminas\Mail\Headers;
|
||||
use Laminas\Mail\Storage\Part;
|
||||
|
||||
use function count;
|
||||
use function feof;
|
||||
use function fgets;
|
||||
use function fopen;
|
||||
use function fread;
|
||||
use function fseek;
|
||||
use function ftell;
|
||||
use function is_resource;
|
||||
use function stream_copy_to_stream;
|
||||
use function trim;
|
||||
|
||||
use const SEEK_END;
|
||||
|
||||
class File extends Part
|
||||
{
|
||||
/** @var array */
|
||||
protected $contentPos = [];
|
||||
/** @var array */
|
||||
protected $partPos = [];
|
||||
/** @var resource */
|
||||
protected $fh;
|
||||
|
||||
/**
|
||||
@@ -31,13 +47,14 @@ class File extends Part
|
||||
}
|
||||
|
||||
if (! is_resource($params['file'])) {
|
||||
$this->fh = fopen($params['file'], 'r');
|
||||
$fh = fopen($params['file'], 'r');
|
||||
} else {
|
||||
$this->fh = $params['file'];
|
||||
$fh = $params['file'];
|
||||
}
|
||||
if (! $this->fh) {
|
||||
if (! $fh) {
|
||||
throw new Exception\RuntimeException('could not open file');
|
||||
}
|
||||
$this->fh = $fh;
|
||||
if (isset($params['startPos'])) {
|
||||
fseek($this->fh, $params['startPos']);
|
||||
}
|
||||
@@ -70,7 +87,7 @@ class File extends Part
|
||||
}
|
||||
|
||||
$part = [];
|
||||
$pos = $this->contentPos[0];
|
||||
$pos = $this->contentPos[0];
|
||||
fseek($this->fh, $pos);
|
||||
while (! feof($this->fh) && ($endPos === null || $pos < $endPos)) {
|
||||
$line = fgets($this->fh);
|
||||
@@ -82,18 +99,18 @@ class File extends Part
|
||||
}
|
||||
|
||||
$lastPos = $pos;
|
||||
$pos = ftell($this->fh);
|
||||
$line = trim($line);
|
||||
$pos = ftell($this->fh);
|
||||
$line = trim($line);
|
||||
|
||||
if ($line == '--' . $boundary) {
|
||||
if ($part) {
|
||||
// not first part
|
||||
$part[1] = $lastPos;
|
||||
$part[1] = $lastPos;
|
||||
$this->partPos[] = $part;
|
||||
}
|
||||
$part = [$pos];
|
||||
} elseif ($line == '--' . $boundary . '--') {
|
||||
$part[1] = $lastPos;
|
||||
$part[1] = $lastPos;
|
||||
$this->partPos[] = $part;
|
||||
break;
|
||||
}
|
||||
@@ -146,9 +163,9 @@ class File extends Part
|
||||
}
|
||||
|
||||
return new static([
|
||||
'file' => $this->fh,
|
||||
'file' => $this->fh,
|
||||
'startPos' => $this->partPos[$num][0],
|
||||
'endPos' => $this->partPos[$num][1],
|
||||
'endPos' => $this->partPos[$num][1],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ interface PartInterface extends RecursiveIterator
|
||||
* This getter is short for PartInterface::getHeader($name, 'string')
|
||||
*
|
||||
* @see PartInterface::getHeader()
|
||||
*
|
||||
* @param string $name header name
|
||||
* @return string value of header
|
||||
* @throws Exception\ExceptionInterface
|
||||
|
||||
@@ -4,12 +4,23 @@ namespace Laminas\Mail\Storage;
|
||||
|
||||
use Laminas\Mail\Exception as MailException;
|
||||
use Laminas\Mail\Protocol;
|
||||
use Laminas\Mail\Protocol\Exception\RuntimeException;
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Storage\Message;
|
||||
use Laminas\Mime;
|
||||
|
||||
use function array_combine;
|
||||
use function array_key_exists;
|
||||
use function is_string;
|
||||
use function range;
|
||||
use function strtolower;
|
||||
|
||||
class Pop3 extends AbstractStorage
|
||||
{
|
||||
/**
|
||||
* protocol handler
|
||||
*
|
||||
* @var null|\Laminas\Mail\Protocol\Pop3
|
||||
*/
|
||||
protected $protocol;
|
||||
@@ -18,7 +29,7 @@ class Pop3 extends AbstractStorage
|
||||
* Count messages all messages in current box
|
||||
*
|
||||
* @return int number of messages
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
*/
|
||||
public function countMessages()
|
||||
@@ -38,7 +49,7 @@ class Pop3 extends AbstractStorage
|
||||
*/
|
||||
public function getSize($id = 0)
|
||||
{
|
||||
$id = $id ? $id : null;
|
||||
$id = $id ?: null;
|
||||
return $this->protocol->getList($id);
|
||||
}
|
||||
|
||||
@@ -46,23 +57,23 @@ class Pop3 extends AbstractStorage
|
||||
* Fetch a message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @return \Laminas\Mail\Storage\Message
|
||||
* @return Message
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
*/
|
||||
public function getMessage($id)
|
||||
{
|
||||
$bodyLines = 0;
|
||||
$message = $this->protocol->top($id, $bodyLines, true);
|
||||
$message = $this->protocol->top($id, $bodyLines, true);
|
||||
|
||||
return new $this->messageClass([
|
||||
'handler' => $this,
|
||||
'id' => $id,
|
||||
'headers' => $message,
|
||||
'handler' => $this,
|
||||
'id' => $id,
|
||||
'headers' => $message,
|
||||
'noToplines' => $bodyLines < 1,
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw header of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
@@ -70,7 +81,7 @@ class Pop3 extends AbstractStorage
|
||||
* @param int $topLines include this many lines with header (after an empty line)
|
||||
* @return string raw header
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawHeader($id, $part = null, $topLines = 0)
|
||||
{
|
||||
@@ -82,14 +93,14 @@ class Pop3 extends AbstractStorage
|
||||
return $this->protocol->top($id, 0, true);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get raw content of message or part
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param null|array|string $part path to part or null for message content
|
||||
* @return string raw content
|
||||
* @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getRawContent($id, $part = null)
|
||||
{
|
||||
@@ -117,8 +128,8 @@ class Pop3 extends AbstractStorage
|
||||
*
|
||||
* @param array|object|Protocol\Pop3 $params mail reader specific
|
||||
* parameters or configured Pop3 protocol object
|
||||
* @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
|
||||
* @throws \Laminas\Mail\Protocol\Exception\RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
@@ -134,7 +145,7 @@ class Pop3 extends AbstractStorage
|
||||
$params = ParamsNormalizer::normalizeParams($params);
|
||||
|
||||
if (! isset($params['user'])) {
|
||||
throw new Exception\InvalidArgumentException('need at least user in params');
|
||||
throw new InvalidArgumentException('need at least user in params');
|
||||
}
|
||||
|
||||
$host = $params['host'] ?? 'localhost';
|
||||
@@ -172,7 +183,7 @@ class Pop3 extends AbstractStorage
|
||||
/**
|
||||
* Keep the server busy.
|
||||
*
|
||||
* @throws \Laminas\Mail\Protocol\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function noop()
|
||||
{
|
||||
@@ -185,7 +196,7 @@ class Pop3 extends AbstractStorage
|
||||
* identify the message.
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @throws \Laminas\Mail\Protocol\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
{
|
||||
@@ -199,7 +210,7 @@ class Pop3 extends AbstractStorage
|
||||
*
|
||||
* @param int|null $id message number
|
||||
* @return array|string message number for given message or all messages as array
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function getUniqueId($id = null)
|
||||
{
|
||||
@@ -225,7 +236,7 @@ class Pop3 extends AbstractStorage
|
||||
* as parameter and use this method to translate it to message number right before calling removeMessage()
|
||||
*
|
||||
* @param string $id unique id
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return int message number
|
||||
*/
|
||||
public function getNumberByUniqueId($id)
|
||||
@@ -241,7 +252,7 @@ class Pop3 extends AbstractStorage
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception\InvalidArgumentException('unique id not found');
|
||||
throw new InvalidArgumentException('unique id not found');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,8 +260,9 @@ class Pop3 extends AbstractStorage
|
||||
* retrieved if Top wasn't needed/tried yet.
|
||||
*
|
||||
* @see AbstractStorage::__get()
|
||||
*
|
||||
* @param string $var
|
||||
* @return string
|
||||
* @return null|string
|
||||
*/
|
||||
public function __get($var)
|
||||
{
|
||||
@@ -264,7 +276,7 @@ class Pop3 extends AbstractStorage
|
||||
// need to make a real call, because not all server are honest in their capas
|
||||
try {
|
||||
$this->protocol->top(1, 0, false);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// ignoring error
|
||||
}
|
||||
}
|
||||
@@ -276,7 +288,7 @@ class Pop3 extends AbstractStorage
|
||||
$id = null;
|
||||
try {
|
||||
$id = $this->protocol->uniqueid(1);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// ignoring error
|
||||
}
|
||||
$this->has['uniqueid'] = (bool) $id;
|
||||
|
||||
@@ -5,10 +5,64 @@ namespace Laminas\Mail\Storage\Writable;
|
||||
use Laminas\Mail\Exception as MailException;
|
||||
use Laminas\Mail\Storage;
|
||||
use Laminas\Mail\Storage\Exception as StorageException;
|
||||
use Laminas\Mail\Storage\Exception\ExceptionInterface;
|
||||
use Laminas\Mail\Storage\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Storage\Exception\RuntimeException;
|
||||
use Laminas\Mail\Storage\Folder;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
use function array_flip;
|
||||
use function array_keys;
|
||||
use function array_search;
|
||||
use function array_values;
|
||||
use function closedir;
|
||||
use function copy;
|
||||
use function dirname;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function fgets;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function filesize;
|
||||
use function fopen;
|
||||
use function fread;
|
||||
use function fwrite;
|
||||
use function get_resource_type;
|
||||
use function getmypid;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_numeric;
|
||||
use function is_resource;
|
||||
use function link;
|
||||
use function microtime;
|
||||
use function mkdir;
|
||||
use function opendir;
|
||||
use function php_uname;
|
||||
use function readdir;
|
||||
use function rename;
|
||||
use function rmdir;
|
||||
use function rtrim;
|
||||
use function sleep;
|
||||
use function str_contains;
|
||||
use function str_starts_with;
|
||||
use function stream_copy_to_stream;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strrpos;
|
||||
use function strtok;
|
||||
use function substr;
|
||||
use function time;
|
||||
use function trim;
|
||||
use function unlink;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_WARNING;
|
||||
use const FILE_APPEND;
|
||||
|
||||
class Maildir extends Folder\Maildir implements WritableInterface
|
||||
{
|
||||
// TODO: init maildir (+ constructor option create if not found)
|
||||
@@ -26,8 +80,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* If the given dir is already a valid maildir this will not fail.
|
||||
*
|
||||
* @param string $dir directory for the new maildir (may already exist)
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function initMaildir($dir)
|
||||
{
|
||||
@@ -69,8 +123,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* Additional parameters are (see parent for more):
|
||||
* - create if true a new maildir is create if none exists
|
||||
*
|
||||
* @param $params array mail reader specific parameters
|
||||
* @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
|
||||
* @param array|object $params mail reader specific parameters
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
@@ -78,7 +132,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$params = (object) $params;
|
||||
}
|
||||
|
||||
if (! empty($params->create)
|
||||
if (
|
||||
! empty($params->create)
|
||||
&& isset($params->dirname)
|
||||
&& ! file_exists($params->dirname . DIRECTORY_SEPARATOR . 'cur')
|
||||
) {
|
||||
@@ -95,8 +150,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* may be used as parent or which chars may be used in the folder name
|
||||
*
|
||||
* @param string $name global name of folder, local name if $parentFolder is set
|
||||
* @param string|\Laminas\Mail\Storage\Folder $parentFolder parent of new folder, else root folder is parent
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param string|Folder $parentFolder parent of new folder, else root folder is parent
|
||||
* @throws RuntimeException
|
||||
* @return string only used internally (new created maildir)
|
||||
*/
|
||||
public function createFolder($name, $parentFolder = null)
|
||||
@@ -115,25 +170,26 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$exists = null;
|
||||
try {
|
||||
$exists = $this->getFolders($folder);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// ok
|
||||
}
|
||||
if ($exists) {
|
||||
throw new StorageException\RuntimeException('folder already exists');
|
||||
}
|
||||
|
||||
if (strpos($folder, $this->delim . $this->delim) !== false) {
|
||||
if (str_contains($folder, $this->delim . $this->delim)) {
|
||||
throw new StorageException\RuntimeException('invalid name - folder parts may not be empty');
|
||||
}
|
||||
|
||||
if (strpos($folder, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($folder, 'INBOX' . $this->delim)) {
|
||||
$folder = substr($folder, 6);
|
||||
}
|
||||
|
||||
$fulldir = $this->rootdir . '.' . $folder;
|
||||
|
||||
// check if we got tricked and would create a dir outside of the rootdir or not as direct child
|
||||
if (strpos($folder, DIRECTORY_SEPARATOR) !== false || strpos($folder, '/') !== false
|
||||
if (
|
||||
str_contains($folder, DIRECTORY_SEPARATOR) || str_contains($folder, '/')
|
||||
|| dirname($fulldir) . DIRECTORY_SEPARATOR != $this->rootdir
|
||||
) {
|
||||
throw new StorageException\RuntimeException('invalid name - no directory separator allowed in folder name');
|
||||
@@ -146,7 +202,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$parent = substr($folder, 0, strrpos($folder, $this->delim));
|
||||
try {
|
||||
$this->getFolders($parent);
|
||||
} catch (MailException\ExceptionInterface $e) {
|
||||
} catch (MailException\ExceptionInterface) {
|
||||
// does not - create parent folder
|
||||
$this->createFolder($parent);
|
||||
}
|
||||
@@ -176,7 +232,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* remove a folder
|
||||
*
|
||||
* @param string|Folder $name name or instance of folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function removeFolder($name)
|
||||
{
|
||||
@@ -191,7 +247,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
$name = trim($name, $this->delim);
|
||||
if (strpos($name, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($name, 'INBOX' . $this->delim)) {
|
||||
$name = substr($name, 6);
|
||||
}
|
||||
|
||||
@@ -249,9 +305,9 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
*
|
||||
* The new name has the same restrictions as in createFolder()
|
||||
*
|
||||
* @param string|\Laminas\Mail\Storage\Folder $oldName name or instance of folder
|
||||
* @param string|Folder $oldName name or instance of folder
|
||||
* @param string $newName new global name of folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function renameFolder($oldName, $newName)
|
||||
{
|
||||
@@ -262,16 +318,16 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
$oldName = trim($oldName, $this->delim);
|
||||
if (strpos($oldName, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($oldName, 'INBOX' . $this->delim)) {
|
||||
$oldName = substr($oldName, 6);
|
||||
}
|
||||
|
||||
$newName = trim($newName, $this->delim);
|
||||
if (strpos($newName, 'INBOX' . $this->delim) === 0) {
|
||||
if (str_starts_with($newName, 'INBOX' . $this->delim)) {
|
||||
$newName = substr($newName, 6);
|
||||
}
|
||||
|
||||
if (strpos($newName, $oldName . $this->delim) === 0) {
|
||||
if (str_starts_with($newName, $oldName . $this->delim)) {
|
||||
throw new StorageException\RuntimeException('new folder cannot be a child of old folder');
|
||||
}
|
||||
|
||||
@@ -325,7 +381,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
*/
|
||||
protected function createUniqueId()
|
||||
{
|
||||
$id = '';
|
||||
$id = '';
|
||||
$id .= microtime(true);
|
||||
$id .= '.' . getmypid();
|
||||
$id .= '.' . php_uname('n');
|
||||
@@ -340,7 +396,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* you should close the returned filehandle!
|
||||
*
|
||||
* @param string $folder name of current folder without leading .
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
* @return array array('dirname' => dir of maildir folder, 'uniq' => unique id, 'filename' => name of create file
|
||||
* 'handle' => file opened for writing)
|
||||
*/
|
||||
@@ -385,10 +441,10 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
return [
|
||||
'dirname' => $this->rootdir . '.' . $folder,
|
||||
'uniq' => $uniq,
|
||||
'dirname' => $this->rootdir . '.' . $folder,
|
||||
'uniq' => $uniq,
|
||||
'filename' => $tmpdir . $uniq,
|
||||
'handle' => $fh,
|
||||
'handle' => $fh,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -414,7 +470,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
if (! isset($wantedFlags[$flag])) {
|
||||
continue;
|
||||
}
|
||||
$info .= $char;
|
||||
$info .= $char;
|
||||
$flags[$char] = $flag;
|
||||
unset($wantedFlags[$flag]);
|
||||
}
|
||||
@@ -449,7 +505,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$folder = $this->currentFolder;
|
||||
}
|
||||
|
||||
if (! ($folder instanceof Folder)) {
|
||||
if (! $folder instanceof Folder) {
|
||||
$folder = $this->getFolders($folder);
|
||||
}
|
||||
|
||||
@@ -472,7 +528,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
if ($size !== false) {
|
||||
$info = ',S=' . $size . $info;
|
||||
}
|
||||
$newFilename = $tempFile['dirname'] . DIRECTORY_SEPARATOR;
|
||||
$newFilename = $tempFile['dirname'] . DIRECTORY_SEPARATOR;
|
||||
$newFilename .= $recent ? 'new' : 'cur';
|
||||
$newFilename .= DIRECTORY_SEPARATOR . $tempFile['uniq'] . $info;
|
||||
|
||||
@@ -492,8 +548,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
$this->files[] = [
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'filename' => $newFilename,
|
||||
];
|
||||
if ($this->quota) {
|
||||
@@ -505,8 +561,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* copy an existing message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param string|\Laminas\Mail\Storage\Folder $folder name or instance of targer folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param string|Folder $folder name or instance of targer folder
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function copyMessage($id, $folder)
|
||||
{
|
||||
@@ -514,7 +570,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
throw new StorageException\RuntimeException('storage is over quota!');
|
||||
}
|
||||
|
||||
if (! ($folder instanceof Folder)) {
|
||||
if (! $folder instanceof Folder) {
|
||||
$folder = $this->getFolders($folder);
|
||||
}
|
||||
|
||||
@@ -558,12 +614,13 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if ($folder->getGlobalName() == $this->currentFolder
|
||||
if (
|
||||
$folder->getGlobalName() == $this->currentFolder
|
||||
|| ($this->currentFolder == 'INBOX' && $folder->getGlobalName() == '/')
|
||||
) {
|
||||
$this->files[] = [
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'uniq' => $tempFile['uniq'],
|
||||
'flags' => $flags,
|
||||
'filename' => $newFile,
|
||||
];
|
||||
}
|
||||
@@ -577,16 +634,17 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* move an existing message
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param string|\Laminas\Mail\Storage\Folder $folder name or instance of targer folder
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param string|Folder $folder name or instance of targer folder
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function moveMessage($id, $folder)
|
||||
{
|
||||
if (! ($folder instanceof Folder)) {
|
||||
if (! $folder instanceof Folder) {
|
||||
$folder = $this->getFolders($folder);
|
||||
}
|
||||
|
||||
if ($folder->getGlobalName() == $this->currentFolder
|
||||
if (
|
||||
$folder->getGlobalName() == $this->currentFolder
|
||||
|| ($this->currentFolder == 'INBOX' && $folder->getGlobalName() == '/')
|
||||
) {
|
||||
throw new StorageException\RuntimeException('target is current folder');
|
||||
@@ -641,7 +699,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
*
|
||||
* @param int $id number of message
|
||||
* @param array $flags new flags for message
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function setFlags($id, $flags)
|
||||
{
|
||||
@@ -672,8 +730,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
/**
|
||||
* stub for not supported message deletion
|
||||
*
|
||||
* @param $id
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @param int $id
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function removeMessage($id)
|
||||
{
|
||||
@@ -716,8 +774,9 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* get currently set quota
|
||||
*
|
||||
* @see \Laminas\Mail\Storage\Writable\Maildir::setQuota()
|
||||
*
|
||||
* @param bool $fromStorage
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
* @return bool|array
|
||||
*/
|
||||
public function getQuota($fromStorage = false)
|
||||
@@ -748,7 +807,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
|
||||
/**
|
||||
* @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating maildirsize"
|
||||
* @throws \Laminas\Mail\Storage\Exception\RuntimeException
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @return array
|
||||
*/
|
||||
protected function calculateMaildirsize()
|
||||
@@ -842,7 +902,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
return [
|
||||
'size' => $totalSize,
|
||||
'size' => $totalSize,
|
||||
'count' => $messages,
|
||||
'quota' => $quota,
|
||||
];
|
||||
@@ -850,6 +910,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
|
||||
/**
|
||||
* @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating the quota for a Maildir++"
|
||||
*
|
||||
* @param bool $forceRecalc
|
||||
* @return array
|
||||
*/
|
||||
@@ -859,7 +920,8 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
$totalSize = 0;
|
||||
$messages = 0;
|
||||
$maildirsize = '';
|
||||
if (! $forceRecalc
|
||||
if (
|
||||
! $forceRecalc
|
||||
&& file_exists($this->rootdir . 'maildirsize')
|
||||
&& filesize($this->rootdir . 'maildirsize') < 5120
|
||||
) {
|
||||
@@ -874,10 +936,10 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
}
|
||||
if (! $fh) {
|
||||
$result = $this->calculateMaildirsize();
|
||||
$result = $this->calculateMaildirsize();
|
||||
$totalSize = $result['size'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
} else {
|
||||
$maildirsize = explode("\n", $maildirsize);
|
||||
if (is_array($this->quota)) {
|
||||
@@ -895,9 +957,9 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
unset($maildirsize[0]);
|
||||
foreach ($maildirsize as $line) {
|
||||
list($size, $count) = explode(' ', trim($line));
|
||||
$totalSize += $size;
|
||||
$messages += $count;
|
||||
[$size, $count] = explode(' ', trim($line));
|
||||
$totalSize += $size;
|
||||
$messages += $count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,10 +971,10 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
// Also we're using local time to calculate the 15 minute offset. Touching a file just for known the
|
||||
// local time of the file storage isn't worth the hassle.
|
||||
if ($overQuota && ($maildirsize || filemtime($this->rootdir . 'maildirsize') > time() - 900)) {
|
||||
$result = $this->calculateMaildirsize();
|
||||
$totalSize = $result['size'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
$result = $this->calculateMaildirsize();
|
||||
$totalSize = $result['size'];
|
||||
$messages = $result['count'];
|
||||
$quota = $result['quota'];
|
||||
$overQuota = false;
|
||||
$overQuota = $overQuota || (isset($quota['size']) && $totalSize > $quota['size']);
|
||||
$overQuota = $overQuota || (isset($quota['count']) && $messages > $quota['count']);
|
||||
@@ -924,20 +986,23 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
}
|
||||
|
||||
return [
|
||||
'size' => $totalSize,
|
||||
'count' => $messages,
|
||||
'quota' => $quota,
|
||||
'size' => $totalSize,
|
||||
'count' => $messages,
|
||||
'quota' => $quota,
|
||||
'over_quota' => $overQuota,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
* @param int $count
|
||||
* @return void
|
||||
*/
|
||||
protected function addQuotaEntry($size, $count = 1)
|
||||
{
|
||||
if (! file_exists($this->rootdir . 'maildirsize')) {
|
||||
// if (! file_exists($this->rootdir . 'maildirsize')) {
|
||||
// TODO: should get file handler from calculateQuota
|
||||
}
|
||||
$size = (int) $size;
|
||||
$count = (int) $count;
|
||||
// }
|
||||
file_put_contents($this->rootdir . 'maildirsize', "$size $count\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
@@ -945,6 +1010,7 @@ class Maildir extends Folder\Maildir implements WritableInterface
|
||||
* check if storage is currently over quota
|
||||
*
|
||||
* @see calculateQuota()
|
||||
*
|
||||
* @param bool $detailedResponse return known data of quota and current size and message count
|
||||
* @param bool $forceRecalc
|
||||
* @return bool|array over quota state or detailed response
|
||||
|
||||
@@ -6,14 +6,10 @@ use Laminas\Stdlib\AbstractOptions;
|
||||
|
||||
class Envelope extends AbstractOptions
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
protected $from;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
protected $to;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,18 +5,24 @@ namespace Laminas\Mail\Transport;
|
||||
use Laminas\Stdlib\ArrayUtils;
|
||||
use Traversable;
|
||||
|
||||
use function class_exists;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
// phpcs:ignore WebimpressCodingStandard.NamingConventions.AbstractClass.Prefix
|
||||
abstract class Factory
|
||||
{
|
||||
/**
|
||||
* @var array Known transport types
|
||||
*/
|
||||
/** @var array Known transport types */
|
||||
protected static $classMap = [
|
||||
'file' => File::class,
|
||||
'inmemory' => InMemory::class,
|
||||
'memory' => InMemory::class,
|
||||
'null' => InMemory::class,
|
||||
'sendmail' => Sendmail::class,
|
||||
'smtp' => Smtp::class,
|
||||
'file' => File::class,
|
||||
'inmemory' => InMemory::class,
|
||||
'memory' => InMemory::class,
|
||||
'null' => InMemory::class,
|
||||
'sendmail' => Sendmail::class,
|
||||
'smtp' => Smtp::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -35,7 +41,7 @@ abstract class Factory
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects an array or Traversable argument; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($spec) ? get_class($spec) : gettype($spec))
|
||||
is_object($spec) ? $spec::class : gettype($spec)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ namespace Laminas\Mail\Transport;
|
||||
|
||||
use Laminas\Mail\Message;
|
||||
|
||||
use function file_put_contents;
|
||||
use function sprintf;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* File transport
|
||||
*
|
||||
@@ -11,9 +16,7 @@ use Laminas\Mail\Message;
|
||||
*/
|
||||
class File implements TransportInterface
|
||||
{
|
||||
/**
|
||||
* @var FileOptions
|
||||
*/
|
||||
/** @var FileOptions */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
@@ -28,7 +31,7 @@ class File implements TransportInterface
|
||||
*
|
||||
* @param null|FileOptions $options OPTIONAL (Default: null)
|
||||
*/
|
||||
public function __construct(FileOptions $options = null)
|
||||
public function __construct(?FileOptions $options = null)
|
||||
{
|
||||
if (! $options instanceof FileOptions) {
|
||||
$options = new FileOptions();
|
||||
@@ -46,8 +49,6 @@ class File implements TransportInterface
|
||||
|
||||
/**
|
||||
* Sets options
|
||||
*
|
||||
* @param FileOptions $options
|
||||
*/
|
||||
public function setOptions(FileOptions $options)
|
||||
{
|
||||
@@ -57,9 +58,7 @@ class File implements TransportInterface
|
||||
/**
|
||||
* Saves e-mail message to a file
|
||||
*
|
||||
* @param Message $message
|
||||
* @throws Exception\RuntimeException on not writable target directory or
|
||||
* on file_put_contents() failure
|
||||
* @throws Exception\RuntimeException On not writable target directory or on file_put_contents() failure.
|
||||
*/
|
||||
public function send(Message $message)
|
||||
{
|
||||
|
||||
@@ -3,25 +3,32 @@
|
||||
namespace Laminas\Mail\Transport;
|
||||
|
||||
use Laminas\Mail\Exception;
|
||||
use Laminas\Mail\Exception\InvalidArgumentException;
|
||||
use Laminas\Stdlib\AbstractOptions;
|
||||
|
||||
use function gettype;
|
||||
use function is_callable;
|
||||
use function is_dir;
|
||||
use function is_object;
|
||||
use function is_writable;
|
||||
use function mt_rand;
|
||||
use function sprintf;
|
||||
use function sys_get_temp_dir;
|
||||
use function time;
|
||||
|
||||
class FileOptions extends AbstractOptions
|
||||
{
|
||||
/**
|
||||
* @var string Path to stored mail files
|
||||
*/
|
||||
/** @var string Path to stored mail files */
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
/** @var callable */
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* Set path to stored mail files
|
||||
*
|
||||
* @param string $path
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return FileOptions
|
||||
*/
|
||||
public function setPath($path)
|
||||
@@ -56,7 +63,7 @@ class FileOptions extends AbstractOptions
|
||||
* Set callback used to generate a file name
|
||||
*
|
||||
* @param callable $callback
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return FileOptions
|
||||
*/
|
||||
public function setCallback($callback)
|
||||
@@ -65,7 +72,7 @@ class FileOptions extends AbstractOptions
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'%s expects a valid callback; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($callback) ? get_class($callback) : gettype($callback))
|
||||
is_object($callback) ? $callback::class : gettype($callback)
|
||||
));
|
||||
}
|
||||
$this->callback = $callback;
|
||||
@@ -80,9 +87,7 @@ class FileOptions extends AbstractOptions
|
||||
public function getCallback()
|
||||
{
|
||||
if (null === $this->callback) {
|
||||
$this->setCallback(function () {
|
||||
return 'LaminasMail_' . time() . '_' . mt_rand() . '.eml';
|
||||
});
|
||||
$this->setCallback(static fn() => 'LaminasMail_' . time() . '_' . mt_rand() . '.eml');
|
||||
}
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,11 @@ use Laminas\Mail\Message;
|
||||
*/
|
||||
class InMemory implements TransportInterface
|
||||
{
|
||||
/**
|
||||
* @var null|Message
|
||||
*/
|
||||
/** @var null|Message */
|
||||
protected $lastMessage;
|
||||
|
||||
/**
|
||||
* Takes the last message and saves it for testing.
|
||||
*
|
||||
* @param Message $message
|
||||
*/
|
||||
public function send(Message $message)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,32 @@ namespace Laminas\Mail\Transport;
|
||||
use Laminas\Mail;
|
||||
use Laminas\Mail\Address\AddressInterface;
|
||||
use Laminas\Mail\Header\HeaderInterface;
|
||||
use Laminas\Mail\Transport\Exception\InvalidArgumentException;
|
||||
use Laminas\Mail\Transport\Exception\RuntimeException;
|
||||
use Traversable;
|
||||
|
||||
use function count;
|
||||
use function escapeshellarg;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function mail;
|
||||
use function preg_match;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
use const PHP_OS;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* Class for sending email via the PHP internal mail() function
|
||||
*/
|
||||
@@ -28,18 +52,15 @@ class Sendmail implements TransportInterface
|
||||
|
||||
/**
|
||||
* error information
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $errstr;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $operatingSystem;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param null|string|array|Traversable $parameters OPTIONAL (Default: null)
|
||||
*/
|
||||
public function __construct($parameters = null)
|
||||
@@ -56,7 +77,7 @@ class Sendmail implements TransportInterface
|
||||
* Used to populate the additional_parameters argument to mail()
|
||||
*
|
||||
* @param null|string|array|Traversable $parameters
|
||||
* @throws \Laminas\Mail\Transport\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return Sendmail
|
||||
*/
|
||||
public function setParameters($parameters)
|
||||
@@ -67,10 +88,10 @@ class Sendmail implements TransportInterface
|
||||
}
|
||||
|
||||
if (! is_array($parameters) && ! $parameters instanceof Traversable) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string, array, or Traversable object of parameters; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($parameters) ? get_class($parameters) : gettype($parameters))
|
||||
is_object($parameters) ? $parameters::class : gettype($parameters)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -89,16 +110,16 @@ class Sendmail implements TransportInterface
|
||||
* Primarily for testing purposes, but could be used to curry arguments.
|
||||
*
|
||||
* @param callable $callable
|
||||
* @throws \Laminas\Mail\Transport\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return Sendmail
|
||||
*/
|
||||
public function setCallable($callable)
|
||||
{
|
||||
if (! is_callable($callable)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a callable argument; received "%s"',
|
||||
__METHOD__,
|
||||
(is_object($callable) ? get_class($callable) : gettype($callable))
|
||||
is_object($callable) ? $callable::class : gettype($callable)
|
||||
));
|
||||
}
|
||||
$this->callable = $callable;
|
||||
@@ -107,8 +128,6 @@ class Sendmail implements TransportInterface
|
||||
|
||||
/**
|
||||
* Send a message
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
*/
|
||||
public function send(Mail\Message $message)
|
||||
{
|
||||
@@ -133,8 +152,7 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare recipients list
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @throws \Laminas\Mail\Transport\Exception\RuntimeException
|
||||
* @throws RuntimeException
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareRecipients(Mail\Message $message)
|
||||
@@ -143,7 +161,7 @@ class Sendmail implements TransportInterface
|
||||
|
||||
$hasTo = $headers->has('to');
|
||||
if (! $hasTo && ! $headers->has('cc') && ! $headers->has('bcc')) {
|
||||
throw new Exception\RuntimeException(
|
||||
throw new RuntimeException(
|
||||
'Invalid email; contains no at least one of "To", "Cc", and "Bcc" header'
|
||||
);
|
||||
}
|
||||
@@ -156,7 +174,7 @@ class Sendmail implements TransportInterface
|
||||
$to = $headers->get('to');
|
||||
$list = $to->getAddressList();
|
||||
if (0 == count($list)) {
|
||||
throw new Exception\RuntimeException('Invalid "To" header; contains no addresses');
|
||||
throw new RuntimeException('Invalid "To" header; contains no addresses');
|
||||
}
|
||||
|
||||
// If not on Windows, return normal string
|
||||
@@ -176,7 +194,6 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare the subject line string
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareSubject(Mail\Message $message)
|
||||
@@ -192,7 +209,6 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare the body string
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareBody(Mail\Message $message)
|
||||
@@ -211,7 +227,6 @@ class Sendmail implements TransportInterface
|
||||
/**
|
||||
* Prepare the textual representation of headers
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareHeaders(Mail\Message $message)
|
||||
@@ -225,8 +240,8 @@ class Sendmail implements TransportInterface
|
||||
$from = $headers->get('From');
|
||||
if ($from) {
|
||||
foreach ($from->getAddressList() as $address) {
|
||||
if (strpos($address->getEmail(), '\\"') !== false) {
|
||||
throw new Exception\RuntimeException('Potential code injection in From header');
|
||||
if (str_contains($address->getEmail(), '\\"')) {
|
||||
throw new RuntimeException('Potential code injection in From header');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,7 +254,6 @@ class Sendmail implements TransportInterface
|
||||
* Basically, overrides the MAIL FROM envelope with either the Sender or
|
||||
* From address.
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareParameters(Mail\Message $message)
|
||||
@@ -255,16 +269,14 @@ class Sendmail implements TransportInterface
|
||||
|
||||
$sender = $message->getSender();
|
||||
if ($sender instanceof AddressInterface) {
|
||||
$parameters .= ' -f' . \escapeshellarg($sender->getEmail());
|
||||
return $parameters;
|
||||
return $parameters . ' -f' . escapeshellarg($sender->getEmail());
|
||||
}
|
||||
|
||||
$from = $message->getFrom();
|
||||
if (count($from)) {
|
||||
$from->rewind();
|
||||
$sender = $from->current();
|
||||
$parameters .= ' -f' . \escapeshellarg($sender->getEmail());
|
||||
return $parameters;
|
||||
$sender = $from->current();
|
||||
return $parameters . ' -f' . escapeshellarg($sender->getEmail());
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
@@ -277,8 +289,8 @@ class Sendmail implements TransportInterface
|
||||
* @param string $subject
|
||||
* @param string $message
|
||||
* @param string $headers
|
||||
* @param $parameters
|
||||
* @throws \Laminas\Mail\Transport\Exception\RuntimeException
|
||||
* @param null|string $parameters
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function mailHandler($to, $subject, $message, $headers, $parameters)
|
||||
{
|
||||
@@ -295,7 +307,7 @@ class Sendmail implements TransportInterface
|
||||
if (empty($errstr)) {
|
||||
$errstr = 'Unknown error';
|
||||
}
|
||||
throw new Exception\RuntimeException('Unable to send mail: ' . $errstr);
|
||||
throw new RuntimeException('Unable to send mail: ' . $errstr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +321,7 @@ class Sendmail implements TransportInterface
|
||||
* @param array $errcontext
|
||||
* @return bool always true
|
||||
*/
|
||||
public function handleMailErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
|
||||
public function handleMailErrors($errno, $errstr, $errfile = null, $errline = null, ?array $errcontext = null)
|
||||
{
|
||||
$this->errstr = $errstr;
|
||||
return true;
|
||||
@@ -325,6 +337,6 @@ class Sendmail implements TransportInterface
|
||||
if (! $this->operatingSystem) {
|
||||
$this->operatingSystem = strtoupper(substr(PHP_OS, 0, 3));
|
||||
}
|
||||
return ($this->operatingSystem == 'WIN');
|
||||
return $this->operatingSystem == 'WIN';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ use Laminas\Mail\Protocol;
|
||||
use Laminas\Mail\Protocol\Exception as ProtocolException;
|
||||
use Laminas\ServiceManager\ServiceManager;
|
||||
|
||||
use function array_unique;
|
||||
use function count;
|
||||
use function sprintf;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* SMTP connection object
|
||||
*
|
||||
@@ -16,29 +21,19 @@ use Laminas\ServiceManager\ServiceManager;
|
||||
*/
|
||||
class Smtp implements TransportInterface
|
||||
{
|
||||
/**
|
||||
* @var SmtpOptions
|
||||
*/
|
||||
/** @var SmtpOptions */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var Envelope|null
|
||||
*/
|
||||
/** @var Envelope|null */
|
||||
protected $envelope;
|
||||
|
||||
/**
|
||||
* @var Protocol\Smtp
|
||||
*/
|
||||
/** @var null|Protocol\Smtp */
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
/** @var bool */
|
||||
protected $autoDisconnect = true;
|
||||
|
||||
/**
|
||||
* @var Protocol\SmtpPluginManager
|
||||
*/
|
||||
/** @var Protocol\SmtpPluginManager */
|
||||
protected $plugins;
|
||||
|
||||
/**
|
||||
@@ -49,11 +44,9 @@ class Smtp implements TransportInterface
|
||||
protected $connectedTime;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param SmtpOptions $options Optional
|
||||
*/
|
||||
public function __construct(SmtpOptions $options = null)
|
||||
public function __construct(?SmtpOptions $options = null)
|
||||
{
|
||||
if (! $options instanceof SmtpOptions) {
|
||||
$options = new SmtpOptions();
|
||||
@@ -64,7 +57,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Set options
|
||||
*
|
||||
* @param SmtpOptions $options
|
||||
* @return Smtp
|
||||
*/
|
||||
public function setOptions(SmtpOptions $options)
|
||||
@@ -85,8 +77,6 @@ class Smtp implements TransportInterface
|
||||
|
||||
/**
|
||||
* Set options
|
||||
*
|
||||
* @param Envelope $envelope
|
||||
*/
|
||||
public function setEnvelope(Envelope $envelope)
|
||||
{
|
||||
@@ -106,7 +96,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Set plugin manager for obtaining SMTP protocol connection
|
||||
*
|
||||
* @param Protocol\SmtpPluginManager $plugins
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return Smtp
|
||||
*/
|
||||
@@ -155,10 +144,9 @@ class Smtp implements TransportInterface
|
||||
* Return an SMTP connection
|
||||
*
|
||||
* @param string $name
|
||||
* @param array|null $options
|
||||
* @return Protocol\Smtp
|
||||
*/
|
||||
public function plugin($name, array $options = null)
|
||||
public function plugin($name, ?array $options = null)
|
||||
{
|
||||
return $this->getPluginManager()->get($name, $options);
|
||||
}
|
||||
@@ -168,30 +156,30 @@ class Smtp implements TransportInterface
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (! $this->getConnection() instanceof Protocol\Smtp) {
|
||||
$connection = $this->getConnection();
|
||||
if (! $connection instanceof Protocol\Smtp) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->getConnection()->quit();
|
||||
} catch (ProtocolException\ExceptionInterface $e) {
|
||||
$connection->quit();
|
||||
} catch (ProtocolException\ExceptionInterface) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if ($this->autoDisconnect) {
|
||||
$this->getConnection()->disconnect();
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection protocol instance
|
||||
*
|
||||
* @param Protocol\AbstractProtocol $connection
|
||||
*/
|
||||
public function setConnection(Protocol\AbstractProtocol $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
if (($connection instanceof Protocol\Smtp)
|
||||
if (
|
||||
$connection instanceof Protocol\Smtp
|
||||
&& ($this->getOptions()->getConnectionTimeLimit() !== null)
|
||||
) {
|
||||
$connection->setUseCompleteQuit(false);
|
||||
@@ -201,12 +189,13 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Gets the connection protocol instance
|
||||
*
|
||||
* @return Protocol\Smtp
|
||||
* @return null|Protocol\Smtp
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
$timeLimit = $this->getOptions()->getConnectionTimeLimit();
|
||||
if ($timeLimit !== null
|
||||
if (
|
||||
$timeLimit !== null
|
||||
&& $this->connectedTime !== null
|
||||
&& ((time() - $this->connectedTime) > $timeLimit)
|
||||
) {
|
||||
@@ -222,8 +211,9 @@ class Smtp implements TransportInterface
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
if ($this->getConnection() instanceof Protocol\Smtp) {
|
||||
$this->getConnection()->disconnect();
|
||||
$connection = $this->getConnection();
|
||||
if ($connection instanceof Protocol\Smtp) {
|
||||
$connection->disconnect();
|
||||
$this->connectedTime = null;
|
||||
}
|
||||
}
|
||||
@@ -234,7 +224,6 @@ class Smtp implements TransportInterface
|
||||
* The connection via the protocol adapter is made just-in-time to allow a
|
||||
* developer to add a custom adapter if required before mail is sent.
|
||||
*
|
||||
* @param Message $message
|
||||
* @throws Exception\RuntimeException
|
||||
*/
|
||||
public function send(Message $message)
|
||||
@@ -242,7 +231,7 @@ class Smtp implements TransportInterface
|
||||
// If sending multiple messages per session use existing adapter
|
||||
$connection = $this->getConnection();
|
||||
|
||||
if (! ($connection instanceof Protocol\Smtp) || ! $connection->hasSession()) {
|
||||
if (! $connection instanceof Protocol\Smtp || ! $connection->hasSession()) {
|
||||
$connection = $this->connect();
|
||||
} else {
|
||||
// Reset connection to ensure reliable transaction
|
||||
@@ -260,7 +249,7 @@ class Smtp implements TransportInterface
|
||||
throw new Exception\RuntimeException(
|
||||
sprintf(
|
||||
'%s transport expects at least one recipient if the message has at least one header or body',
|
||||
__CLASS__
|
||||
self::class
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -280,7 +269,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Retrieve email address for envelope FROM
|
||||
*
|
||||
* @param Message $message
|
||||
* @throws Exception\RuntimeException
|
||||
* @return string
|
||||
*/
|
||||
@@ -300,7 +288,7 @@ class Smtp implements TransportInterface
|
||||
// Per RFC 2822 3.6
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
'%s transport expects either a Sender or at least one From address in the Message; none provided',
|
||||
__CLASS__
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
@@ -312,7 +300,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Prepare array of email address recipients
|
||||
*
|
||||
* @param Message $message
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareRecipients(Message $message)
|
||||
@@ -339,7 +326,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Prepare header string from message
|
||||
*
|
||||
* @param Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareHeaders(Message $message)
|
||||
@@ -352,7 +338,6 @@ class Smtp implements TransportInterface
|
||||
/**
|
||||
* Prepare body string from message
|
||||
*
|
||||
* @param Message $message
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareBody(Message $message)
|
||||
@@ -368,10 +353,10 @@ class Smtp implements TransportInterface
|
||||
protected function lazyLoadConnection()
|
||||
{
|
||||
// Check if authentication is required and determine required class
|
||||
$options = $this->getOptions();
|
||||
$config = $options->getConnectionConfig();
|
||||
$config['host'] = $options->getHost();
|
||||
$config['port'] = $options->getPort();
|
||||
$options = $this->getOptions();
|
||||
$config = $options->getConnectionConfig();
|
||||
$config['host'] = $options->getHost();
|
||||
$config['port'] = $options->getPort();
|
||||
|
||||
$this->setConnection($this->plugin($options->getConnectionClass(), $config));
|
||||
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
namespace Laminas\Mail\Transport;
|
||||
|
||||
use Laminas\Mail\Exception;
|
||||
use Laminas\Mail\Exception\InvalidArgumentException;
|
||||
use Laminas\Stdlib\AbstractOptions;
|
||||
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
|
||||
class SmtpOptions extends AbstractOptions
|
||||
{
|
||||
/**
|
||||
* @var string Local client hostname
|
||||
*/
|
||||
/** @var string Local client hostname */
|
||||
protected $name = 'localhost';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $connectionClass = 'smtp';
|
||||
|
||||
/**
|
||||
@@ -24,14 +26,10 @@ class SmtpOptions extends AbstractOptions
|
||||
*/
|
||||
protected $connectionConfig = [];
|
||||
|
||||
/**
|
||||
* @var string Remote SMTP hostname or IP
|
||||
*/
|
||||
/** @var string Remote SMTP hostname or IP */
|
||||
protected $host = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
/** @var int */
|
||||
protected $port = 25;
|
||||
|
||||
/**
|
||||
@@ -57,7 +55,7 @@ class SmtpOptions extends AbstractOptions
|
||||
*
|
||||
* @todo hostname/IP validation
|
||||
* @param string $name
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setName($name)
|
||||
@@ -65,7 +63,7 @@ class SmtpOptions extends AbstractOptions
|
||||
if (! is_string($name) && $name !== null) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Name must be a string or null; argument of type "%s" provided',
|
||||
(is_object($name) ? get_class($name) : gettype($name))
|
||||
is_object($name) ? $name::class : gettype($name)
|
||||
));
|
||||
}
|
||||
$this->name = $name;
|
||||
@@ -90,7 +88,7 @@ class SmtpOptions extends AbstractOptions
|
||||
* Set connection class
|
||||
*
|
||||
* @param string $connectionClass the value to be set
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setConnectionClass($connectionClass)
|
||||
@@ -98,7 +96,7 @@ class SmtpOptions extends AbstractOptions
|
||||
if (! is_string($connectionClass) && $connectionClass !== null) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Connection class must be a string or null; argument of type "%s" provided',
|
||||
(is_object($connectionClass) ? get_class($connectionClass) : gettype($connectionClass))
|
||||
is_object($connectionClass) ? $connectionClass::class : gettype($connectionClass)
|
||||
));
|
||||
}
|
||||
$this->connectionClass = $connectionClass;
|
||||
@@ -118,7 +116,6 @@ class SmtpOptions extends AbstractOptions
|
||||
/**
|
||||
* Set connection configuration array
|
||||
*
|
||||
* @param array $connectionConfig
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setConnectionConfig(array $connectionConfig)
|
||||
@@ -164,7 +161,7 @@ class SmtpOptions extends AbstractOptions
|
||||
* Set the port the SMTP server runs on
|
||||
*
|
||||
* @param int $port
|
||||
* @throws \Laminas\Mail\Exception\InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return SmtpOptions
|
||||
*/
|
||||
public function setPort($port)
|
||||
|
||||
@@ -12,8 +12,7 @@ interface TransportInterface
|
||||
/**
|
||||
* Send a mail message
|
||||
*
|
||||
* @param \Laminas\Mail\Message $message
|
||||
* @return
|
||||
* @return void
|
||||
*/
|
||||
public function send(Mail\Message $message);
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ignore_php_platform_requirements": {
|
||||
"8.1": true
|
||||
}
|
||||
}
|
||||
7
lib/laminas/laminas-mime/.laminas-ci/pre-install.sh
Normal file
7
lib/laminas/laminas-mime/.laminas-ci/pre-install.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Temporary workaround for cyclic dependencies - can be removed once 3.0 has been released
|
||||
|
||||
echo "Branch as 2.99.x in Pre-Install"
|
||||
|
||||
git checkout -b 2.99.x
|
||||
@@ -1,5 +1,21 @@
|
||||
# laminas-mime
|
||||
|
||||
> ## 🇷🇺 Русским гражданам
|
||||
>
|
||||
> Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм.
|
||||
>
|
||||
> У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую.
|
||||
>
|
||||
> Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!"
|
||||
>
|
||||
> ## 🇺🇸 To Citizens of Russia
|
||||
>
|
||||
> We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism.
|
||||
>
|
||||
> One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences.
|
||||
>
|
||||
> You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!"
|
||||
|
||||
> This package is considered feature-complete, and is now in **security-only** maintenance mode, following a [decision by the Technical Steering Committee](https://github.com/laminas/technical-steering-committee/blob/2b55453e172a1b8c9c4c212be7cf7e7a58b9352c/meetings/minutes/2020-08-03-TSC-Minutes.md#vote-on-components-to-mark-as-security-only).
|
||||
> If you have a security issue, please [follow our security reporting guidelines](https://getlaminas.org/security/).
|
||||
> If you wish to take on the role of maintainer, please [nominate yourself](https://github.com/laminas/technical-steering-committee/issues/new?assignees=&labels=Nomination&template=Maintainer_Nomination.md&title=%5BNOMINATION%5D%5BMAINTAINER%5D%3A+%7Bname+of+person+being+nominated%7D)
|
||||
|
||||
@@ -16,16 +16,19 @@
|
||||
"forum": "https://discourse.laminas.dev"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0",
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
|
||||
"laminas/laminas-stdlib": "^2.7 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.2.1",
|
||||
"laminas/laminas-mail": "^2.12",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
"laminas/laminas-coding-standard": "~2.4.0",
|
||||
"laminas/laminas-mail": "^2.19.0",
|
||||
"phpunit/phpunit": "~9.5.25"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-mail": "Laminas\\Mail component"
|
||||
|
||||
1223
lib/laminas/laminas-mime/composer.lock
generated
1223
lib/laminas/laminas-mime/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="./vendor/squizlabs/php_codesniffer/phpcs.xsd">
|
||||
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="cache" value=".phpcs-cache"/>
|
||||
<arg name="colors"/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="parallel" value="80"/>
|
||||
|
||||
<!-- Show progress -->
|
||||
<arg value="p"/>
|
||||
|
||||
<!-- Paths to check -->
|
||||
<file>src</file>
|
||||
<file>test</file>
|
||||
|
||||
<!-- Include all rules from Laminas Coding Standard -->
|
||||
<rule ref="LaminasCodingStandard"/>
|
||||
</ruleset>
|
||||
@@ -491,17 +491,22 @@ class Mime
|
||||
* Mail headers depend on an extended quoted printable algorithm otherwise
|
||||
* a range of bugs can occur.
|
||||
*
|
||||
* @param string $str
|
||||
* @param string $charset
|
||||
* @param int $lineLength Defaults to {@link LINELENGTH}
|
||||
* @param string $lineEnd Defaults to {@link LINEEND}
|
||||
* @param string $str
|
||||
* @param string $charset
|
||||
* @param int $lineLength Defaults to {@link LINELENGTH}
|
||||
* @param string $lineEnd Defaults to {@link LINEEND}
|
||||
* @param positive-int|0 $headerNameSize When folding a line, it is necessary to calculate
|
||||
* the length of the entire line (together with the header name).
|
||||
* Therefore, you can specify the header name and colon length
|
||||
* in this argument to fold the string properly.
|
||||
* @return string
|
||||
*/
|
||||
public static function encodeQuotedPrintableHeader(
|
||||
$str,
|
||||
$charset,
|
||||
$lineLength = self::LINELENGTH,
|
||||
$lineEnd = self::LINEEND
|
||||
$lineEnd = self::LINEEND,
|
||||
$headerNameSize = 0
|
||||
) {
|
||||
// Reduce line-length by the length of the required delimiter, charsets and encoding
|
||||
$prefix = sprintf('=?%s?Q?', $charset);
|
||||
@@ -527,7 +532,14 @@ class Mime
|
||||
if ($token === '=20') {
|
||||
// only if we have a single char token or space, we can append the
|
||||
// tempstring it to the current line or start a new line if necessary.
|
||||
$lineLimitReached = strlen($lines[$currentLine] . $tmp) > $lineLength;
|
||||
if ($currentLine === 0) {
|
||||
// The size of the first line should be calculated with the header name.
|
||||
$currentLineLength = strlen($lines[$currentLine] . $tmp) + $headerNameSize;
|
||||
} else {
|
||||
$currentLineLength = strlen($lines[$currentLine] . $tmp);
|
||||
}
|
||||
|
||||
$lineLimitReached = $currentLineLength > $lineLength;
|
||||
$noCurrentLine = $lines[$currentLine] === '';
|
||||
if ($noCurrentLine && $lineLimitReached) {
|
||||
$lines[$currentLine] = $tmp;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Laminas\Mime;
|
||||
|
||||
use function array_key_exists;
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
@@ -315,7 +314,7 @@ class Part
|
||||
if (! is_string($content) && ! is_resource($content)) {
|
||||
throw new Exception\InvalidArgumentException(sprintf(
|
||||
'Content must be string or resource; received "%s"',
|
||||
is_object($content) ? get_class($content) : gettype($content)
|
||||
is_object($content) ? $content::class : gettype($content)
|
||||
));
|
||||
}
|
||||
$this->content = $content;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# laminas-stdlib
|
||||
|
||||
[](https://github.com/laminas/laminas-stdlib/actions/workflows/continuous-integration.yml)
|
||||
[](https://coveralls.io/github/laminas/laminas-stdlib?branch=master)
|
||||
[](https://shepherd.dev/github/laminas/laminas-stdlib)
|
||||
|
||||
> ## 🇷🇺 Русским гражданам
|
||||
>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"platform": {
|
||||
"php": "7.4.99"
|
||||
"php": "8.1.99"
|
||||
},
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
@@ -27,15 +27,14 @@
|
||||
"extra": {
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0"
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~2.3.0",
|
||||
"phpbench/phpbench": "^1.2.6",
|
||||
"phpunit/phpunit": "^9.5.23",
|
||||
"psalm/plugin-phpunit": "^0.17.0",
|
||||
"vimeo/psalm": "^4.26",
|
||||
"phpstan/phpdoc-parser": "^0.5.4"
|
||||
"laminas/laminas-coding-standard": "^2.5",
|
||||
"phpbench/phpbench": "^1.2.15",
|
||||
"phpunit/phpunit": "^10.5.8",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"vimeo/psalm": "^5.20.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
4852
lib/laminas/laminas-stdlib/composer.lock
generated
4852
lib/laminas/laminas-stdlib/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ namespace Laminas\Stdlib;
|
||||
use Traversable;
|
||||
|
||||
use function array_shift;
|
||||
use function get_object_vars;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
use function method_exists;
|
||||
@@ -16,6 +17,10 @@ use function str_replace;
|
||||
use function strtolower;
|
||||
use function ucwords;
|
||||
|
||||
/**
|
||||
* @template TValue
|
||||
* @implements ParameterObjectInterface<string, TValue>
|
||||
*/
|
||||
abstract class AbstractOptions implements ParameterObjectInterface
|
||||
{
|
||||
// phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore,WebimpressCodingStandard.NamingConventions.ValidVariableName.NotCamelCapsProperty
|
||||
@@ -33,7 +38,7 @@ abstract class AbstractOptions implements ParameterObjectInterface
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|Traversable|null $options
|
||||
* @param iterable<string, TValue>|AbstractOptions<TValue>|null $options
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
@@ -45,7 +50,7 @@ abstract class AbstractOptions implements ParameterObjectInterface
|
||||
/**
|
||||
* Set one or more configuration properties
|
||||
*
|
||||
* @param array|Traversable|AbstractOptions $options
|
||||
* @param iterable<string, TValue>|AbstractOptions<TValue> $options
|
||||
* @throws Exception\InvalidArgumentException
|
||||
* @return AbstractOptions Provides fluent interface
|
||||
*/
|
||||
@@ -77,19 +82,20 @@ abstract class AbstractOptions implements ParameterObjectInterface
|
||||
/**
|
||||
* Cast to array
|
||||
*
|
||||
* @return array
|
||||
* @return array<string, TValue>
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$array = [];
|
||||
|
||||
/** @param string[] $letters */
|
||||
$transform = static function (array $letters): string {
|
||||
/** @var list<string> $letters */
|
||||
$letter = array_shift($letters);
|
||||
return '_' . strtolower($letter);
|
||||
};
|
||||
|
||||
foreach ($this as $key => $value) {
|
||||
/** @psalm-var TValue $value */
|
||||
foreach (get_object_vars($this) as $key => $value) {
|
||||
if ($key === '__strictMode__') {
|
||||
continue;
|
||||
}
|
||||
@@ -106,7 +112,7 @@ abstract class AbstractOptions implements ParameterObjectInterface
|
||||
* @see ParameterObject::__set()
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param TValue|null $value
|
||||
* @throws Exception\BadMethodCallException
|
||||
* @return void
|
||||
*/
|
||||
@@ -137,7 +143,7 @@ abstract class AbstractOptions implements ParameterObjectInterface
|
||||
*
|
||||
* @param string $key
|
||||
* @throws Exception\BadMethodCallException
|
||||
* @return mixed
|
||||
* @return TValue
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Laminas\Stdlib;
|
||||
|
||||
use AllowDynamicProperties;
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use Iterator;
|
||||
use IteratorAggregate;
|
||||
@@ -17,7 +19,7 @@ use function array_keys;
|
||||
use function asort;
|
||||
use function class_exists;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function get_debug_type;
|
||||
use function get_object_vars;
|
||||
use function gettype;
|
||||
use function in_array;
|
||||
@@ -30,7 +32,7 @@ use function natcasesort;
|
||||
use function natsort;
|
||||
use function serialize;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use function str_starts_with;
|
||||
use function uasort;
|
||||
use function uksort;
|
||||
use function unserialize;
|
||||
@@ -39,7 +41,13 @@ use function unserialize;
|
||||
* Custom framework ArrayObject implementation
|
||||
*
|
||||
* Extends version-specific "abstract" implementation.
|
||||
*
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template-implements IteratorAggregate<TKey, TValue>
|
||||
* @template-implements ArrayAccess<TKey, TValue>
|
||||
*/
|
||||
#[AllowDynamicProperties]
|
||||
class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable
|
||||
{
|
||||
/**
|
||||
@@ -53,26 +61,24 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
*/
|
||||
public const ARRAY_AS_PROPS = 2;
|
||||
|
||||
/** @var array */
|
||||
/** @var array<TKey, TValue> */
|
||||
protected $storage;
|
||||
|
||||
/** @var int */
|
||||
/** @var self::STD_PROP_LIST|self::ARRAY_AS_PROPS */
|
||||
protected $flag;
|
||||
|
||||
/** @var string */
|
||||
/** @var class-string<Iterator> */
|
||||
protected $iteratorClass;
|
||||
|
||||
/** @var array */
|
||||
/** @var list<string> */
|
||||
protected $protectedProperties;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|object $input Object values must act like ArrayAccess
|
||||
* @param int $flags
|
||||
* @param string $iteratorClass
|
||||
* @param array<TKey, TValue>|object $input Object values must act like ArrayAccess
|
||||
* @param self::STD_PROP_LIST|self::ARRAY_AS_PROPS $flags
|
||||
* @param class-string<Iterator> $iteratorClass
|
||||
*/
|
||||
public function __construct($input = [], $flags = self::STD_PROP_LIST, $iteratorClass = 'ArrayIterator')
|
||||
public function __construct($input = [], $flags = self::STD_PROP_LIST, $iteratorClass = ArrayIterator::class)
|
||||
{
|
||||
$this->setFlags($flags);
|
||||
$this->storage = $input;
|
||||
@@ -83,10 +89,10 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Returns whether the requested key exists
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param TKey $key
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($key)
|
||||
public function __isset(mixed $key)
|
||||
{
|
||||
if ($this->flag === self::ARRAY_AS_PROPS) {
|
||||
return $this->offsetExists($key);
|
||||
@@ -102,11 +108,11 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Sets the value at the specified key to value
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @param TKey $key
|
||||
* @param TValue $value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
public function __set(mixed $key, mixed $value)
|
||||
{
|
||||
if ($this->flag === self::ARRAY_AS_PROPS) {
|
||||
$this->offsetSet($key, $value);
|
||||
@@ -123,10 +129,10 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Unsets the value at the specified key
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param TKey $key
|
||||
* @return void
|
||||
*/
|
||||
public function __unset($key)
|
||||
public function __unset(mixed $key)
|
||||
{
|
||||
if ($this->flag === self::ARRAY_AS_PROPS) {
|
||||
$this->offsetUnset($key);
|
||||
@@ -143,10 +149,10 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Returns the value at the specified key by reference
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
* @param TKey $key
|
||||
* @return TValue|null
|
||||
*/
|
||||
public function &__get($key)
|
||||
public function &__get(mixed $key)
|
||||
{
|
||||
if ($this->flag === self::ARRAY_AS_PROPS) {
|
||||
$ret = &$this->offsetGet($key);
|
||||
@@ -164,10 +170,10 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Appends the value
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param TValue $value
|
||||
* @return void
|
||||
*/
|
||||
public function append($value)
|
||||
public function append(mixed $value)
|
||||
{
|
||||
$this->storage[] = $value;
|
||||
}
|
||||
@@ -185,7 +191,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Get the number of public properties in the ArrayObject
|
||||
*
|
||||
* @return int
|
||||
* @return positive-int|0
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function count()
|
||||
@@ -196,8 +202,8 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Exchange the array for another one.
|
||||
*
|
||||
* @param array|ArrayObject|ArrayIterator|object $data
|
||||
* @return array
|
||||
* @param array<TKey, TValue>|ArrayObject<TKey, TValue>|ArrayIterator<TKey, TValue>|object $data
|
||||
* @return array<TKey, TValue>
|
||||
*/
|
||||
public function exchangeArray($data)
|
||||
{
|
||||
@@ -224,7 +230,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Creates a copy of the ArrayObject.
|
||||
*
|
||||
* @return array
|
||||
* @return array<TKey, TValue>
|
||||
*/
|
||||
public function getArrayCopy()
|
||||
{
|
||||
@@ -234,7 +240,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Gets the behavior flags.
|
||||
*
|
||||
* @return int
|
||||
* @return self::STD_PROP_LIST|self::ARRAY_AS_PROPS
|
||||
*/
|
||||
public function getFlags()
|
||||
{
|
||||
@@ -244,7 +250,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Create a new iterator from an ArrayObject instance
|
||||
*
|
||||
* @return Iterator
|
||||
* @return Iterator<TKey, TValue>
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
@@ -257,7 +263,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Gets the iterator classname for the ArrayObject.
|
||||
*
|
||||
* @return string
|
||||
* @return class-string<Iterator>
|
||||
*/
|
||||
public function getIteratorClass()
|
||||
{
|
||||
@@ -297,23 +303,23 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Returns whether the requested key exists
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param TKey $key
|
||||
* @return bool
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetExists($key)
|
||||
public function offsetExists(mixed $key)
|
||||
{
|
||||
return isset($this->storage[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value at the specified key
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
* @param TKey $key
|
||||
* @return TValue|null
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function &offsetGet($key)
|
||||
public function &offsetGet(mixed $key)
|
||||
{
|
||||
$ret = null;
|
||||
if (! $this->offsetExists($key)) {
|
||||
@@ -327,27 +333,27 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Sets the value at the specified key to value
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @param TKey $offset
|
||||
* @param TValue $value
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetSet($key, $value)
|
||||
public function offsetSet(mixed $offset, mixed $value)
|
||||
{
|
||||
$this->storage[$key] = $value;
|
||||
$this->storage[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the value at the specified key
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param TKey $offset
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetUnset($key)
|
||||
public function offsetUnset(mixed $offset)
|
||||
{
|
||||
if ($this->offsetExists($key)) {
|
||||
unset($this->storage[$key]);
|
||||
if ($this->offsetExists($offset)) {
|
||||
unset($this->storage[$offset]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +370,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Magic method used for serializing of an instance.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function __serialize()
|
||||
{
|
||||
@@ -374,7 +380,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Sets the behavior flags
|
||||
*
|
||||
* @param int $flags
|
||||
* @param self::STD_PROP_LIST|self::ARRAY_AS_PROPS $flags
|
||||
* @return void
|
||||
*/
|
||||
public function setFlags($flags)
|
||||
@@ -385,7 +391,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Sets the iterator classname for the ArrayObject
|
||||
*
|
||||
* @param string $class
|
||||
* @param class-string<Iterator> $class
|
||||
* @return void
|
||||
*/
|
||||
public function setIteratorClass($class)
|
||||
@@ -396,7 +402,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($class, '\\') === 0) {
|
||||
if (str_starts_with($class, '\\')) {
|
||||
$class = '\\' . $class;
|
||||
if (class_exists($class)) {
|
||||
$this->iteratorClass = $class;
|
||||
@@ -411,7 +417,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Sort the entries with a user-defined comparison function and maintain key association
|
||||
*
|
||||
* @param callable $function
|
||||
* @param callable(TValue, TValue): int $function
|
||||
* @return void
|
||||
*/
|
||||
public function uasort($function)
|
||||
@@ -424,7 +430,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
/**
|
||||
* Sort the entries by keys using a user-defined comparison function
|
||||
*
|
||||
* @param callable $function
|
||||
* @param callable(TKey, TKey): int $function
|
||||
* @return void
|
||||
*/
|
||||
public function uksort($function)
|
||||
@@ -486,9 +492,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Count
|
||||
throw new UnexpectedValueException(sprintf(
|
||||
'Cannot deserialize %s instance: invalid iteratorClass; expected string, received %s',
|
||||
self::class,
|
||||
is_object($data['iteratorClass'])
|
||||
? get_class($data['iteratorClass'])
|
||||
: gettype($data['iteratorClass'])
|
||||
get_debug_type($data['iteratorClass'])
|
||||
));
|
||||
}
|
||||
$this->setIteratorClass($data['iteratorClass']);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user