updated requirements

This commit is contained in:
Torsten Schulz
2023-06-16 13:08:22 +02:00
parent 1c6f08b77a
commit 079ce3e41d
60 changed files with 8228 additions and 774 deletions

View File

@@ -9,7 +9,7 @@
"require": { "require": {
"tinymce/tinymce": "*", "tinymce/tinymce": "*",
"phpmailer/phpmailer": "dev-master", "phpmailer/phpmailer": "dev-master",
"php-imap/php-imap": "^2.0" "php-imap/php-imap": "5.0"
}, },
"minimum-stability": "dev" "minimum-stability": "dev"
} }

49
composer.lock generated
View File

@@ -4,34 +4,54 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "273d2592d3c90db120bdd9644b0975a0", "content-hash": "28af27dc1d7f1cf3b23cc196c9a13301",
"packages": [ "packages": [
{ {
"name": "php-imap/php-imap", "name": "php-imap/php-imap",
"version": "2.0.3", "version": "5.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barbushin/php-imap.git", "url": "https://github.com/barbushin/php-imap.git",
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b" "reference": "13bdfa9a6f541798253e24e2d8f44332c8be098c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barbushin/php-imap/zipball/cc1a49a3f68090db182183c59ffbc09055d59f5b", "url": "https://api.github.com/repos/barbushin/php-imap/zipball/13bdfa9a6f541798253e24e2d8f44332c8be098c",
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b", "reference": "13bdfa9a6f541798253e24e2d8f44332c8be098c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "ext-fileinfo": "*",
"ext-iconv": "*",
"ext-imap": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.4",
"maglnet/composer-require-checker": "^2.0|^3.2",
"nikic/php-parser": "^4.3,<4.7|^4.10",
"paragonie/hidden-string": "^1.0",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpunit/phpunit": "^8.5|^9.5",
"povils/phpmnd": "^2.2",
"psalm/plugin-phpunit": "^0.10.0|^0.15.1",
"roave/security-advisories": "dev-master",
"sebastian/phpcpd": "^4.1|^6.0"
},
"suggest": {
"ext-fileinfo": "To facilitate IncomingMailAttachment::getFileInfo() auto-detection"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"PhpImap": "src/" "PhpImap\\": "src/PhpImap"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"BSD 3-Clause" "MIT"
], ],
"authors": [ "authors": [
{ {
@@ -40,18 +60,21 @@
"homepage": "http://linkedin.com/in/barbushin" "homepage": "http://linkedin.com/in/barbushin"
} }
], ],
"description": "PHP class to access mailbox by POP3/IMAP/NNTP using IMAP extension", "description": "Manage mailboxes, filter/get/delete emails in PHP (supports IMAP/POP3/NNTP)",
"homepage": "https://github.com/barbushin/php-imap", "homepage": "https://github.com/barbushin/php-imap",
"keywords": [ "keywords": [
"imap", "imap",
"mail", "mail",
"php" "mailbox",
"php",
"pop3",
"receive emails"
], ],
"support": { "support": {
"issues": "https://github.com/barbushin/php-imap/issues", "issues": "https://github.com/barbushin/php-imap/issues",
"source": "https://github.com/barbushin/php-imap/tree/master" "source": "https://github.com/barbushin/php-imap/tree/5.0.0"
}, },
"time": "2015-09-16T07:40:39+00:00" "time": "2022-03-12T14:39:59+00:00"
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",

View File

@@ -6,5 +6,4 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'PhpImap' => array($vendorDir . '/php-imap/php-imap/src'),
); );

View File

@@ -6,5 +6,6 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'PhpImap\\' => array($vendorDir . '/php-imap/php-imap/src/PhpImap'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
); );

View File

@@ -9,27 +9,22 @@ class ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3
public static $prefixLengthsPsr4 = array ( public static $prefixLengthsPsr4 = array (
'P' => 'P' =>
array ( array (
'PhpImap\\' => 8,
'PHPMailer\\PHPMailer\\' => 20, 'PHPMailer\\PHPMailer\\' => 20,
), ),
); );
public static $prefixDirsPsr4 = array ( public static $prefixDirsPsr4 = array (
'PhpImap\\' =>
array (
0 => __DIR__ . '/..' . '/php-imap/php-imap/src/PhpImap',
),
'PHPMailer\\PHPMailer\\' => 'PHPMailer\\PHPMailer\\' =>
array ( array (
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
), ),
); );
public static $prefixesPsr0 = array (
'P' =>
array (
'PhpImap' =>
array (
0 => __DIR__ . '/..' . '/php-imap/php-imap/src',
),
),
);
public static $classMap = array ( public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
); );
@@ -39,7 +34,6 @@ class ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3
return \Closure::bind(function () use ($loader) { return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixLengthsPsr4; $loader->prefixLengthsPsr4 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixDirsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$prefixesPsr0;
$loader->classMap = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$classMap; $loader->classMap = ComposerStaticInitb3a3dfb766a515d49b7f8665bad574b3::$classMap;
}, null, ClassLoader::class); }, null, ClassLoader::class);

View File

@@ -2,33 +2,53 @@
"packages": [ "packages": [
{ {
"name": "php-imap/php-imap", "name": "php-imap/php-imap",
"version": "2.0.3", "version": "5.0.0",
"version_normalized": "2.0.3.0", "version_normalized": "5.0.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barbushin/php-imap.git", "url": "https://github.com/barbushin/php-imap.git",
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b" "reference": "13bdfa9a6f541798253e24e2d8f44332c8be098c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barbushin/php-imap/zipball/cc1a49a3f68090db182183c59ffbc09055d59f5b", "url": "https://api.github.com/repos/barbushin/php-imap/zipball/13bdfa9a6f541798253e24e2d8f44332c8be098c",
"reference": "cc1a49a3f68090db182183c59ffbc09055d59f5b", "reference": "13bdfa9a6f541798253e24e2d8f44332c8be098c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "ext-fileinfo": "*",
"ext-iconv": "*",
"ext-imap": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": "^7.4 || ^8.0"
}, },
"time": "2015-09-16T07:40:39+00:00", "require-dev": {
"friendsofphp/php-cs-fixer": "^3.4",
"maglnet/composer-require-checker": "^2.0|^3.2",
"nikic/php-parser": "^4.3,<4.7|^4.10",
"paragonie/hidden-string": "^1.0",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpunit/phpunit": "^8.5|^9.5",
"povils/phpmnd": "^2.2",
"psalm/plugin-phpunit": "^0.10.0|^0.15.1",
"roave/security-advisories": "dev-master",
"sebastian/phpcpd": "^4.1|^6.0"
},
"suggest": {
"ext-fileinfo": "To facilitate IncomingMailAttachment::getFileInfo() auto-detection"
},
"time": "2022-03-12T14:39:59+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"PhpImap": "src/" "PhpImap\\": "src/PhpImap"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"BSD 3-Clause" "MIT"
], ],
"authors": [ "authors": [
{ {
@@ -37,16 +57,19 @@
"homepage": "http://linkedin.com/in/barbushin" "homepage": "http://linkedin.com/in/barbushin"
} }
], ],
"description": "PHP class to access mailbox by POP3/IMAP/NNTP using IMAP extension", "description": "Manage mailboxes, filter/get/delete emails in PHP (supports IMAP/POP3/NNTP)",
"homepage": "https://github.com/barbushin/php-imap", "homepage": "https://github.com/barbushin/php-imap",
"keywords": [ "keywords": [
"imap", "imap",
"mail", "mail",
"php" "mailbox",
"php",
"pop3",
"receive emails"
], ],
"support": { "support": {
"issues": "https://github.com/barbushin/php-imap/issues", "issues": "https://github.com/barbushin/php-imap/issues",
"source": "https://github.com/barbushin/php-imap/tree/master" "source": "https://github.com/barbushin/php-imap/tree/5.0.0"
}, },
"install-path": "../php-imap/php-imap" "install-path": "../php-imap/php-imap"
}, },

View File

@@ -1,9 +1,9 @@
<?php return array( <?php return array(
'root' => array( 'root' => array(
'name' => '__root__', 'name' => '__root__',
'pretty_version' => '1.0.0+no-version-set', 'pretty_version' => 'dev-main',
'version' => '1.0.0.0', 'version' => 'dev-main',
'reference' => NULL, 'reference' => '1c6f08b77a9f8f7d91de74616da0b18dfccef4e8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@@ -11,18 +11,18 @@
), ),
'versions' => array( 'versions' => array(
'__root__' => array( '__root__' => array(
'pretty_version' => '1.0.0+no-version-set', 'pretty_version' => 'dev-main',
'version' => '1.0.0.0', 'version' => 'dev-main',
'reference' => NULL, 'reference' => '1c6f08b77a9f8f7d91de74616da0b18dfccef4e8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'php-imap/php-imap' => array( 'php-imap/php-imap' => array(
'pretty_version' => '2.0.3', 'pretty_version' => '5.0.0',
'version' => '2.0.3.0', 'version' => '5.0.0.0',
'reference' => 'cc1a49a3f68090db182183c59ffbc09055d59f5b', 'reference' => '13bdfa9a6f541798253e24e2d8f44332c8be098c',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../php-imap/php-imap', 'install_path' => __DIR__ . '/../php-imap/php-imap',
'aliases' => array(), 'aliases' => array(),

View File

@@ -4,8 +4,8 @@
$issues = array(); $issues = array();
if (!(PHP_VERSION_ID >= 50500)) { if (!(PHP_VERSION_ID >= 70400)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.5.0". You are running ' . PHP_VERSION . '.'; $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
} }
if ($issues) { if ($issues) {

View File

@@ -0,0 +1,36 @@
# Advanced Configuration for CodeClimate: https://docs.codeclimate.com/docs
languages:
PHP: true
exclude_paths: ["tests/*", "examples/*"]
version: "2" # required to adjust maintainability checks
checks:
argument-count:
config:
threshold: 5
complex-logic:
config:
threshold: 4
file-lines:
config:
threshold: 250
method-complexity:
config:
threshold: 5
method-count:
config:
threshold: 20
method-lines:
config:
threshold: 40
nested-control-flow:
config:
threshold: 4
return-statements:
config:
threshold: 4
similar-code:
config:
threshold: # language-specific defaults. an override will affect all languages.
identical-code:
config:
threshold: # language-specific defaults. an override will affect all languages.

15
vendor/php-imap/php-imap/.editorconfig vendored Normal file
View File

@@ -0,0 +1,15 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.yml]
indent_size = 2
[composer.json]
indent_style = space

View File

@@ -1,22 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

View File

@@ -0,0 +1,21 @@
# How to contribute
First of all, thanks for taking the time to contribute!
Every contribution, being it pull requests, bug reports or feature requests, will help to improve this library!
## Ways to contribute
* Found a bug? Want a feature? Or just having question? [Open an
issue!](https://github.com/barbushin/php-imap/issues/new/choose)
* Add a feature or fix a bug:
* Check for existing issue or create a new one.
* Fork the repo, make your changes.
* Create a pull request, and reference the issue.
* Add examples, tests, or improve documentation.
## Test
When committing code, please make sure to test before creating a pull request.
We use PHPUnit for testing, feel free to add new tests. This is not a requirement, but helps us maintain code coverage.

View File

@@ -0,0 +1,46 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] A short description of what the bug is"
labels: needs investigation
assignees: ''
---
**Environment (please complete the following information):**
- PHP IMAP version: [e.g. 3.0.11]
- PHP Version: [e.g. 7.1.26]
- Type of execution: [e.g. Daemon / CLI or Web Server]
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
The used code:
```php
$mailbox = new Mailbox(...
```
The headers of the parsed email, if required and possible (only, if it's NOT confidential):
```
Received: from BN3NAM04HT142.eop-NAM04.prod.protection.outlook.com
(2603:10a6:209:2a::30) by AM6PR05MB6294.eurprd05.prod.outlook.com with HTTPS
via AM6PR07CA0017.EURPRD07.PROD.OUTLOOK.COM; Sun, 5 May 2019 12:29:42 +0000
Received: from BN3NAM04FT054.eop-NAM04.prod.protection.outlook.com
(10.152.92.54) by BN3NAM04HT142.eop-NAM04.prod.protection.outlook.com
(10.152.92.244) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.1835.13; Sun, 5 May
2019 12:29:41 +0000
...
```
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots / Outputs**
If applicable, add screenshots or outputs of your script to help explain your problem.
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature Request] A short description of what you want to happen"
labels: needs investigation
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,16 @@
---
name: Other Issue
about: Ask your question, if it's not a bug or feature request
title: ''
labels: ''
assignees: ''
---
**Environment (please complete the following information):**
- PHP IMAP version: [e.g. 3.0.11]
- PHP Version: [e.g. 7.1.26]
- Type of execution: [e.g. Daemon / CLI or Web Server]
**Your Text**
A clear and concise description of what you want.

View File

@@ -0,0 +1,16 @@
**Describe the change(s)**
A clear and concise description of what you changed and why you changed it.
**Example code to use new / updated methods**
```php
$mailbox = new Mailbox(...
```
---
Make sure, that these boxes are checked before creating your pull request:
- [ ] A short description of this change is provided
- [ ] A short example code is provided, if possible
- [ ] PHPUnit tests for your changes exists

View File

@@ -0,0 +1,53 @@
name: PHP Code Coverage
on:
push:
branches:
- master
pull_request:
jobs:
coverage:
name: Coverage
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: ['ubuntu-20.04']
php-versions: ['8.1']
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
coverage: xdebug
- uses: actions/checkout@v2
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache Files
uses: actions/cache@v2
with:
path: |
${{ steps.composer-cache.outputs.dir }}
**/.php_cs.cache
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run tests
uses: paambaati/codeclimate-action@v2.7.2
env:
CC_TEST_REPORTER_ID: "945dfb58a832d233a3caeb84e3e6d3be212e8c7abcb48117fce63b9adcb43647"
with:
coverageCommand: ./vendor/bin/phpunit --testdox --stop-on-failure --coverage-clover=clover.xml

View File

@@ -0,0 +1,50 @@
name: PHP Static Analysis & Tests
on:
push:
branches:
- master
pull_request:
jobs:
static-analysis:
name: Static Analysis PHP ${{ matrix.php-versions }}
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: ['ubuntu-20.04']
php-versions: ['7.4', '8.0', '8.1']
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
coverage: none
- uses: actions/checkout@v2
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache Files
uses: actions/cache@v2
with:
path: |
${{ steps.composer-cache.outputs.dir }}
**/.php_cs.cache
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run static analysis
run: composer run static-analysis

View File

@@ -0,0 +1,50 @@
name: PHP Unit Tests
on:
push:
branches:
- master
pull_request:
jobs:
phpunit:
name: PHP ${{ matrix.php-versions }} Unit Tests
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: ['ubuntu-20.04']
php-versions: ['7.4', '8.0', '8.1']
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
coverage: none
- uses: actions/checkout@v2
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache Files
uses: actions/cache@v2
with:
path: |
${{ steps.composer-cache.outputs.dir }}
**/.php_cs.cache
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run tests
run: ./vendor/bin/phpunit --testdox --stop-on-failure

View File

@@ -1,3 +1,11 @@
# All of the vendor directory should be installed by running 'composer install'
vendor/
composer.lock
*.phar
.php-cs-fixer.cache
coverage/
psalm/cache/
################# #################
## Eclipse ## Eclipse
################# #################
@@ -153,6 +161,7 @@ pip-log.txt
# Unit test / coverage reports # Unit test / coverage reports
.coverage .coverage
.tox .tox
clover.xml
#Translations #Translations
*.mo *.mo
@@ -162,3 +171,9 @@ pip-log.txt
# Mac crap # Mac crap
.DS_Store .DS_Store
# NetBeans IDE
nbproject/
# Visual Studio Code
.vscode/

View File

@@ -0,0 +1,39 @@
<?php
/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0.0-rc.1|configurator
* you can change this configuration by importing this file.
*/
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHP71Migration' => true, // @PHP72Migration does not exist
'@PHP71Migration:risky' => true, // @PHP72Migration:risky does not exist
'array_syntax' => ['syntax' => 'short'],
'declare_strict_types' => true,
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => true,
'import_functions' => false,
],
'native_constant_invocation' => true,
'native_function_invocation' => [
'strict' => false,
'include' => ['@compiler_optimized'],
],
'no_superfluous_phpdoc_tags' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_method_casing' => true,
'php_unit_test_case_static_method_calls' => ['call_type' => 'this'],
'phpdoc_to_comment' => false,
'void_return' => true,
])
->setFinder(PhpCsFixer\Finder::create()
->exclude('vendor')
->in(__DIR__)
)
;

View File

@@ -1,32 +1,21 @@
ImapMailbox The MIT License (MIT)
Copyright (c) 2012 by Barbushin Sergey <barbushin@gmail.com>. Copyright (c) 2012 Sergey Barbushin <barbushin@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without Permission is hereby granted, free of charge, to any person obtaining a copy
modification, are permitted provided that the following conditions are of this software and associated documentation files (the "Software"), to deal
met: in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
* Redistributions of source code must retain the above copyright The above copyright notice and this permission notice shall be included in
notice, this list of conditions and the following disclaimer. all copies or substantial portions of the Software.
* Redistributions in binary form must reproduce the above THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
copyright notice, this list of conditions and the following IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
disclaimer in the documentation and/or other materials provided FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
with the distribution. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* The names of the contributors may not be used to endorse or OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
promote products derived from this software without specific THE SOFTWARE.
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,50 +1,190 @@
ImapMailbox is PHP class to access mailbox by POP3/IMAP/NNTP using IMAP extension # PHP IMAP
[![GitHub release](https://img.shields.io/github/release/barbushin/php-imap.svg?style=flat-square)](https://packagist.org/packages/php-imap/php-imap)
[![Supported PHP Version](https://img.shields.io/packagist/php-v/php-imap/php-imap.svg)](README.md)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
[![Packagist](https://img.shields.io/packagist/dt/php-imap/php-imap.svg?style=flat-square)](https://packagist.org/packages/php-imap/php-imap)
[![CI PHP Unit Tests](https://github.com/barbushin/php-imap/actions/workflows/php_unit_tests.yml/badge.svg?branch=master)](https://github.com/barbushin/php-imap/actions/workflows/php_unit_tests.yml)
[![CI PHP Static Analysis](https://github.com/barbushin/php-imap/actions/workflows/php_static_analysis.yml/badge.svg?branch=master)](https://github.com/barbushin/php-imap/actions/workflows/php_static_analysis.yml)
[![CI PHP Code Coverage](https://github.com/barbushin/php-imap/actions/workflows/php_code_coverage.yml/badge.svg?branch=master)](https://github.com/barbushin/php-imap/actions/workflows/php_code_coverage.yml)
[![Maintainability](https://api.codeclimate.com/v1/badges/02f72a4fd695cb7e2976/maintainability)](https://codeclimate.com/github/barbushin/php-imap/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/02f72a4fd695cb7e2976/test_coverage)](https://codeclimate.com/github/barbushin/php-imap/test_coverage)
[![Type Coverage](https://shepherd.dev/github/barbushin/php-imap/coverage.svg)](https://shepherd.dev/github/barbushin/php-imap)
Initially released in December 2012, the PHP IMAP Mailbox is a powerful and open source library to connect to a mailbox by POP3, IMAP and NNTP using the PHP IMAP extension. This library allows you to fetch emails from your email server. Extend the functionality or create powerful web applications to handle your incoming emails.
### Features ### Features
* Connect to mailbox by POP3/IMAP/NNTP (see [imap_open](http://php.net/imap_open)) * Connect to mailbox by POP3/IMAP/NNTP, using [PHP IMAP extension](http://php.net/manual/book.imap.php)
* Get mailbox status (see [imap_check](http://php.net/imap_check)) * Get emails with attachments and inline images
* Receive emails (+attachments, +html body images) * Get emails filtered or sorted by custom criteria
* Search emails by custom criteria (see [imap_search](http://php.net/imap_search)) * Mark emails as seen/unseen
* Change email status (see [imap_setflag_full](http://php.net/imap_setflag_full)) * Delete emails
* Delete email * Manage mailbox folders
### Requirements
| PHP Version | php-imap Version | php-imap status |
| ------------- | ------------- | ------------- |
| 5.6 | 3.x | End of life |
| 7.0 | 3.x | End of life |
| 7.1 | 3.x | End of life |
| 7.2 | 3.x, 4.x | End of life |
| 7.3 | 3.x, 4.x | End of life |
| 7.4 | >3.0.33, 4.x, 5.x | Active support |
| 8.0 | >3.0.33, 4.x, 5.x | Active support |
| 8.1 | >4.3.0, 5.x | Active support |
* PHP `fileinfo` extension must be present; so make sure this line is active in your php.ini: `extension=php_fileinfo.dll`
* PHP `iconv` extension must be present; so make sure this line is active in your php.ini: `extension=php_iconv.dll`
* PHP `imap` extension must be present; so make sure this line is active in your php.ini: `extension=php_imap.dll`
* PHP `mbstring` extension must be present; so make sure this line is active in your php.ini: `extension=php_mbstring.dll`
* PHP `json` extension must be present; so make sure this line is active in your php.ini: `extension=json.dll`
### Installation by Composer ### Installation by Composer
{ Install the [latest available release](https://github.com/barbushin/php-imap/releases):
"require": {
"php-imap/php-imap": "~2.0"
}
}
Or $ composer require php-imap/php-imap
$ composer require php-imap/php-imap ~2.0 Install the latest available and stable source code from `master`, which is may not released / tagged yet:
### Migration from `v1.*` to `v2.*` $ composer require php-imap/php-imap:dev-master
Just add following code in the head of your script: ### Run Tests
use PhpImap\Mailbox as ImapMailbox; Before you can run the any tests you may need to run `composer install` to install all (development) dependencies.
use PhpImap\IncomingMail;
use PhpImap\IncomingMailAttachment;
### [Usage example](https://github.com/barbushin/php-imap/blob/master/example/index.php) #### Run all tests
You can run all available tests by running the following command (inside of the installed `php-imap` directory): `composer run tests`
#### Run only PHPUnit tests
You can run all PHPUnit tests by running the following command (inside of the installed `php-imap` directory): `php vendor/bin/phpunit --testdox`
### Integration with frameworks
* Symfony - https://github.com/secit-pl/imap-bundle
### Getting Started Example
Below, you'll find an example code how you can use this library. For further information and other examples, you may take a look at the [wiki](https://github.com/barbushin/php-imap/wiki).
By default, this library uses random filenames for attachments as identical file names from other emails would overwrite other attachments. If you want to keep the original file name, you can set the attachment filename mode to ``true``, but then you also need to ensure, that those files don't get overwritten by other emails for example.
```php ```php
$mailbox = new PhpImap\Mailbox('{imap.gmail.com:993/imap/ssl}INBOX', 'some@gmail.com', '*********', __DIR__); // Create PhpImap\Mailbox instance for all further actions
$mails = array(); $mailbox = new PhpImap\Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********', // Password for the before configured username
__DIR__, // Directory, where attachments will be saved (optional)
'UTF-8', // Server encoding (optional)
true, // Trim leading/ending whitespaces of IMAP path (optional)
false // Attachment filename mode (optional; false = random filename; true = original filename)
);
$mailsIds = $mailbox->searchMailBox('ALL'); // set some connection arguments (if appropriate)
$mailbox->setConnectionArgs(
CL_EXPUNGE // expunge deleted mails upon mailbox close
| OP_SECURE // don't do non-secure authentication
);
try {
// Get all emails (messages)
// PHP.net imap_search criteria: http://php.net/manual/en/function.imap-search.php
$mailsIds = $mailbox->searchMailbox('ALL');
} catch(PhpImap\Exceptions\ConnectionException $ex) {
echo "IMAP connection failed: " . implode(",", $ex->getErrors('all'));
die();
}
// If $mailsIds is empty, no emails could be found
if(!$mailsIds) { if(!$mailsIds) {
die('Mailbox is empty'); die('Mailbox is empty');
} }
$mailId = reset($mailsIds); // Get the first message
$mail = $mailbox->getMail($mailId); // If '__DIR__' was defined in the first line, it will automatically
// save all attachments to the specified directory
$mail = $mailbox->getMail($mailsIds[0]);
var_dump($mail); // Show, if $mail has one or more attachments
var_dump($mail->getAttachments()); echo "\nMail has attachments? ";
if($mail->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}
// Print all information of $mail
print_r($mail);
// Print all attachements of $mail
echo "\n\nAttachments:\n";
print_r($mail->getAttachments());
```
Method `imap()` allows to call any [PHP IMAP function](https://www.php.net/manual/ref.imap.php) in a context of the instance. Example:
```php
// Call imap_check() - see http://php.net/manual/function.imap-check.php
$info = $mailbox->imap('check');
// Show current time for the mailbox
$currentServerTime = isset($info->Date) && $info->Date ? date('Y-m-d H:i:s', strtotime($info->Date)) : 'Unknown';
echo $currentServerTime;
```
Some request require much time and resources:
```php
// If you don't need to grab attachments you can significantly increase performance of your application
$mailbox->setAttachmentsIgnore(true);
// get the list of folders/mailboxes
$folders = $mailbox->getMailboxes('*');
// loop through mailboxs
foreach($folders as $folder) {
// switch to particular mailbox
$mailbox->switchMailbox($folder['fullpath']);
// search in particular mailbox
$mails_ids[$folder['fullpath']] = $mailbox->searchMailbox('SINCE "1 Jan 2018" BEFORE "28 Jan 2018"');
}
print_r($mails_ids);
```
### Upgrading from 3.x
Prior to 3.1, `Mailbox` used a "magic" method (`Mailbox::imap()`), with the
class `Imap` now performing it's purpose to call many `imap_*` functions with
automated string encoding/decoding of arguments and return values:
Before:
```php
public function checkMailbox()
{
return $this->imap('check');
}
```
After:
```php
public function checkMailbox(): object
{
return Imap::check($this->getImapStream());
}
``` ```
### Recommended ### Recommended

View File

@@ -0,0 +1,18 @@
{
"symbol-whitelist" : [
"null", "true", "false",
"static", "self", "parent",
"array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "mixed", "never",
"IMAP\\Connection"
],
"php-core-extensions" : [
"Core",
"date",
"pcre",
"Phar",
"Reflection",
"SPL",
"standard"
],
"scan-files" : []
}

View File

@@ -1,28 +1,72 @@
{ {
"name": "php-imap/php-imap", "name": "php-imap/php-imap",
"description": "PHP class to access mailbox by POP3/IMAP/NNTP using IMAP extension", "description": "Manage mailboxes, filter/get/delete emails in PHP (supports IMAP/POP3/NNTP)",
"keywords": [ "keywords": [
"PHP", "PHP",
"IMAP", "mail",
"mail" "IMAP",
], "POP3",
"homepage": "https://github.com/barbushin/php-imap", "mailbox",
"license": "BSD 3-Clause", "receive emails"
"type": "library", ],
"authors": [ "homepage": "https://github.com/barbushin/php-imap",
{ "license": "MIT",
"name": "Sergey Barbushin", "type": "library",
"homepage": "http://linkedin.com/in/barbushin", "authors": [
"email": "barbushin@gmail.com" {
} "name": "Sergey Barbushin",
], "homepage": "http://linkedin.com/in/barbushin",
"require": { "email": "barbushin@gmail.com"
"php": ">=5.3.0" }
}, ],
"autoload": { "config": {
"psr-0": { "sort-packages": true
"PhpImap": "src/" },
} "require": {
}, "php": "^7.4 || ^8.0",
"minimum-stability": "stable" "ext-fileinfo": "*",
"ext-iconv": "*",
"ext-imap": "*",
"ext-mbstring": "*",
"ext-json": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.4",
"maglnet/composer-require-checker": "^2.0|^3.2",
"nikic/php-parser": "^4.3,<4.7|^4.10",
"paragonie/hidden-string": "^1.0",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpunit/phpunit": "^8.5|^9.5",
"povils/phpmnd": "^2.2",
"psalm/plugin-phpunit": "^0.10.0|^0.15.1",
"roave/security-advisories": "dev-master",
"sebastian/phpcpd": "^4.1|^6.0"
},
"scripts": {
"static-analysis": [
"parallel-lint .php-cs-fixer.dist.php src tests examples",
"phpcpd src tests",
"composer-require-checker check --config-file=composer-require-checker.config.json ./composer.json",
"phpmnd ./ --exclude=./.github/ --exclude=./examples/ --exclude=./vendor/ --non-zero-exit-on-violation --hint",
"php-cs-fixer fix --allow-risky=yes --no-interaction --dry-run -v",
"psalm --show-info=false"
],
"tests": [
"@static-analysis",
"phpunit --testdox"
]
},
"suggest": {
"ext-fileinfo": "To facilitate IncomingMailAttachment::getFileInfo() auto-detection"
},
"autoload-dev": {
"psr-4": {
"PhpImap\\": "tests/unit"
}
},
"autoload": {
"psr-4": {
"PhpImap\\": "src/PhpImap"
}
}
} }

View File

@@ -0,0 +1,74 @@
<?php
/**
* Example: Get and parse all emails which match the subject "part of the subject" with saving their attachments.
*
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use PhpImap\Exceptions\ConnectionException;
use PhpImap\Mailbox;
$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********', // Password for the before configured username
__DIR__, // Directory, where attachments will be saved (optional)
'US-ASCII' // Server encoding (optional)
);
try {
$mail_ids = $mailbox->searchMailbox('SUBJECT "part of the subject"');
} catch (ConnectionException $ex) {
exit('IMAP connection failed: '.$ex->getMessage());
} catch (Exception $ex) {
exit('An error occured: '.$ex->getMessage());
}
foreach ($mail_ids as $mail_id) {
echo "+------ P A R S I N G ------+\n";
$email = $mailbox->getMail(
$mail_id, // ID of the email, you want to get
false // Do NOT mark emails as seen (optional)
);
echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n";
echo 'from-email: '.(string) $email->fromAddress."\n";
echo 'to: '.(string) $email->toString."\n";
echo 'subject: '.(string) $email->subject."\n";
echo 'message_id: '.(string) $email->messageId."\n";
echo 'mail has attachments? ';
if ($email->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}
if (!empty($email->getAttachments())) {
echo \count($email->getAttachments())." attachements\n";
}
if ($email->textHtml) {
echo "Message HTML:\n".$email->textHtml;
} else {
echo "Message Plain:\n".$email->textPlain;
}
if (!empty($email->autoSubmitted)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Auto-Reply ------+\n";
}
if (!empty($email_content->precedence)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Non-Delivery Report/Receipt ------+\n";
}
}
$mailbox->disconnect();

View File

@@ -0,0 +1,84 @@
<?php
/**
* Example: Get and parse all emails without saving their attachments.
*
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use PhpImap\Exceptions\ConnectionException;
use PhpImap\Mailbox;
$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********', // Password for the before configured username
null, // Directory, where attachments will be saved (optional)
'US-ASCII' // Server encoding (optional)
);
// OR
$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********' // Password for the before configured username
);
// If you haven't defined the server encoding (charset) in 'new Mailbox()', you can change it any time
$mailbox->setServerEncoding('US-ASCII');
try {
$mail_ids = $mailbox->searchMailbox('UNSEEN');
} catch (ConnectionException $ex) {
exit('IMAP connection failed: '.$ex->getMessage());
} catch (Exception $ex) {
exit('An error occured: '.$ex->getMessage());
}
foreach ($mail_ids as $mail_id) {
echo "+------ P A R S I N G ------+\n";
$email = $mailbox->getMail(
$mail_id, // ID of the email, you want to get
false // Do NOT mark emails as seen (optional)
);
echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n";
echo 'from-email: '.(string) $email->fromAddress."\n";
echo 'to: '.(string) $email->toString."\n";
echo 'subject: '.(string) $email->subject."\n";
echo 'message_id: '.(string) $email->messageId."\n";
echo 'mail has attachments? ';
if ($email->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}
if (!empty($email->getAttachments())) {
echo \count($email->getAttachments())." attachements\n";
}
if ($email->textHtml) {
echo "Message HTML:\n".$email->textHtml;
} else {
echo "Message Plain:\n".$email->textPlain;
}
if (!empty($email->autoSubmitted)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Auto-Reply ------+\n";
}
if (!empty($email_content->precedence)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Non-Delivery Report/Receipt ------+\n";
}
}
$mailbox->disconnect();

View File

@@ -0,0 +1,74 @@
<?php
/**
* Example: Get and parse all unseen emails with saving their attachments.
*
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use PhpImap\Exceptions\ConnectionException;
use PhpImap\Mailbox;
$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********', // Password for the before configured username
__DIR__, // Directory, where attachments will be saved (optional)
'US-ASCII' // Server encoding (optional)
);
try {
$mail_ids = $mailbox->searchMailbox('UNSEEN');
} catch (ConnectionException $ex) {
exit('IMAP connection failed: '.$ex->getErrors('first'));
} catch (Exception $ex) {
exit('An error occured: '.$ex->getMessage());
}
foreach ($mail_ids as $mail_id) {
echo "+------ P A R S I N G ------+\n";
$email = $mailbox->getMail(
$mail_id, // ID of the email, you want to get
false // Do NOT mark emails as seen (optional)
);
echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n";
echo 'from-email: '.(string) $email->fromAddress."\n";
echo 'to: '.(string) $email->toString."\n";
echo 'subject: '.(string) $email->subject."\n";
echo 'message_id: '.(string) $email->messageId."\n";
echo 'mail has attachments? ';
if ($email->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}
if (!empty($email->getAttachments())) {
echo \count($email->getAttachments())." attachements\n";
}
if ($email->textHtml) {
echo "Message HTML:\n".$email->textHtml;
} else {
echo "Message Plain:\n".$email->textPlain;
}
if (!empty($email->autoSubmitted)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Auto-Reply ------+\n";
}
if (!empty($email_content->precedence)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Non-Delivery Report/Receipt ------+\n";
}
}
$mailbox->disconnect();

View File

@@ -0,0 +1,92 @@
<?php
/**
* Example: Get and parse all unseen emails with saving their attachments one by one.
*
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use PhpImap\Exceptions\ConnectionException;
use PhpImap\Mailbox;
$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********' // Password for the before configured username
);
try {
$mail_ids = $mailbox->searchMailbox('UNSEEN');
} catch (ConnectionException $ex) {
exit('IMAP connection failed: '.$ex->getMessage());
} catch (Exception $ex) {
exit('An error occured: '.$ex->getMessage());
}
foreach ($mail_ids as $mail_id) {
echo "+------ P A R S I N G ------+\n";
$email = $mailbox->getMail(
$mail_id, // ID of the email, you want to get
false // Do NOT mark emails as seen (optional)
);
echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n";
echo 'from-email: '.(string) $email->fromAddress."\n";
echo 'to: '.(string) $email->toString."\n";
echo 'subject: '.(string) $email->subject."\n";
echo 'message_id: '.(string) $email->messageId."\n";
echo 'mail has attachments? ';
if ($email->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}
if (!empty($email->getAttachments())) {
echo \count($email->getAttachments())." attachements\n";
}
// Save attachments one by one
if (!$mailbox->getAttachmentsIgnore()) {
$attachments = $email->getAttachments();
foreach ($attachments as $attachment) {
echo '--> Saving '.(string) $attachment->name.'...';
// Set individually filePath for each single attachment
// In this case, every file will get the current Unix timestamp
$attachment->setFilePath(__DIR__.'/files/'.\time());
if ($attachment->saveToDisk()) {
echo "OK, saved!\n";
} else {
echo "ERROR, could not save!\n";
}
}
}
if ($email->textHtml) {
echo "Message HTML:\n".$email->textHtml;
} else {
echo "Message Plain:\n".$email->textPlain;
}
if (!empty($email->autoSubmitted)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Auto-Reply ------+\n";
}
if (!empty($email_content->precedence)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Non-Delivery Report/Receipt ------+\n";
}
}
$mailbox->disconnect();

27
vendor/php-imap/php-imap/phpunit.xml vendored Normal file
View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
verbose="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
colors="true"
forceCoversAnnotation="false"
processIsolation="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory>src</directory>
</include>
</coverage>
<testsuites>
<testsuite name="php-imap Tests">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="3.12.2@7c7ebd068f8acaba211d4a2c707c4ba90874fa26">
<file src="examples/get_and_parse_all_emails_without_saving_attachments.php">
<UnusedVariable occurrences="1">
<code>$mailbox</code>
</UnusedVariable>
</file>
<file src="src/PhpImap/Imap.php">
<DocblockTypeContradiction occurrences="3">
<code>\is_int($section)</code>
<code>!\is_string($section) &amp;&amp; !\is_int($section)</code>
<code>\is_resource($maybe)</code>
</DocblockTypeContradiction>
</file>
<file src="src/PhpImap/Mailbox.php">
<DocblockTypeContradiction occurrences="2">
<code>\in_array($imapSearchOption, $supported_options, true)</code>
<code>\in_array($key, $supported_params, true)</code>
</DocblockTypeContradiction>
<InvalidArgument occurrences="3">
<code>$element-&gt;charset</code>
<code>$element-&gt;text</code>
<code>$element-&gt;text</code>
</InvalidArgument>
<PossiblyUnusedMethod occurrences="24">
<code>setConnectionRetry</code>
<code>setConnectionRetryDelay</code>
<code>setExpungeOnDisconnect</code>
<code>renameMailbox</code>
<code>getListingFolders</code>
<code>searchMailboxFrom</code>
<code>searchMailboxFromDisableServerEncoding</code>
<code>searchMailboxMergeResults</code>
<code>searchMailboxMergeResultsDisableServerEncoding</code>
<code>saveMail</code>
<code>moveMail</code>
<code>copyMail</code>
<code>markMailAsUnread</code>
<code>markMailAsImportant</code>
<code>markMailsAsRead</code>
<code>markMailsAsUnread</code>
<code>markMailsAsImportant</code>
<code>getMailboxHeaders</code>
<code>getMailboxInfo</code>
<code>getQuotaLimit</code>
<code>getQuotaUsage</code>
<code>getSubscribedMailboxes</code>
<code>subscribeMailbox</code>
<code>unsubscribeMailbox</code>
</PossiblyUnusedMethod>
</file>
<file src="tests/unit/MailboxTest.php">
<InvalidArgument occurrences="1">
<code>self::ANYTHING</code>
</InvalidArgument>
</file>
</files>

37
vendor/php-imap/php-imap/psalm.xml vendored Normal file
View File

@@ -0,0 +1,37 @@
<?xml version="1.0"?>
<psalm
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
name="Psalm for php-imap"
useDocblockTypes="true"
errorLevel="1"
strictBinaryOperands="false"
rememberPropertyAssignmentsAfterCall="true"
checkForThrowsDocblock="false"
throwExceptionOnError="0"
findUnusedCode="false"
ensureArrayStringOffsetsExist="true"
ensureArrayIntOffsetsExist="true"
resolveFromConfigFile="true"
xsi:schemaLocation="https://getpsalm.org/schema/config config.xsd"
limitMethodComplexity="true"
errorBaseline="./psalm.baseline.xml"
cacheDirectory="./psalm/cache/"
findUnusedPsalmSuppress="true"
>
<projectFiles>
<file name="./.php-cs-fixer.dist.php"/>
<directory name="src"/>
<ignoreFiles>
<directory name="tests"/>
<directory name="examples"/>
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
<issueHandlers>
</issueHandlers>
<plugins>
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
</plugins>
</psalm>

View File

@@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
namespace PhpImap;
use const ENC8BIT;
use const ENCBASE64;
use const ENCBINARY;
use const ENCQUOTEDPRINTABLE;
/**
* @see https://github.com/barbushin/php-imap
*
* @author nickl- http://github.com/nickl-
*/
class DataPartInfo
{
public const TEXT_PLAIN = 0;
public const TEXT_HTML = 1;
/**
* @var int
*
* @readonly
*/
public $id;
/**
* @var int|mixed
*
* @readonly
*/
public $encoding;
/** @var string|null */
public $charset;
/**
* @var 0|string
*
* @readonly
*/
public $part;
/**
* @var Mailbox
*
* @readonly
*/
public $mail;
/**
* @var int
*
* @readonly
*/
public $options;
/** @var string|null */
protected $data;
/**
* @param 0|string $part
* @param int|mixed $encoding
*/
public function __construct(Mailbox $mail, int $id, $part, $encoding, int $options)
{
$this->mail = $mail;
$this->id = $id;
$this->part = $part;
$this->encoding = $encoding;
$this->options = $options;
}
public function fetch(): string
{
if (0 === $this->part) {
$this->data = Imap::body($this->mail->getImapStream(), $this->id, $this->options);
} else {
if (null !== $this->data) {
return $this->data;
}
$this->data = Imap::fetchbody($this->mail->getImapStream(), $this->id, $this->part, $this->options);
}
return $this->decodeAfterFetch($this->data);
}
public function decodeAfterFetch(string $data): string
{
switch ($this->encoding) {
case ENC8BIT:
$this->data = \imap_utf8((string) $data);
break;
case ENCBINARY:
$this->data = \imap_binary((string) $data);
break;
case ENCBASE64:
$this->data = \base64_decode((string) $data, false);
break;
case ENCQUOTEDPRINTABLE:
$this->data = \quoted_printable_decode((string) $data);
break;
}
return $this->convertEncodingAfterFetch();
}
protected function convertEncodingAfterFetch(): string
{
if (isset($this->charset) && !empty(\trim($this->charset))) {
$this->data = $this->mail->decodeMimeStr(
(string) $this->data // Data to convert
);
$this->data = $this->mail->convertToUtf8(
$this->data,
$this->charset
);
}
return (null === $this->data) ? '' : $this->data;
}
}

View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace PhpImap\Exceptions;
use Exception;
/**
* @see https://github.com/barbushin/php-imap
*
* @author Barbushin Sergey http://linkedin.com/in/barbushin
*/
class ConnectionException extends Exception
{
public function __construct(array $message, int $code = 0, Exception $previous = null)
{
parent::__construct(json_encode($message), $code, $previous);
}
public function getErrors(string $select = 'first')
{
$message = $this->getMessage();
switch (strtolower($select)) {
case 'all':
return json_decode($message);
break;
default:
case 'first':
$message = json_decode($message);
return $message[0];
break;
case 'last':
$message = json_decode($message);
return $message[\count($message) - 1];
break;
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace PhpImap\Exceptions;
use Exception;
/**
* @see https://github.com/barbushin/php-imap
*
* @author Barbushin Sergey http://linkedin.com/in/barbushin
*/
class InvalidParameterException extends Exception
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,65 +1,247 @@
<?php namespace PhpImap; <?php
declare(strict_types=1);
namespace PhpImap;
use const FILEINFO_MIME_TYPE;
use InvalidArgumentException;
/** /**
* @see https://github.com/barbushin/php-imap * The PhpImap IncomingMail class.
*
* @author Barbushin Sergey http://linkedin.com/in/barbushin * @author Barbushin Sergey http://linkedin.com/in/barbushin
*
* @see https://github.com/barbushin/php-imap
*
* @property string $textPlain lazy plain message body
* @property string $textHtml lazy html message body
*/ */
class IncomingMail { class IncomingMail extends IncomingMailHeader
{
/**
* @var IncomingMailAttachment[]
*/
protected $attachments = [];
public $id; /** @var bool */
public $date; protected $hasAttachments = false;
public $subject;
public $fromName; /**
public $fromAddress; * @var DataPartInfo[][]
*
* @psalm-var array{0:list<DataPartInfo>, 1:list<DataPartInfo>}
*/
protected $dataInfo = [[], []];
public $to = array(); /** @var string|null */
public $toString; private $textPlain;
public $cc = array();
public $replyTo = array();
public $messageId; /** @var string|null */
private $textHtml;
public $textPlain; /**
public $textHtml; * __get() is utilized for reading data from inaccessible (protected
/** @var IncomingMailAttachment[] */ * or private) or non-existing properties.
protected $attachments = array(); *
* @param string $name Name of the property (eg. textPlain)
*
* @return string Value of the property (eg. Plain text message)
*/
public function __get(string $name): string
{
$type = false;
if ('textPlain' == $name) {
$type = DataPartInfo::TEXT_PLAIN;
}
if ('textHtml' == $name) {
$type = DataPartInfo::TEXT_HTML;
}
if (('textPlain' === $name || 'textHtml' === $name) && isset($this->$name)) {
return (string) $this->$name;
}
if (false === $type) {
\trigger_error("Undefined property: IncomingMail::$name");
}
if (!isset($this->$name)) {
$this->$name = '';
}
foreach ($this->dataInfo[$type] as $data) {
$this->$name .= \trim($data->fetch());
}
public function addAttachment(IncomingMailAttachment $attachment) { /** @var string */
$this->attachments[$attachment->id] = $attachment; return $this->$name;
} }
/** /**
* @return IncomingMailAttachment[] * The method __isset() is triggered by calling isset() or empty()
*/ * on inaccessible (protected or private) or non-existing properties.
public function getAttachments() { *
return $this->attachments; * @param string $name Name of the property (eg. textPlain)
} *
* @return bool True, if property is set or empty
*/
public function __isset(string $name): bool
{
self::__get($name);
/** return isset($this->$name);
* Get array of internal HTML links placeholders }
* @return array attachmentId => link placeholder
*/
public function getInternalLinksPlaceholders() {
return preg_match_all('/=["\'](ci?d:([\w\.%*@-]+))["\']/i', $this->textHtml, $matches) ? array_combine($matches[2], $matches[1]) : array();
} public function setHeader(IncomingMailHeader $header): void
{
/** @psalm-var array<string, scalar|array|object|null> */
$array = \get_object_vars($header);
foreach ($array as $property => $value) {
$this->$property = $value;
}
}
public function replaceInternalLinks($baseUri) { /**
$baseUri = rtrim($baseUri, '\\/') . '/'; * @param DataPartInfo::TEXT_PLAIN|DataPartInfo::TEXT_HTML $type
$fetchedHtml = $this->textHtml; */
foreach($this->getInternalLinksPlaceholders() as $attachmentId => $placeholder) { public function addDataPartInfo(DataPartInfo $dataInfo, int $type): void
if(isset($this->attachments[$attachmentId])) { {
$fetchedHtml = str_replace($placeholder, $baseUri . basename($this->attachments[$attachmentId]->filePath), $fetchedHtml); $this->dataInfo[$type][] = $dataInfo;
} }
}
return $fetchedHtml; public function addAttachment(IncomingMailAttachment $attachment): void
} {
} if (!\is_string($attachment->id)) {
throw new InvalidArgumentException('Argument 1 passed to '.__METHOD__.'() does not have an id specified!');
class IncomingMailAttachment { }
$this->attachments[$attachment->id] = $attachment;
public $id;
public $name; $this->setHasAttachments(true);
public $filePath; }
/**
* Sets property $hasAttachments.
*
* @param bool $hasAttachments True, if IncomingMail[] has one or more attachments
*/
public function setHasAttachments(bool $hasAttachments): void
{
$this->hasAttachments = $hasAttachments;
}
/**
* Returns, if the mail has attachments or not.
*
* @return bool true or false
*/
public function hasAttachments(): bool
{
return $this->hasAttachments;
}
/**
* @return IncomingMailAttachment[]
*/
public function getAttachments(): array
{
return $this->attachments;
}
/**
* @param string $id The attachment id
*/
public function removeAttachment(string $id): bool
{
if (!isset($this->attachments[$id])) {
return false;
}
unset($this->attachments[$id]);
$this->setHasAttachments([] !== $this->attachments);
return true;
}
/**
* Get array of internal HTML links placeholders.
*
* @return array attachmentId => link placeholder
*
* @psalm-return array<string, string>
*/
public function getInternalLinksPlaceholders(): array
{
$fetchedHtml = $this->__get('textHtml');
$match = \preg_match_all('/=["\'](ci?d:([\w\.%*@-]+))["\']/i', $fetchedHtml, $matches);
/** @psalm-var array{1:list<string>, 2:list<string>} */
$matches = $matches;
return $match ? \array_combine($matches[2], $matches[1]) : [];
}
public function replaceInternalLinks(string $baseUri): string
{
$baseUri = \rtrim($baseUri, '\\/').'/';
$fetchedHtml = $this->textHtml;
$search = [];
$replace = [];
foreach ($this->getInternalLinksPlaceholders() as $attachmentId => $placeholder) {
foreach ($this->attachments as $attachment) {
if ($attachment->contentId == $attachmentId) {
if (!\is_string($attachment->id)) {
throw new InvalidArgumentException('Argument 1 passed to '.__METHOD__.'() does not have an id specified!');
}
$search[] = $placeholder;
$replace[] = $baseUri.\basename($this->attachments[$attachment->id]->filePath);
}
}
}
/** @psalm-var string */
return \str_replace($search, $replace, $fetchedHtml);
}
/**
* Embed inline image attachments as base64 to allow for
* email html to display inline images automatically.
*/
public function embedImageAttachments(): void
{
$fetchedHtml = $this->__get('textHtml');
\preg_match_all("/\bcid:[^'\"\s]{1,256}/mi", $fetchedHtml, $matches);
if (isset($matches[0]) && \is_array($matches[0]) && \count($matches[0])) {
/** @var list<string> */
$matches = $matches[0];
$attachments = $this->getAttachments();
foreach ($matches as $match) {
$cid = \str_replace('cid:', '', $match);
foreach ($attachments as $attachment) {
/**
* Inline images can contain a "Content-Disposition: inline", but only a "Content-ID" is also enough.
* See https://github.com/barbushin/php-imap/issues/569.
*/
if ($attachment->contentId == $cid || 'inline' == \mb_strtolower((string) $attachment->disposition)) {
$contents = $attachment->getContents();
$contentType = $attachment->getFileInfo(FILEINFO_MIME_TYPE);
if (!\strstr($contentType, 'image')) {
continue;
} elseif (!\is_string($attachment->id)) {
throw new InvalidArgumentException('Argument 1 passed to '.__METHOD__.'() does not have an id specified!');
}
$base64encoded = \base64_encode($contents);
$replacement = 'data:'.$contentType.';base64, '.$base64encoded;
$this->textHtml = \str_replace($match, $replacement, $this->textHtml);
$this->removeAttachment($attachment->id);
}
}
}
}
}
} }

View File

@@ -0,0 +1,169 @@
<?php
declare(strict_types=1);
namespace PhpImap;
use const FILEINFO_NONE;
use finfo;
use UnexpectedValueException;
/**
* @see https://github.com/barbushin/php-imap
*
* @author Barbushin Sergey http://linkedin.com/in/barbushin
*
* @property string|false|null $filePath lazy attachment data file
*
* @psalm-type fileinfoconst = 0|2|16|1024|1040|8|32|128|256|16777216
*/
class IncomingMailAttachment
{
/** @var string|null */
public $id;
/** @var string|null */
public $contentId;
/** @var int|null */
public $type;
/** @var int|null */
public $encoding;
/** @var string|null */
public $subtype;
/** @var string|null */
public $description;
/** @var string|null */
public $name;
/** @var int|null */
public $sizeInBytes;
/** @var string|null */
public $disposition;
/** @var string|null */
public $charset;
/** @var bool|null */
public $emlOrigin;
/** @var string|null */
public $fileInfoRaw;
/** @var string|null */
public $fileInfo;
/** @var string|null */
public $mime;
/** @var string|null */
public $mimeEncoding;
/** @var string|null */
public $fileExtension;
/** @var string|null */
public $mimeType;
/** @var string|null */
private $file_path;
/** @var DataPartInfo|null */
private $dataInfo;
/** @var string|null */
private $filePath;
/**
* @return false|string
*/
public function __get(string $name)
{
if ('filePath' !== $name) {
\trigger_error("Undefined property: IncomingMailAttachment::$name");
}
if (!isset($this->file_path)) {
return false;
}
$this->filePath = $this->file_path;
if (@\file_exists($this->file_path)) {
return $this->filePath;
}
return $this->filePath;
}
/**
* Sets the file path.
*
* @param string $filePath File path incl. file name and optional extension
*/
public function setFilePath(string $filePath): void
{
$this->file_path = $filePath;
}
/**
* Sets the data part info.
*
* @param DataPartInfo $dataInfo Date info (file content)
*/
public function addDataPartInfo(DataPartInfo $dataInfo): void
{
$this->dataInfo = $dataInfo;
}
/**
* Gets information about a file.
*
* @param int $fileinfo_const Any predefined constant. See https://www.php.net/manual/en/fileinfo.constants.php
*
* @psalm-param fileinfoconst $fileinfo_const
*/
public function getFileInfo(int $fileinfo_const = FILEINFO_NONE): string
{
$finfo = new finfo($fileinfo_const);
return $finfo->buffer($this->getContents());
}
/**
* Gets the file content.
*/
public function getContents(): string
{
if (null === $this->dataInfo) {
throw new UnexpectedValueException(static::class.'::$dataInfo has not been set by calling '.self::class.'::addDataPartInfo()');
}
return $this->dataInfo->fetch();
}
/**
* Saves the attachment object on the disk.
*
* @return bool True, if it could save the attachment on the disk
*/
public function saveToDisk(): bool
{
if (null === $this->dataInfo) {
return false;
}
if (false === \file_put_contents($this->__get('filePath'), $this->dataInfo->fetch())) {
unset($this->filePath, $this->file_path);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,149 @@
<?php
declare(strict_types=1);
namespace PhpImap;
/**
* @see https://github.com/barbushin/php-imap
*
* @author Barbushin Sergey http://linkedin.com/in/barbushin
*/
class IncomingMailHeader
{
/** @var int|null The IMAP message ID - not the "Message-ID:"-header of the email */
public $id;
/** @var string|null */
public $imapPath;
/** @var string|null */
public $mailboxFolder;
/** @var bool */
public $isSeen = false;
/** @var bool */
public $isAnswered = false;
/** @var bool */
public $isRecent = false;
/** @var bool */
public $isFlagged = false;
/** @var bool */
public $isDeleted = false;
/** @var bool */
public $isDraft = false;
/** @var string|null */
public $date;
/** @var string|null */
public $headersRaw;
/** @var object|null */
public $headers;
/** @var string|null */
public $mimeVersion;
/** @var string|null */
public $xVirusScanned;
/** @var string|null */
public $organization;
/** @var string|null */
public $contentType;
/** @var string|null */
public $xMailer;
/** @var string|null */
public $contentLanguage;
/** @var string|null */
public $xSenderIp;
/** @var string|null */
public $priority;
/** @var string|null */
public $importance;
/** @var string|null */
public $sensitivity;
/** @var string|null */
public $autoSubmitted;
/** @var string|null */
public $precedence;
/** @var string|null */
public $failedRecipients;
/** @var string|null */
public $subject;
/** @var string|null */
public $fromHost;
/** @var string|null */
public $fromName;
/** @var string|null */
public $fromAddress;
/** @var string|null */
public $senderHost;
/** @var string|null */
public $senderName;
/** @var string|null */
public $senderAddress;
/** @var string|null */
public $xOriginalTo;
/**
* @var (string|null)[]
*
* @psalm-var array<string, string|null>
*/
public $to = [];
/** @var string|null */
public $toString;
/**
* @var (string|null)[]
*
* @psalm-var array<string, string|null>
*/
public $cc = [];
/** @var string|null */
public $ccString;
/**
* @var (string|null)[]
*
* @psalm-var array<string, string|null>
*/
public $bcc = [];
/**
* @var (string|null)[]
*
* @psalm-var array<string, string|null>
*/
public $replyTo = [];
/** @var string|null */
public $messageId;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
<?php namespace PhpImap;
spl_autoload_register(function ($class) {
if(strpos($class, __NAMESPACE__) === 0) {
/** @noinspection PhpIncludeInspection */
require_once(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php');
}
});

View File

@@ -0,0 +1,210 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use Generator;
use ParagonIE\HiddenString\HiddenString;
use PHPUnit\Framework\TestCase;
use Throwable;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
* @psalm-type COMPOSE_ENVELOPE = array{
* subject?:string
* }
* @psalm-type COMPOSE_BODY = list<array{
* type?:int,
* encoding?:int,
* charset?:string,
* subtype?:string,
* description?:string,
* 'disposition.type'?:string,
* 'type.parameters'?:array{name:string},
* 'contents.data'?:string,
* id?:string,
* disposition?:array{filename:string}
* }>
*/
abstract class AbstractLiveMailboxTest extends TestCase
{
use LiveMailboxTestingTrait;
/**
* @psalm-return Generator<empty, empty, mixed, void>
*/
public function ComposeProvider(): Generator
{
yield from [];
}
/**
* @psalm-return Generator<int, array{
* 0:MAILBOX_ARGS,
* 1:COMPOSE_ENVELOPE,
* 2:COMPOSE_BODY,
* 3:string,
* 4:bool
* }, mixed, void>
*/
public function AppendProvider(): Generator
{
foreach ($this->MailBoxProvider() as $mailbox_args) {
foreach ($this->ComposeProvider() as $compose_args) {
[$envelope, $body, $expected_compose_result] = $compose_args;
yield [$mailbox_args, $envelope, $body, $expected_compose_result, false];
}
foreach ($this->ComposeProvider() as $compose_args) {
[$envelope, $body, $expected_compose_result] = $compose_args;
yield [$mailbox_args, $envelope, $body, $expected_compose_result, true];
}
}
}
/**
* @dataProvider AppendProvider
*
* @group live
*
* @depends testGetImapStream
* @depends testMailCompose
*
* @psalm-param MAILBOX_ARGS $mailbox_args
* @psalm-param COMPOSE_ENVELOPE $envelope
* @psalm-param COMPOSE_BODY $body
*/
public function testAppend(
array $mailbox_args,
array $envelope,
array $body,
string $_expected_compose_result,
bool $pre_compose
): void {
if ($this->MaybeSkipAppendTest($envelope)) {
return;
}
[$search_criteria] = $this->SubjectSearchCriteriaAndSubject($envelope);
[$mailbox, $remove_mailbox, $path] = $this->getMailboxFromArgs(
$mailbox_args
);
/** @var Throwable|null */
$exception = null;
$mailboxDeleted = false;
try {
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$message = [$envelope, $body];
if ($pre_compose) {
$message = Imap::mail_compose($envelope, $body);
}
$mailbox->appendMessageToMailbox($message);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$mailbox->deleteMail($search[0]);
$mailbox->expungeDeletedMails();
$mailbox->switchMailbox($path->getString());
$mailbox->deleteMailbox($remove_mailbox);
$mailboxDeleted = true;
$this->assertCount(
0,
$mailbox->searchMailbox($search_criteria),
(
'If a subject was found,'.
' then the message is was not expunged as requested.'
)
);
} catch (Throwable $ex) {
$exception = $ex;
} finally {
$mailbox->switchMailbox($path->getString());
if (!$mailboxDeleted) {
$mailbox->deleteMailbox($remove_mailbox);
}
$mailbox->disconnect();
}
if (null !== $exception) {
throw $exception;
}
}
/**
* Get subject search criteria and subject.
*
* @psalm-param array{subject?:mixed} $envelope
*
* @psalm-return array{0:string, 1:string}
*/
protected function SubjectSearchCriteriaAndSubject(array $envelope): array
{
/** @var string|null */
$subject = $envelope['subject'] ?? null;
$this->assertIsString($subject);
$search_criteria = \sprintf('SUBJECT "%s"', $subject);
/** @psalm-var array{0:string, 1:string} */
return [$search_criteria, $subject];
}
protected function MaybeSkipAppendTest(array $envelope): bool
{
if (!isset($envelope['subject'])) {
$this->markTestSkipped(
'Cannot search for message by subject, no subject specified!'
);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace PhpImap\Fixtures;
use PhpImap\DataPartInfo as Base;
class DataPartInfo extends Base
{
/** @var string|null */
protected $data;
public function fetch(): string
{
return $this->decodeAfterFetch($this->data);
}
public function setData(string $data = null): void
{
$this->data = $data;
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace PhpImap\Fixtures;
use const FILEINFO_MIME_TYPE;
use const FILEINFO_NONE;
use PhpImap\IncomingMailAttachment as Base;
class IncomingMailAttachment extends Base
{
/** @var string|null */
public $override_getFileInfo_mime_type = null;
public function getFileInfo(int $fileinfo_const = FILEINFO_NONE): string
{
if (
FILEINFO_MIME_TYPE === $fileinfo_const &&
isset($this->override_getFileInfo_mime_type)
) {
return $this->override_getFileInfo_mime_type;
}
return parent::getFileInfo($fileinfo_const);
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace PhpImap\Fixtures;
use PhpImap\Mailbox as Base;
class Mailbox extends Base
{
public function getImapPassword(): string
{
return $this->imapPassword;
}
public function getImapOptions(): int
{
return $this->imapOptions;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 B

View File

@@ -0,0 +1,152 @@
<?php
/**
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use Generator;
use ParagonIE\HiddenString\HiddenString;
use PhpImap\Exceptions\ConnectionException;
use PHPUnit\Framework\TestCase as Base;
use const SORTARRIVAL;
use Throwable;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
* @psalm-type PSALM_OPEN_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:int,
* 4:int,
* 5:array{DISABLE_AUTHENTICATOR:string}|array<empty, empty>
* } $args
*/
class ImapTest extends Base
{
use LiveMailboxTestingTrait;
/**
* @psalm-return Generator<'CI ENV with invalid password'|'empty mailbox/username/password', array{0: ConnectionException::class, 1: '/^[AUTHENTICATIONFAILED]/'|'Can't open mailbox : no such mailbox', 2: array{0: HiddenString, 1: HiddenString, 2: HiddenString, 3: 0, 4: 0, 5: array<empty, empty>}, 3?: true}, mixed, void>
*/
public function OpenFailure(): Generator
{
yield 'empty mailbox/username/password' => [
ConnectionException::class,
'Can\'t open mailbox : no such mailbox',
[
new HiddenString(''),
new HiddenString(''),
new HiddenString(''),
0,
0,
[],
],
];
$imapPath = \getenv('PHPIMAP_IMAP_PATH');
$login = \getenv('PHPIMAP_LOGIN');
$password = \getenv('PHPIMAP_PASSWORD');
if (\is_string($imapPath) && \is_string($login) && \is_string($password)) {
yield 'CI ENV with invalid password' => [
ConnectionException::class,
'/^\[AUTHENTICATIONFAILED\].*/',
[
new HiddenString($imapPath, true, true),
new HiddenString($login, true, true),
new HiddenString(\strrev($password), true, true),
0,
0,
[],
],
true,
];
}
}
/**
* @dataProvider OpenFailure
*
* @psalm-param class-string<Throwable> $exception
* @psalm-param PSALM_OPEN_ARGS $args
*/
public function testOpenFailure(
string $exception,
string $message,
array $args,
bool $message_as_regex = false
): void {
$this->expectException($exception);
if ($message_as_regex) {
$this->expectExceptionMessageMatches($message);
} else {
$this->expectExceptionMessage($message);
}
Imap::open(
$args[0]->getString(),
$args[1]->getString(),
$args[2]->getString(),
$args[3],
$args[4],
$args[5]
);
}
/**
* @dataProvider MailBoxProvider
*
* @group live
*/
public function testSortEmpty(
HiddenString $path,
HiddenString $login,
HiddenString $password
): void {
[$mailbox, $remove_mailbox, $path] = $this->getMailboxFromArgs([
$path,
$login,
$password,
\sys_get_temp_dir(),
]);
/** @var Throwable|null */
$exception = null;
$mailboxDeleted = false;
try {
$this->assertSame(
[],
Imap::sort(
$mailbox->getImapStream(),
SORTARRIVAL,
false,
0
)
);
} catch (Throwable $ex) {
$exception = $ex;
} finally {
$mailbox->switchMailbox($path->getString());
if (!$mailboxDeleted) {
$mailbox->deleteMailbox($remove_mailbox);
}
$mailbox->disconnect();
}
if (null !== $exception) {
throw $exception;
}
}
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use const DATE_RFC3339;
use const ENCOTHER;
use PHPUnit\Framework\TestCase;
class IncomingMailTest extends TestCase
{
public function testSetHeader(): void
{
$mail = new IncomingMail();
$header = new IncomingMailHeader();
$mail->id = 1;
$header->id = 2;
$mail->isDraft = true;
$header->isDraft = false;
$mail->date = \date(DATE_RFC3339, 0);
$header->date = \date(DATE_RFC3339, 60 * 60 * 24);
$mail->setHeader($header);
foreach (
[
'id',
'isDraft',
'date',
] as $property
) {
/** @var scalar|array|object|resource|null */
$headerPropertyValue = $header->$property;
$this->assertSame($headerPropertyValue, $mail->$property);
}
}
public function testDataPartInfo(): void
{
$mail = new IncomingMail();
$mailbox = new Mailbox('', '', '');
$data_part = new Fixtures\DataPartInfo($mailbox, 1, 0, ENCOTHER, 0);
$data_part->setData('foo');
$this->assertSame('foo', $data_part->fetch());
$mail->addDataPartInfo($data_part, DataPartInfo::TEXT_PLAIN);
$this->assertSame('foo', $mail->textPlain);
$this->assertTrue($mail->__isset('textPlain'));
}
public function testAttachments(): void
{
$mail = new IncomingMail();
$this->assertFalse($mail->hasAttachments());
$this->assertSame([], $mail->getAttachments());
$attachments = [
new IncomingMailAttachment(),
];
foreach ($attachments as $i => $attachment) {
$attachment->id = (string) $i;
$mail->addAttachment($attachment);
}
$this->assertTrue($mail->hasAttachments());
$this->assertSame($attachments, $mail->getAttachments());
foreach ($attachments as $attachment) {
$this->assertIsString($attachment->id);
$this->assertTrue($mail->removeAttachment($attachment->id));
}
$this->assertFalse($mail->hasAttachments());
$this->assertSame([], $mail->getAttachments());
foreach ($attachments as $attachment) {
$this->assertIsString($attachment->id);
$this->assertFalse($mail->removeAttachment($attachment->id));
}
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use PHPUnit\Framework\TestCase;
class Issue509Test extends TestCase
{
public const base64 =
'vsiz58fPvcq0z7HuLiC05MDlx9jB1rzFvK0gsKi758fVtM+02S4NCsDMt7EgwM/AuiC16b7uILq7
wPvAzCC++L3AtM+02S4NCsDMwM8gvu62u7DUIMfPvcO0wsH2ILHDsd3H1bTPtNkuDQrBprChIMik
vcMgsPi9xMD7wLi3ziCw7b/rtce++r3AtM+x7j8NCg0KU2VudCBmcm9tIE1haWw8aHR0cHM6Ly9n
by5taWNyb3NvZnQuY29tL2Z3bGluay8/TGlua0lkPTU1MDk4Nj4gZm9yIFdpbmRvd3MgMTANCg0K
RnJvbTogQ2xvdWR3b3JrZXJzIEFnZW50cyBLUjxtYWlsdG86am9icy5rckBjbG91ZHdvcmtlcnMu
Y29tcGFueT4NClNlbnQ6IEZyaWRheSwgTWF5IDIyLCAyMDIwIDg6NDkgUE0NClRvOiBjYXNleWN1
bGxlbjE3QGhvdG1haWwuY29tPG1haWx0bzpjYXNleWN1bGxlbjE3QGhvdG1haWwuY29tPg0KU3Vi
amVjdDogQ2xvdWR3b3JrZXJzIENvbXBhbnktIFlvdXIgQXBwbGljYXRpb24NCg0Kvsiz58fPvcq0
z7HuLg0KtOe757+hvK0gsPjB9sfRIL73uau/oSDB9r/4x9jB1rzFvK0gsKi758fVtM+02S4gwMy/
oSC068fYILyzuO215biuwNq46SC02cC9sPogsLC9wLTPtNkuDQq/wrbzwM4gwNu+97DJseIgxL+5
wrTPxry/obytILDtsLTAzCC6uLO7tMIguN68vMH2v6EgtOvH2CC05MfPtMIgsM3AzCDB1r73uavA
1LTPtNkuILTnu+fAxyC/wMbbt7kgwMzFzbXpwLogxMTHu8XNt84gxvfF0MC7IMXrx9gguN68vMH2
v6EgtOTH1bTPtNkuIL/CtvPAzsC4t84gv+6/tbXHtMIgvve5q8DMuOcgvu618LyttefB9iDExMe7
xc2/zSDA/MDaILHiseK3ziDAz8fYvt8gx9W0z7TZLg0KDQqw7bC0wMcgv+WxuCDD5sG3v6Egv+y8
sb3Dx9i+3yDHz7TCILi4xa0gtOvIrSCzu7/rwMcgvPbAp7ChILP0wLogvPbB2MDUtM+02S4gwKW7
58DMxq6/oSCw+MH2x9G06yC3ziwgwMzAzCC068fRILHNx8/AxyChsL+tuLAgxcK1tb/NIMD7sdjA
+8DOILi2wL2wocH8obHAzCDHyr/kx9W0z7TZLg0KDQrAzL+hILTrx9ggvsuw7SCw6L3DtMIgsM3A
zCDBwbTZsO0gu/2wosfVtM+02S4guN68vMH2IMfPs6q05yAwLjnAr7fOwNS0z7TZLg0Ksd6/qbTC
ILjFtN4gw8osIDEwwM8gvve5q8DPILO7v6EgUGF5cGFswMyzqiDAusfgILzbsd0sIL/4x8+0wiC5
5r3EwLi3ziDB9rHetcu0z7TZLiDAzLexIMDPwLsgx9i6uLzMsMWzqiC16b7uuri9xSDA+8DMIMDW
wLi9xbChv+Q/DQqxw7Hdx9Egu+fH18DMIMDWwLi46SC+8MGmtecgwfq5rsfYwda9yr3Dv8AhILCo
u+fH1bTPtNkuDQoNCg0KRG9uZ2h5dW4gS2ltDQoNCkNMT1VEV09SS0VSUyBDT01QQU5ZDQoNCsOk
v+vGwA0KDQpGb246ICs0NCAoMCkgMjA4MDgwNjU3MQ0KDQoxMjggQ2Fubm9uIFdvcmtzaG9wcyBD
YW5ub24gRHJpdmUNCkUxNCA0QVMgTG9uZG9uDQp3d3cuY2xvdWR3b3JrZXJzLmNvbXBhbnkNCg0K
DQo=';
public const sha256 =
'5656f5f8a872b8989ba3aaecdfbdc6311bf4c5e0219c27b3b004ce83d8ffd6f3';
public function testDecode(): void
{
$mailbox = new Mailbox('', '', '');
$mailbox->decodeMimeStrDefaultCharset = 'EUC-KR';
$decoded = $mailbox->decodeMimeStr(\base64_decode(self::base64));
$this->assertSame(self::sha256, \hash('sha256', $decoded));
}
}

View File

@@ -0,0 +1,184 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use const ENC8BIT;
use const ENCBASE64;
use PHPUnit\Framework\TestCase;
use const TYPEIMAGE;
class Issue519Test extends TestCase
{
public const HEADER_VALUES = [
'inline',
'Inline',
'iNline',
'INline',
'inLine',
'InLine',
'iNLine',
'INLine',
'inlIne',
'InlIne',
'iNlIne',
'INlIne',
'inLIne',
'InLIne',
'iNLIne',
'INLIne',
'inliNe',
'InliNe',
'iNliNe',
'INliNe',
'inLiNe',
'InLiNe',
'iNLiNe',
'INLiNe',
'inlINe',
'InlINe',
'iNlINe',
'INlINe',
'inLINe',
'InLINe',
'iNLINe',
'INLINe',
'inlinE',
'InlinE',
'iNlinE',
'INlinE',
'inLinE',
'InLinE',
'iNLinE',
'INLinE',
'inlInE',
'InlInE',
'iNlInE',
'INlInE',
'inLInE',
'InLInE',
'iNLInE',
'INLInE',
'inliNE',
'InliNE',
'iNliNE',
'INliNE',
'inLiNE',
'InLiNE',
'iNLiNE',
'INLiNE',
'inlINE',
'InlINE',
'iNlINE',
'INlINE',
'inLINE',
'InLINE',
'iNLINE',
'INLINE',
];
public const CID = 'cid:foo.jpg';
public const ID = 'foo.jpg';
public const SUBTYPE = 'jpeg';
public const SIZE_IN_BYTES = 0;
public const HTML = 'foo.html';
public const HTML_EMBED = '<img src="data:image/jpeg;base64, ">';
public const MIME_TYPE = 'image/jpeg';
public const EXPECTED_ATTACHMENT_COUNT = 1;
public const EXPECTED_ATTACHMENT_COUNT_AFTER_EMBED = 0;
/**
* @psalm-return array<string, array{0: string}>
*
* @return string[][]
*/
public function provider(): array
{
$out = [];
foreach (self::HEADER_VALUES as $value) {
$out[$value] = [$value];
}
return $out;
}
/**
* @dataProvider provider
*/
public function test(string $header_value): void
{
$mailbox = new Mailbox('', '', '');
$mail = new IncomingMail();
$attachment = new Fixtures\IncomingMailAttachment();
$part = new Fixtures\DataPartInfo(
$mailbox,
0,
0,
ENCBASE64,
0
);
$html = new Fixtures\DataPartInfo(
$mailbox,
0,
0,
ENC8BIT,
0
);
$html_string = '<img src="'.self::CID.'">';
$html->setData($html_string);
$part->setData('');
$attachment->id = self::ID;
$attachment->contentId = self::ID;
$attachment->type = TYPEIMAGE;
$attachment->encoding = ENCBASE64;
$attachment->subtype = self::SUBTYPE;
$attachment->description = self::ID;
$attachment->name = self::ID;
$attachment->sizeInBytes = self::SIZE_IN_BYTES;
$attachment->disposition = $header_value;
$attachment->override_getFileInfo_mime_type = self::MIME_TYPE;
$attachment->addDataPartInfo($part);
$mail->addDataPartInfo($html, DataPartInfo::TEXT_HTML);
$mail->addAttachment($attachment);
$this->assertTrue($mail->hasAttachments());
$this->assertCount(
self::EXPECTED_ATTACHMENT_COUNT,
$mail->getAttachments()
);
$this->assertSame($html_string, $mail->textHtml);
$mail->embedImageAttachments();
$this->assertCount(
self::EXPECTED_ATTACHMENT_COUNT_AFTER_EMBED,
$mail->getAttachments()
);
$this->assertSame(self::HTML_EMBED, $mail->textHtml);
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use Generator;
use ParagonIE\HiddenString\HiddenString;
use const TYPETEXT;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
* @psalm-type COMPOSE_ENVELOPE = array{
* subject?:string
* }
* @psalm-type COMPOSE_BODY = list<array{
* type?:int,
* encoding?:int,
* charset?:string,
* subtype?:string,
* description?:string,
* disposition?:array{filename:string}
* }>
*/
class LiveMailboxIssue250Test extends AbstractLiveMailboxTest
{
/**
* @psalm-return Generator<int, array{0: array{subject: string}, 1: array{0: array{type: 0, 'contents.data': 'test'}}, 2: string}, mixed, void>
*/
public function ComposeProvider(): Generator
{
$random_subject = 'barbushin/php-imap#250 测试: '.\bin2hex(\random_bytes(16));
yield [
['subject' => $random_subject],
[
[
'type' => TYPETEXT,
'contents.data' => 'test',
],
],
(
'Subject: '.$random_subject."\r\n".
'MIME-Version: 1.0'."\r\n".
'Content-Type: TEXT/PLAIN; CHARSET=US-ASCII'."\r\n".
"\r\n".
'test'."\r\n"
),
];
}
/**
* @dataProvider AppendProvider
*
* @group live
* @group live-issue-250
*
* @psalm-param MAILBOX_ARGS $mailbox_args
* @psalm-param COMPOSE_ENVELOPE $envelope
* @psalm-param COMPOSE_BODY $body
*/
public function testAppend(
array $mailbox_args,
array $envelope,
array $body,
string $expected_compose_result,
bool $pre_compose
): void {
parent::testAppend(
$mailbox_args,
$envelope,
$body,
$expected_compose_result,
$pre_compose
);
}
}

View File

@@ -0,0 +1,141 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use Exception;
use ParagonIE\HiddenString\HiddenString;
use const TYPEMULTIPART;
use const TYPETEXT;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
*/
class LiveMailboxIssue490Test extends AbstractLiveMailboxTest
{
/**
* @dataProvider MailBoxProvider
*
* @group live
* @group live-issue-490
*/
public function testGetTextAttachments(
HiddenString $imapPath,
HiddenString $login,
HiddenString $password,
string $attachmentsDir,
string $serverEncoding = 'UTF-8'
): void {
[$mailbox, $remove_mailbox] = $this->getMailbox(
$imapPath,
$login,
$password,
$attachmentsDir,
$serverEncoding
);
$exception = null;
try {
$envelope = [
'subject' => 'barbushin/php-imap#501: '.\bin2hex(\random_bytes(16)),
];
[$search_criteria] = $this->SubjectSearchCriteriaAndSubject(
$envelope
);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$message = Imap::mail_compose(
$envelope,
[
[
'type' => TYPEMULTIPART,
],
[
'type' => TYPETEXT,
'contents.data' => 'foo',
],
[
'type' => TYPEMULTIPART,
'subtype' => 'plain',
'description' => 'bar.txt',
'disposition.type' => 'attachment',
'disposition' => ['filename' => 'bar.txt'],
'type.parameters' => ['name' => 'bar.txt'],
'contents.data' => 'bar',
],
[
'type' => TYPEMULTIPART,
'subtype' => 'plain',
'description' => 'baz.txt',
'disposition.type' => 'attachment',
'disposition' => ['filename' => 'baz.txt'],
'type.parameters' => ['name' => 'baz.txt'],
'contents.data' => 'baz',
],
]
);
$mailbox->appendMessageToMailbox($message);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$mail = $mailbox->getMail($search[0], false);
$this->assertSame('foo', $mail->textPlain);
$attachments = $mail->getAttachments();
$keys = \array_keys($attachments);
$this->assertCount(2, $attachments);
$this->assertSame('bar', $attachments[$keys[0]]->getContents());
$this->assertSame('baz', $attachments[$keys[1]]->getContents());
} catch (Exception $ex) {
$exception = $ex;
} finally {
$mailbox->switchMailbox($imapPath->getString());
$mailbox->deleteMailbox($remove_mailbox);
$mailbox->disconnect();
}
if (null !== $exception) {
throw $exception;
}
}
}

View File

@@ -0,0 +1,130 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use Exception;
use ParagonIE\HiddenString\HiddenString;
use const TYPETEXT;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
*/
class LiveMailboxIssue501Test extends AbstractLiveMailboxTest
{
/**
* @group offline
* @group offline-issue-501
*/
public function testDecodeMimeStrEmpty(): void
{
$this->assertSame([], \imap_mime_header_decode(''));
// example credentials nabbed from MailboxTest::testConstructorTrimsPossibleVariables()
$imapPath = ' {imap.example.com:993/imap/ssl}INBOX ';
$login = ' php-imap@example.com';
$password = ' v3rY!53cEt&P4sSWöRd$';
// directory names can contain spaces before AND after on Linux/Unix systems. Windows trims these spaces automatically.
$attachmentsDir = '.';
$serverEncoding = 'UTF-8 ';
$mailbox = new Mailbox($imapPath, $login, $password, $attachmentsDir, $serverEncoding);
$this->assertSame('', $mailbox->decodeMimeStr(''));
}
/**
* @dataProvider MailBoxProvider
*
* @group live
* @group live-issue-501
*/
public function testGetEmptyBody(
HiddenString $imapPath,
HiddenString $login,
HiddenString $password,
string $attachmentsDir,
string $serverEncoding = 'UTF-8'
): void {
[$mailbox, $remove_mailbox] = $this->getMailbox(
$imapPath,
$login,
$password,
$attachmentsDir,
$serverEncoding
);
$exception = null;
try {
$envelope = [
'subject' => 'barbushin/php-imap#501: '.\bin2hex(\random_bytes(16)),
];
[$search_criteria] = $this->SubjectSearchCriteriaAndSubject(
$envelope
);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$mailbox->appendMessageToMailbox(Imap::mail_compose(
$envelope,
[
[
'type' => TYPETEXT,
'contents.data' => '',
],
]
));
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$mail = $mailbox->getMail($search[0], false);
$this->assertSame('', $mail->textPlain);
} catch (Exception $ex) {
$exception = $ex;
} finally {
$mailbox->switchMailbox($imapPath->getString());
$mailbox->deleteMailbox($remove_mailbox);
$mailbox->disconnect();
}
if (null !== $exception) {
throw $exception;
}
}
}

View File

@@ -0,0 +1,258 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use const ENCBASE64;
use ParagonIE\HiddenString\HiddenString;
use Throwable;
use const TYPEIMAGE;
use const TYPEMULTIPART;
use const TYPETEXT;
/**
* @psalm-import-type COMPOSE_ENVELOPE from AbstractLiveMailboxTest
*/
class LiveMailboxIssue514Test extends AbstractLiveMailboxTest
{
/**
* @dataProvider MailBoxProvider
*
* @group live
* @group issue-514
*/
public function testEmbed(
HiddenString $imapPath,
HiddenString $login,
HiddenString $password,
string $attachmentsDir,
string $serverEncoding = 'UTF-8'
): void {
/** @var Throwable|null */
$exception = null;
$mailboxDeleted = false;
/** @psalm-var COMPOSE_ENVELOPE */
$envelope = [
'subject' => 'barbushin/php-imap#514--'.\bin2hex(\random_bytes(16)),
];
[$search_criteria] = $this->SubjectSearchCriteriaAndSubject($envelope);
$body = [
[
'type' => TYPEMULTIPART,
],
[
'type' => TYPETEXT,
'subtype' => 'plain',
'contents.data' => 'foo',
],
[
'type' => TYPETEXT,
'subtype' => 'html',
'contents.data' => \implode('', [
'<img alt="png" width="5" height="1" src="cid:foo.png">',
'<img alt="webp" width="5" height="1" src="cid:foo.webp">',
]),
],
[
'type' => TYPEIMAGE,
'subtype' => 'png',
'encoding' => ENCBASE64,
'id' => 'foo.png',
'description' => 'foo.png',
'disposition' => ['filename' => 'foo.png'],
'disposition.type' => 'inline',
'type.parameters' => ['name' => 'foo.png'],
'contents.data' => \base64_encode(
\file_get_contents(__DIR__.'/Fixtures/rgbkw5x1.png')
),
],
[
'type' => TYPEIMAGE,
'subtype' => 'webp',
'encoding' => ENCBASE64,
'id' => 'foo.webp',
'description' => 'foo.webp',
'disposition' => ['filename' => 'foo.webp'],
'disposition.type' => 'inline',
'type.parameters' => ['name' => 'foo.webp'],
'contents.data' => \base64_encode(
\file_get_contents(__DIR__.'/Fixtures/rgbkw5x1.webp')
),
],
];
$message = Imap::mail_compose(
$envelope,
$body
);
[$mailbox, $remove_mailbox, $path] = $this->getMailboxFromArgs([
$imapPath,
$login,
$password,
$attachmentsDir,
$serverEncoding,
]);
$result = null;
try {
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$mailbox->appendMessageToMailbox($message);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$result = $mailbox->getMail($search[0], false);
/** @var array<string, int> */
$counts = [];
foreach ($result->getAttachments() as $attachment) {
if (!isset($counts[(string) $attachment->contentId])) {
$counts[(string) $attachment->contentId] = 0;
}
++$counts[(string) $attachment->contentId];
}
$this->assertCount(
2,
$counts,
(
'counts should only contain foo.png and foo.webp, found: '.
\implode(
', ',
\array_keys($counts)
)
)
);
foreach ($counts as $cid => $count) {
$this->assertSame(
1,
$count,
$cid.' had '.(string) $count.', expected 1.'
);
}
$this->assertSame(
'foo',
$result->textPlain,
'plain text body did not match expected result!'
);
$embedded = \implode('', [
'<img alt="png" width="5" height="1" src="',
'data:image/png; charset=binary;base64, ',
$body[3]['contents.data'],
'">',
'<img alt="webp" width="5" height="1" src="',
'data:image/webp; charset=binary;base64, ',
$body[4]['contents.data'],
'">',
]);
$this->assertSame(
[
'foo.png' => 'cid:foo.png',
'foo.webp' => 'cid:foo.webp',
],
$result->getInternalLinksPlaceholders(),
'Internal link placeholders did not match expected result!'
);
$replaced = \implode('', [
'<img alt="png" width="5" height="1" src="',
'foo.png',
'">',
'<img alt="webp" width="5" height="1" src="',
'foo.webp',
'">',
]);
foreach ($result->getAttachments() as $attachment) {
if ('foo.png' === $attachment->contentId) {
$replaced = \str_replace(
'foo.png',
'/'.\basename($attachment->filePath),
$replaced
);
} elseif ('foo.webp' === $attachment->contentId) {
$replaced = \str_replace(
'foo.webp',
'/'.\basename($attachment->filePath),
$replaced
);
}
}
$this->assertSame(
$replaced,
$result->replaceInternalLinks(''),
'replaced html body did not match expected result!'
);
$this->assertSame(
$body[2]['contents.data'],
$result->textHtml,
'unembeded html body did not match expected result!'
);
$result->embedImageAttachments();
$this->assertSame(
$embedded,
$result->textHtml,
'embeded html body did not match expected result!'
);
$mailbox->deleteMail($search[0]);
} catch (Throwable $ex) {
$exception = $ex;
} finally {
$mailbox->switchMailbox($path->getString());
if (!$mailboxDeleted) {
$mailbox->deleteMailbox($remove_mailbox);
}
$mailbox->disconnect();
}
if (null !== $exception) {
throw $exception;
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author Sebi94nbg
*/
declare(strict_types=1);
namespace PhpImap;
use const ENCQUOTEDPRINTABLE;
use Generator;
use PHPUnit\Framework\TestCase;
class LiveMailboxStringDecodingConvertingTest extends TestCase
{
/**
* Provides data for testing string decoding.
*/
public function stringDecodeProvider(): Generator
{
yield 'Issue #250 iso-8859-1' => [
ENCQUOTEDPRINTABLE,
'iso-8859-1',
'mountainguan',
'mountainguan',
'e94a37111edb29a8d3f6078dc4810953964f19562613cf2bd15e21b69d30822a',
];
yield 'Issue #250 utf-7' => [
ENCQUOTEDPRINTABLE,
'utf-7',
'+bUuL1Q-',
'测试',
'6aa8f49cc992dfd75a114269ed26de0ad6d4e7d7a70d9c8afb3d7a57a88a73ed',
];
yield 'Issue #250 utf-7 with chinese' => [
ENCQUOTEDPRINTABLE,
'utf-7',
'mountainguan+bUuL1Q-',
'mountainguan测试',
'62a5022b682b7e02bda8d18424fa06501cdd71cce2832e95129673f63da2e177',
];
yield 'Issue #250 utf-8 with chinese' => [
ENCQUOTEDPRINTABLE,
'utf-8',
'mountainguan=E6=B5=8B=E8=AF=95',
'mountainguan测试',
'62a5022b682b7e02bda8d18424fa06501cdd71cce2832e95129673f63da2e177',
];
yield 'Issue #657' => [
ENCQUOTEDPRINTABLE,
'iso-8859-2',
'=EC=B9=E8=F8=BE=FD=E1=ED=E9',
'ěščřžýáíé',
'a05e42c7e14de716cd501e135f3f5e49545f71069de316a1e9f7bb153f9a7356',
];
yield 'Emoji utf-8' => [
ENCQUOTEDPRINTABLE,
'utf-8',
'Some subject here =F0=9F=98=98',
'Some subject here 😘',
'da66c62e7e82316b8b543f52f1ecc4415c4dc93bc87e2239ee5f98bdf00a8c50',
];
}
/**
* Test that string decoding and converting works as expected.
*
* @dataProvider stringDecodeProvider
*/
public function testStringDecode(int $encoding, string $charset, string $iso_8859_2, string $utf8, string $sha256): void
{
$mailbox = new Mailbox('', '', '');
$dataInfo = new DataPartInfo($mailbox, 1337, '', $encoding, 0);
$dataInfo->charset = $charset;
$decoded = $dataInfo->decodeAfterFetch($iso_8859_2);
$this->assertSame($utf8, $decoded);
$this->assertSame($sha256, \hash('sha256', $decoded));
}
}

View File

@@ -0,0 +1,678 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use function date;
use const ENCBASE64;
use Generator;
use ParagonIE\HiddenString\HiddenString;
use const SORTARRIVAL;
use Throwable;
use const TYPEAPPLICATION;
use const TYPEMULTIPART;
use const TYPETEXT;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
* @psalm-type COMPOSE_ENVELOPE = array{
* subject?:string
* }
* @psalm-type COMPOSE_BODY = list<array{
* type?:int,
* encoding?:int,
* charset?:string,
* subtype?:string,
* description?:string,
* disposition?:array{filename:string}
* }>
*
* @todo see @todo of Imap::mail_compose()
*/
class LiveMailboxTest extends AbstractLiveMailboxTest
{
public const RANDOM_MAILBOX_SAMPLE_SIZE = 3;
public const ISSUE_EXPECTED_ATTACHMENT_COUNT = [
448 => 1,
391 => 2,
];
/**
* @dataProvider MailBoxProvider
*
* @group live
*/
public function testGetImapStream(HiddenString $imapPath, HiddenString $login, HiddenString $password, string $attachmentsDir, string $serverEncoding = 'UTF-8'): void
{
[$mailbox, $remove_mailbox] = $this->getMailbox(
$imapPath,
$login,
$password,
$attachmentsDir,
$serverEncoding
);
/** @var Throwable|null */
$exception = null;
try {
$mailbox->getImapStream();
$this->assertTrue($mailbox->hasImapStream());
$mailboxes = $mailbox->getMailboxes();
\shuffle($mailboxes);
$mailboxes = \array_values($mailboxes);
$limit = \min(\count($mailboxes), self::RANDOM_MAILBOX_SAMPLE_SIZE);
for ($i = 0; $i < $limit; ++$i) {
$this->assertIsArray($mailboxes[$i]);
$this->assertTrue(isset($mailboxes[$i]['shortpath']));
$this->assertIsString($mailboxes[$i]['shortpath']);
$mailbox->switchMailbox($mailboxes[$i]['shortpath']);
$check = $mailbox->checkMailbox();
foreach ([
'Date',
'Driver',
'Mailbox',
'Nmsgs',
'Recent',
] as $expectedProperty) {
$this->assertTrue(\property_exists($check, $expectedProperty));
}
$this->assertIsString($check->Date, 'Date property of Mailbox::checkMailbox() result was not a string!');
$unix = \strtotime($check->Date);
if (false === $unix && \preg_match('/[+-]\d{1,2}:?\d{2} \([^\)]+\)$/', $check->Date)) {
/** @var int */
$pos = \strrpos($check->Date, '(');
// Although the date property is likely RFC2822-compliant, it will not be parsed by strtotime()
$unix = \strtotime(\substr($check->Date, 0, $pos));
}
$this->assertIsInt($unix, 'Date property of Mailbox::checkMailbox() result was not a valid date!');
$this->assertTrue(\in_array($check->Driver, ['POP3', 'IMAP', 'NNTP', 'pop3', 'imap', 'nntp'], true), 'Driver property of Mailbox::checkMailbox() result was not of an expected value!');
$this->assertIsInt($check->Nmsgs, 'Nmsgs property of Mailbox::checkMailbox() result was not of an expected type!');
$this->assertIsInt($check->Recent, 'Recent property of Mailbox::checkMailbox() result was not of an expected type!');
$status = $mailbox->statusMailbox();
foreach ([
'messages',
'recent',
'unseen',
'uidnext',
'uidvalidity',
] as $expectedProperty) {
$this->assertTrue(\property_exists($status, $expectedProperty));
}
$this->assertSame($check->Nmsgs, $mailbox->countMails(), 'Mailbox::checkMailbox()->Nmsgs did not match Mailbox::countMails()!');
}
} catch (Throwable $ex) {
$exception = $ex;
} finally {
$mailbox->switchMailbox($imapPath->getString());
$mailbox->deleteMailbox($remove_mailbox);
$mailbox->disconnect();
}
if (null !== $exception) {
throw $exception;
}
}
/**
* @psalm-return Generator<int, array{0: array{subject: string}, 1: array{0: array{type: 0|1|3, 'contents.data'?: string, encoding?: 3, subtype?: 'octet-stream', description?: '.gitignore'|'gitignore.', 'disposition.type'?: 'attachment', disposition?: array{filename: '.gitignore'|'gitignore.'}, 'type.parameters'?: array{name: '.gitignore'|'gitignore.'}}, 1?: array{type: 0, 'contents.data': 'test'}, 2?: array{type: 3, encoding: 3, subtype: 'octet-stream', description: 'foo.bin', 'disposition.type': 'attachment', disposition: array{filename: 'foo.bin'}, 'type.parameters': array{name: 'foo.bin'}, 'contents.data': string}, 3?: array{type: 3, encoding: 3, subtype: 'octet-stream', description: 'foo.bin', 'disposition.type': 'attachment', disposition: array{filename: 'foo.bin'}, 'type.parameters': array{name: 'foo.bin'}, 'contents.data': string}}, 2: string}, mixed, void>
*/
public function ComposeProvider(): Generator
{
$random_subject = 'test: '.\bin2hex(\random_bytes(16));
yield [
['subject' => $random_subject],
[
[
'type' => TYPETEXT,
'contents.data' => 'test',
],
],
(
'Subject: '.$random_subject."\r\n".
'MIME-Version: 1.0'."\r\n".
'Content-Type: TEXT/PLAIN; CHARSET=US-ASCII'."\r\n".
"\r\n".
'test'."\r\n"
),
];
$random_subject = 'barbushin/php-imap#448: dot first:'.\bin2hex(\random_bytes(16));
yield [
['subject' => $random_subject],
[
[
'type' => TYPEAPPLICATION,
'encoding' => ENCBASE64,
'subtype' => 'octet-stream',
'description' => '.gitignore',
'disposition.type' => 'attachment',
'disposition' => ['filename' => '.gitignore'],
'type.parameters' => ['name' => '.gitignore'],
'contents.data' => \base64_encode(
\file_get_contents(__DIR__.'/../../.gitignore')
),
],
],
(
'Subject: '.$random_subject."\r\n".
'MIME-Version: 1.0'."\r\n".
'Content-Type: APPLICATION/octet-stream; name=.gitignore'."\r\n".
'Content-Transfer-Encoding: BASE64'."\r\n".
'Content-Description: .gitignore'."\r\n".
'Content-Disposition: attachment; filename=.gitignore'."\r\n".
"\r\n".
\base64_encode(
\file_get_contents(__DIR__.'/../../.gitignore')
)."\r\n"
),
];
$random_subject = 'barbushin/php-imap#448: dot last: '.\bin2hex(\random_bytes(16));
yield [
['subject' => $random_subject],
[
[
'type' => TYPEAPPLICATION,
'encoding' => ENCBASE64,
'subtype' => 'octet-stream',
'description' => 'gitignore.',
'disposition.type' => 'attachment',
'disposition' => ['filename' => 'gitignore.'],
'type.parameters' => ['name' => 'gitignore.'],
'contents.data' => \base64_encode(
\file_get_contents(__DIR__.'/../../.gitignore')
),
],
],
(
'Subject: '.$random_subject."\r\n".
'MIME-Version: 1.0'."\r\n".
'Content-Type: APPLICATION/octet-stream; name=gitignore.'."\r\n".
'Content-Transfer-Encoding: BASE64'."\r\n".
'Content-Description: gitignore.'."\r\n".
'Content-Disposition: attachment; filename=gitignore.'."\r\n".
"\r\n".
\base64_encode(
\file_get_contents(__DIR__.'/../../.gitignore')
)."\r\n"
),
];
$random_subject = 'barbushin/php-imap#391: '.\bin2hex(\random_bytes(16));
$random_attachment_a = \base64_encode(\random_bytes(16));
$random_attachment_b = \base64_encode(\random_bytes(16));
yield [
['subject' => $random_subject],
[
[
'type' => TYPEMULTIPART,
],
[
'type' => TYPETEXT,
'contents.data' => 'test',
],
[
'type' => TYPEAPPLICATION,
'encoding' => ENCBASE64,
'subtype' => 'octet-stream',
'description' => 'foo.bin',
'disposition.type' => 'attachment',
'disposition' => ['filename' => 'foo.bin'],
'type.parameters' => ['name' => 'foo.bin'],
'contents.data' => $random_attachment_a,
],
[
'type' => TYPEAPPLICATION,
'encoding' => ENCBASE64,
'subtype' => 'octet-stream',
'description' => 'foo.bin',
'disposition.type' => 'attachment',
'disposition' => ['filename' => 'foo.bin'],
'type.parameters' => ['name' => 'foo.bin'],
'contents.data' => $random_attachment_b,
],
],
(
'Subject: '.$random_subject."\r\n".
'MIME-Version: 1.0'."\r\n".
'Content-Type: MULTIPART/MIXED; BOUNDARY="{{REPLACE_BOUNDARY_HERE}}"'."\r\n".
"\r\n".
'--{{REPLACE_BOUNDARY_HERE}}'."\r\n".
'Content-Type: TEXT/PLAIN; CHARSET=US-ASCII'."\r\n".
"\r\n".
'test'."\r\n".
'--{{REPLACE_BOUNDARY_HERE}}'."\r\n".
'Content-Type: APPLICATION/octet-stream; name=foo.bin'."\r\n".
'Content-Transfer-Encoding: BASE64'."\r\n".
'Content-Description: foo.bin'."\r\n".
'Content-Disposition: attachment; filename=foo.bin'."\r\n".
"\r\n".
$random_attachment_a."\r\n".
'--{{REPLACE_BOUNDARY_HERE}}'."\r\n".
'Content-Type: APPLICATION/octet-stream; name=foo.bin'."\r\n".
'Content-Transfer-Encoding: BASE64'."\r\n".
'Content-Description: foo.bin'."\r\n".
'Content-Disposition: attachment; filename=foo.bin'."\r\n".
"\r\n".
$random_attachment_b."\r\n".
'--{{REPLACE_BOUNDARY_HERE}}--'."\r\n"
),
];
}
/**
* @dataProvider ComposeProvider
*
* @group compose
*
* @psalm-param COMPOSE_ENVELOPE $envelope
* @psalm-param COMPOSE_BODY $body
*/
public function testMailCompose(array $envelope, array $body, string $expected_result): void
{
$actual_result = Imap::mail_compose($envelope, $body);
$expected_result = $this->ReplaceBoundaryHere(
$expected_result,
$actual_result
);
$this->assertSame($expected_result, $actual_result);
}
/**
* @dataProvider AppendProvider
*
* @group live
*
* @depends testAppend
*
* @psalm-param MAILBOX_ARGS $mailbox_args
* @psalm-param COMPOSE_ENVELOPE $envelope
* @psalm-param COMPOSE_BODY $body
*/
public function testAppendNudgesMailboxCount(
array $mailbox_args,
array $envelope,
array $body,
string $_expected_compose_result,
bool $pre_compose
): void {
if ($this->MaybeSkipAppendTest($envelope)) {
return;
}
[$search_criteria] = $this->SubjectSearchCriteriaAndSubject($envelope);
[$mailbox, $remove_mailbox, $path] = $this->getMailboxFromArgs(
$mailbox_args
);
$count = $mailbox->countMails();
$message = [$envelope, $body];
if ($pre_compose) {
$message = Imap::mail_compose($envelope, $body);
}
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$mailbox->appendMessageToMailbox($message);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$this->assertSame(
$count + 1,
$mailbox->countMails(),
(
'If the message count did not increase'.
' then either the message was not appended,'.
' or a mesage was removed while the test was running.'
)
);
$mailbox->deleteMail($search[0]);
$mailbox->expungeDeletedMails();
$mailbox->switchMailbox($path->getString());
$mailbox->deleteMailbox($remove_mailbox);
$this->assertCount(
0,
$mailbox->searchMailbox($search_criteria),
(
'If a subject was found,'.
' then the message is was not expunged as requested.'
)
);
}
/**
* @dataProvider AppendProvider
*
* @group live
*
* @depends testAppend
*
* @psalm-param MAILBOX_ARGS $mailbox_args
* @psalm-param COMPOSE_ENVELOPE $envelope
* @psalm-param COMPOSE_BODY $body
*/
public function testAppendSingleSearchMatchesSort(
array $mailbox_args,
array $envelope,
array $body,
string $_expected_compose_result,
bool $pre_compose
): void {
if ($this->MaybeSkipAppendTest($envelope)) {
return;
}
[$search_criteria] = $this->SubjectSearchCriteriaAndSubject($envelope);
[$mailbox, $remove_mailbox, $path] = $this->getMailboxFromArgs(
$mailbox_args
);
$message = [$envelope, $body];
if ($pre_compose) {
$message = Imap::mail_compose($envelope, $body);
}
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$mailbox->appendMessageToMailbox($message);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$this->assertSame(
$search,
$mailbox->sortMails(SORTARRIVAL, true, $search_criteria)
);
$this->assertSame(
$search,
$mailbox->sortMails(SORTARRIVAL, false, $search_criteria)
);
$this->assertSame(
$search,
$mailbox->sortMails(SORTARRIVAL, false, $search_criteria, 'UTF-8')
);
$this->assertTrue(\in_array(
$search[0],
$mailbox->sortMails(SORTARRIVAL, false, null),
true
));
$mailbox->deleteMail($search[0]);
$mailbox->expungeDeletedMails();
$mailbox->switchMailbox($path->getString());
$mailbox->deleteMailbox($remove_mailbox);
$this->assertCount(
0,
$mailbox->searchMailbox($search_criteria),
(
'If a subject was found,'.
' then the message is was not expunged as requested.'
)
);
}
/**
* @dataProvider AppendProvider
*
* @group live
*
* @depends testAppend
*
* @psalm-param MAILBOX_ARGS $mailbox_args
* @psalm-param COMPOSE_ENVELOPE $envelope
* @psalm-param COMPOSE_BODY $body
*/
public function testAppendRetrievalMatchesExpected(
array $mailbox_args,
array $envelope,
array $body,
string $expected_compose_result,
bool $pre_compose
): void {
if ($this->MaybeSkipAppendTest($envelope)) {
return;
}
[$search_criteria, $search_subject] = $this->SubjectSearchCriteriaAndSubject($envelope);
[$mailbox, $remove_mailbox, $path] = $this->getMailboxFromArgs(
$mailbox_args
);
$message = [$envelope, $body];
if ($pre_compose) {
$message = Imap::mail_compose($envelope, $body);
}
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
0,
$search,
(
'If a subject was found,'.
' then the message is insufficiently unique to assert that'.
' a newly-appended message was actually created.'
)
);
$mailbox->appendMessageToMailbox($message);
$search = $mailbox->searchMailbox($search_criteria);
$this->assertCount(
1,
$search,
(
'If a subject was not found, '.
' then Mailbox::appendMessageToMailbox() failed'.
' despite not throwing an exception.'
)
);
$actual_result = $mailbox->getMailMboxFormat($search[0]);
$this->assertSame(
$this->ReplaceBoundaryHere(
$expected_compose_result,
$actual_result
),
$actual_result
);
$actual_result = $mailbox->getRawMail($search[0]);
$this->assertSame(
$this->ReplaceBoundaryHere(
$expected_compose_result,
$actual_result
),
$actual_result
);
$mail = $mailbox->getMail($search[0], false);
$this->assertSame(
$search_subject,
$mail->subject,
(
'If a retrieved mail did not have a matching subject'.
' despite being found via search,'.
' then something has gone wrong.'
)
);
$info = $mailbox->getMailsInfo($search);
$this->assertCount(1, $info);
$this->assertSame(
$search_subject,
$info[0]->subject,
(
'If a retrieved mail did not have a matching subject'.
' despite being found via search,'.
' then something has gone wrong.'
)
);
if (1 === \preg_match(
'/^barbushin\/php-imap#(448|391):/',
$envelope['subject'] ?? '',
$matches
)) {
$this->assertTrue($mail->hasAttachments());
$attachments = $mail->getAttachments();
$this->assertCount(self::ISSUE_EXPECTED_ATTACHMENT_COUNT[
(int) $matches[1]],
$attachments
);
if ('448' === $matches[1]) {
$this->assertSame(
\file_get_contents(__DIR__.'/../../.gitignore'),
\current($attachments)->getContents()
);
}
}
$mailbox->deleteMail($search[0]);
$mailbox->expungeDeletedMails();
$mailbox->switchMailbox($path->getString());
$mailbox->deleteMailbox($remove_mailbox);
$this->assertCount(
0,
$mailbox->searchMailbox($search_criteria),
(
'If a subject was found,'.
' then the message is was not expunged as requested.'
)
);
}
/**
* @param string $expected_result
* @param string $actual_result
*
* @return string
*
* @psalm-pure
*/
protected function ReplaceBoundaryHere(
$expected_result,
$actual_result
) {
if (
1 === \preg_match('/{{REPLACE_BOUNDARY_HERE}}/', $expected_result) &&
1 === \preg_match(
'/Content-Type: MULTIPART\/MIXED; BOUNDARY="([^"]+)"/',
$actual_result,
$matches
)
) {
$expected_result = \str_replace(
'{{REPLACE_BOUNDARY_HERE}}',
$matches[1],
$expected_result
);
}
return $expected_result;
}
}

View File

@@ -0,0 +1,90 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use ParagonIE\HiddenString\HiddenString;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
*/
trait LiveMailboxTestingTrait
{
/**
* Provides constructor arguments for a live mailbox.
*
* @psalm-return array{'CI ENV'?: array{0: \ParagonIE\HiddenString\HiddenString, 1: \ParagonIE\HiddenString\HiddenString, 2: \ParagonIE\HiddenString\HiddenString, 3: string}}
*
* @return (\ParagonIE\HiddenString\HiddenString|string)[][]
*/
public function MailBoxProvider(): array
{
$sets = [];
$imapPath = \getenv('PHPIMAP_IMAP_PATH');
$login = \getenv('PHPIMAP_LOGIN');
$password = \getenv('PHPIMAP_PASSWORD');
if (\is_string($imapPath) && \is_string($login) && \is_string($password)) {
$sets['CI ENV'] = [new HiddenString($imapPath), new HiddenString($login), new HiddenString($password, true, true), \sys_get_temp_dir()];
}
return $sets;
}
/**
* Get instance of Mailbox, pre-set to a random mailbox.
*
* @param string $attachmentsDir
* @param string $serverEncoding
*
* @return (Mailbox|\ParagonIE\HiddenString\HiddenString|string)[]
*
* @psalm-return array{0: Mailbox, 1: string, 2: \ParagonIE\HiddenString\HiddenString}
*/
protected function getMailbox(HiddenString $imapPath, HiddenString $login, HiddenString $password, $attachmentsDir, $serverEncoding = 'UTF-8'): array
{
$mailbox = new Mailbox($imapPath->getString(), $login->getString(), $password->getString(), $attachmentsDir, $serverEncoding);
$random = 'test-box-'.\date('c').\bin2hex(\random_bytes(4));
$mailbox->createMailbox($random);
$mailbox->switchMailbox($random, false);
return [$mailbox, $random, $imapPath];
}
/**
* @psalm-param MAILBOX_ARGS $mailbox_args
*
* @return mixed[]
*
* @psalm-return array{0:Mailbox, 1:string, 2:HiddenString}
*/
protected function getMailboxFromArgs(array $mailbox_args): array
{
[$path, $username, $password, $attachments_dir] = $mailbox_args;
return $this->getMailbox(
$path,
$username,
$password,
$attachments_dir,
$mailbox_args[4] ?? 'UTF-8'
);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);
namespace PhpImap;
use Generator;
use ParagonIE\HiddenString\HiddenString;
/**
* @psalm-type MAILBOX_ARGS = array{
* 0:HiddenString,
* 1:HiddenString,
* 2:HiddenString,
* 3:string,
* 4?:string
* }
*/
class LiveMailboxWithManualSetupTest extends AbstractLiveMailboxTest
{
/**
* @psalm-return Generator<int, array{0: '.issue-499.Éléments envoyés'}, mixed, void>
*/
public function RelativeToRootPathProvider(): Generator
{
yield [
'.issue-499.Éléments envoyés',
];
}
/**
* @psalm-return Generator<int, array{0: array{0: HiddenString, 1: HiddenString, 2: HiddenString, 3: string, 4?: string}}, mixed, void>
*/
public function statusProviderAbsolutePath(): Generator
{
foreach ($this->RelativeToRootPathProvider() as $path_args) {
foreach ($this->MailBoxProvider() as $args) {
$args[0] = new HiddenString($args[0]->getString().$path_args[0]);
yield [$args];
}
}
}
/**
* Tests the status of an absolute mailbox path set from the Mailbox constructor.
*
* @dataProvider statusProviderAbsolutePath
*
* @group live
* @group live-manual
*
* @psalm-param MAILBOX_ARGS $mailbox_args
*/
public function testAbsolutePathStatusFromConstruction(
array $mailbox_args
): void {
[$mailbox] = $this->getMailboxFromArgs($mailbox_args);
$mailbox->statusMailbox();
$this->assertTrue(true);
}
}

View File

@@ -0,0 +1,814 @@
<?php
/**
* Mailbox - PHPUnit tests.
*
* @author Sebastian Kraetzig <sebastian-kraetzig@gmx.de>
*/
declare(strict_types=1);
namespace PhpImap;
use const CL_EXPUNGE;
use DateTime;
use Generator;
use const IMAP_CLOSETIMEOUT;
use const IMAP_OPENTIMEOUT;
use const IMAP_READTIMEOUT;
use const IMAP_WRITETIMEOUT;
use const OP_ANONYMOUS;
use const OP_DEBUG;
use const OP_HALFOPEN;
use const OP_PROTOTYPE;
use const OP_READONLY;
use const OP_SECURE;
use const OP_SHORTCACHE;
use const OP_SILENT;
use PhpImap\Exceptions\InvalidParameterException;
use PHPUnit\Framework\TestCase;
use const SE_FREE;
use const SE_UID;
final class MailboxTest extends TestCase
{
public const ANYTHING = 0;
/**
* Holds the imap path.
*
* @var string
*/
private $imapPath = '{imap.example.com:993/imap/ssl/novalidate-cert}INBOX';
/**
* Holds the imap username.
*
* @var string|email
*
* @psalm-var string
*/
private $login = 'php-imap@example.com';
/**
* Holds the imap user password.
*
* @var string
*/
private $password = 'v3rY!53cEt&P4sSWöRd$';
/**
* Holds the relative name of the directory, where email attachments will be saved.
*
* @var string
*/
private $attachmentsDir = '.';
/**
* Holds the server encoding setting.
*
* @var string
*/
private $serverEncoding = 'UTF-8';
/**
* Test, that the constructor trims possible variables
* Leading and ending spaces are not even possible in some variables.
*/
public function testConstructorTrimsPossibleVariables(): void
{
$imapPath = ' {imap.example.com:993/imap/ssl}INBOX ';
$login = ' php-imap@example.com';
$password = ' v3rY!53cEt&P4sSWöRd$';
// directory names can contain spaces before AND after on Linux/Unix systems. Windows trims these spaces automatically.
$attachmentsDir = '.';
$serverEncoding = 'UTF-8 ';
$mailbox = new Fixtures\Mailbox($imapPath, $login, $password, $attachmentsDir, $serverEncoding);
$this->assertSame('{imap.example.com:993/imap/ssl}INBOX', $mailbox->getImapPath());
$this->assertSame('php-imap@example.com', $mailbox->getLogin());
$this->assertSame(' v3rY!53cEt&P4sSWöRd$', $mailbox->getImapPassword());
$this->assertSame(\realpath('.'), $mailbox->getAttachmentsDir());
$this->assertSame('UTF-8', $mailbox->getServerEncoding());
}
/**
* @psalm-return non-empty-list<array{0: 'UTF-8'|'Windows-1251'|'Windows-1252'}>
*
* @return string[][]
*/
public function SetAndGetServerEncodingProvider(): array
{
$data = [
['UTF-8'],
];
$supported = \mb_list_encodings();
foreach (
[
'Windows-1251',
'Windows-1252',
] as $perhaps
) {
if (
\in_array(\trim($perhaps), $supported, true) ||
\in_array(\strtoupper(\trim($perhaps)), $supported, true)
) {
$data[] = [$perhaps];
}
}
return $data;
}
/**
* Test, that the server encoding can be set.
*
* @dataProvider SetAndGetServerEncodingProvider
*/
public function testSetAndGetServerEncoding(string $encoding): void
{
$mailbox = $this->getMailbox();
$mailbox->setServerEncoding($encoding);
$encoding = \strtoupper(\trim($encoding));
$this->assertEquals($mailbox->getServerEncoding(), $encoding);
}
/**
* Test, that server encoding is set to a default value.
*/
public function testServerEncodingHasDefaultSetting(): void
{
// Default character encoding should be set
$mailbox = new Mailbox($this->imapPath, $this->login, $this->password, $this->attachmentsDir);
$this->assertSame('UTF-8', $mailbox->getServerEncoding());
}
/**
* Test, that server encoding that all functions uppers the server encoding setting.
*/
public function testServerEncodingUppersSetting(): void
{
// Server encoding should be always upper formatted
$mailbox = new Mailbox($this->imapPath, $this->login, $this->password, $this->attachmentsDir, 'utf-8');
$this->assertSame('UTF-8', $mailbox->getServerEncoding());
$mailbox = new Mailbox($this->imapPath, $this->login, $this->password, $this->attachmentsDir, 'UTF7-IMAP');
$mailbox->setServerEncoding('uTf-8');
$this->assertSame('UTF-8', $mailbox->getServerEncoding());
}
/**
* Provides test data for testing server encodings.
*
* @return (bool|string)[][]
*
* @psalm-return array{UTF-7: array{0: true, 1: 'UTF-7'}, UTF7-IMAP: array{0: true, 1: 'UTF7-IMAP'}, UTF-8: array{0: true, 1: 'UTF-8'}, ASCII: array{0: true, 1: 'ASCII'}, US-ASCII: array{0: true, 1: 'US-ASCII'}, ISO-8859-1: array{0: true, 1: 'ISO-8859-1'}, UTF7: array{0: false, 1: 'UTF7'}, UTF-7-IMAP: array{0: false, 1: 'UTF-7-IMAP'}, UTF-7IMAP: array{0: false, 1: 'UTF-7IMAP'}, UTF8: array{0: false, 1: 'UTF8'}, USASCII: array{0: false, 1: 'USASCII'}, ASC11: array{0: false, 1: 'ASC11'}, ISO-8859-0: array{0: false, 1: 'ISO-8859-0'}, ISO-8855-1: array{0: false, 1: 'ISO-8855-1'}, ISO-8859: array{0: false, 1: 'ISO-8859'}}
*/
public function serverEncodingProvider(): array
{
return [
// Supported encodings
'UTF-7' => [true, 'UTF-7'],
'UTF7-IMAP' => [true, 'UTF7-IMAP'],
'UTF-8' => [true, 'UTF-8'],
'ASCII' => [true, 'ASCII'],
'US-ASCII' => [true, 'US-ASCII'],
'ISO-8859-1' => [true, 'ISO-8859-1'],
// NOT supported encodings
'UTF7' => [false, 'UTF7'],
'UTF-7-IMAP' => [false, 'UTF-7-IMAP'],
'UTF-7IMAP' => [false, 'UTF-7IMAP'],
'UTF8' => [false, 'UTF8'],
'USASCII' => [false, 'USASCII'],
'ASC11' => [false, 'ASC11'],
'ISO-8859-0' => [false, 'ISO-8859-0'],
'ISO-8855-1' => [false, 'ISO-8855-1'],
'ISO-8859' => [false, 'ISO-8859'],
];
}
/**
* Test, that server encoding only can use supported character encodings.
*
* @dataProvider serverEncodingProvider
*/
public function testServerEncodingOnlyUseSupportedSettings(bool $bool, string $encoding): void
{
$mailbox = $this->getMailbox();
if ($bool) {
$mailbox->setServerEncoding($encoding);
$this->assertEquals($encoding, $mailbox->getServerEncoding());
} else {
$this->expectException(InvalidParameterException::class);
$mailbox->setServerEncoding($encoding);
$this->assertNotEquals($encoding, $mailbox->getServerEncoding());
}
}
/**
* Test, that the IMAP search option has a default value
* 1 => SE_UID
* 2 => SE_FREE.
*/
public function testImapSearchOptionHasADefault(): void
{
$this->assertEquals($this->getMailbox()->getImapSearchOption(), 1);
}
/**
* Test, that the IMAP search option can be changed
* 1 => SE_UID
* 2 => SE_FREE.
*/
public function testSetAndGetImapSearchOption(): void
{
$mailbox = $this->getMailbox();
$mailbox->setImapSearchOption(SE_FREE);
$this->assertEquals($mailbox->getImapSearchOption(), 2);
$this->expectException(InvalidParameterException::class);
$mailbox->setImapSearchOption(self::ANYTHING);
$mailbox->setImapSearchOption(SE_UID);
$this->assertEquals($mailbox->getImapSearchOption(), 1);
}
/**
* Test, that the imap login can be retrieved.
*/
public function testGetLogin(): void
{
$this->assertEquals($this->getMailbox()->getLogin(), 'php-imap@example.com');
}
/**
* Test, that the path delimiter has a default value.
*/
public function testPathDelimiterHasADefault(): void
{
$this->assertNotEmpty($this->getMailbox()->getPathDelimiter());
}
/**
* Provides test data for testing path delimiter.
*
* @psalm-return array{0: array{0: '0'}, 1: array{0: '1'}, 2: array{0: '2'}, 3: array{0: '3'}, 4: array{0: '4'}, 5: array{0: '5'}, 6: array{0: '6'}, 7: array{0: '7'}, 8: array{0: '8'}, 9: array{0: '9'}, a: array{0: 'a'}, b: array{0: 'b'}, c: array{0: 'c'}, d: array{0: 'd'}, e: array{0: 'e'}, f: array{0: 'f'}, g: array{0: 'g'}, h: array{0: 'h'}, i: array{0: 'i'}, j: array{0: 'j'}, k: array{0: 'k'}, l: array{0: 'l'}, m: array{0: 'm'}, n: array{0: 'n'}, o: array{0: 'o'}, p: array{0: 'p'}, q: array{0: 'q'}, r: array{0: 'r'}, s: array{0: 's'}, t: array{0: 't'}, u: array{0: 'u'}, v: array{0: 'v'}, w: array{0: 'w'}, x: array{0: 'x'}, y: array{0: 'y'}, z: array{0: 'z'}, !: array{0: '!'}, '\\': array{0: '\'}, $: array{0: '$'}, %: array{0: '%'}, §: array{0: '§'}, &: array{0: '&'}, /: array{0: '/'}, (: array{0: '('}, ): array{0: ')'}, =: array{0: '='}, #: array{0: '#'}, ~: array{0: '~'}, *: array{0: '*'}, +: array{0: '+'}, ,: array{0: ','}, ;: array{0: ';'}, '.': array{0: '.'}, ':': array{0: ':'}, <: array{0: '<'}, >: array{0: '>'}, |: array{0: '|'}, _: array{0: '_'}}
*
* @return string[][]
*/
public function pathDelimiterProvider(): array
{
return [
'0' => ['0'],
'1' => ['1'],
'2' => ['2'],
'3' => ['3'],
'4' => ['4'],
'5' => ['5'],
'6' => ['6'],
'7' => ['7'],
'8' => ['8'],
'9' => ['9'],
'a' => ['a'],
'b' => ['b'],
'c' => ['c'],
'd' => ['d'],
'e' => ['e'],
'f' => ['f'],
'g' => ['g'],
'h' => ['h'],
'i' => ['i'],
'j' => ['j'],
'k' => ['k'],
'l' => ['l'],
'm' => ['m'],
'n' => ['n'],
'o' => ['o'],
'p' => ['p'],
'q' => ['q'],
'r' => ['r'],
's' => ['s'],
't' => ['t'],
'u' => ['u'],
'v' => ['v'],
'w' => ['w'],
'x' => ['x'],
'y' => ['y'],
'z' => ['z'],
'!' => ['!'],
'\\' => ['\\'],
'$' => ['$'],
'%' => ['%'],
'§' => ['§'],
'&' => ['&'],
'/' => ['/'],
'(' => ['('],
')' => [')'],
'=' => ['='],
'#' => ['#'],
'~' => ['~'],
'*' => ['*'],
'+' => ['+'],
',' => [','],
';' => [';'],
'.' => ['.'],
':' => [':'],
'<' => ['<'],
'>' => ['>'],
'|' => ['|'],
'_' => ['_'],
];
}
/**
* Test, that the path delimiter is checked for supported chars.
*
* @dataProvider pathDelimiterProvider
*/
public function testPathDelimiterIsBeingChecked(string $str): void
{
$supported_delimiters = ['.', '/'];
$mailbox = $this->getMailbox();
if (\in_array($str, $supported_delimiters)) {
$this->assertTrue($mailbox->validatePathDelimiter($str));
} else {
$this->expectException(InvalidParameterException::class);
$mailbox->setPathDelimiter($str);
}
}
/**
* Test, that the path delimiter can be set.
*/
public function testSetAndGetPathDelimiter(): void
{
$mailbox = $this->getMailbox();
$mailbox->setPathDelimiter('.');
$this->assertEquals($mailbox->getPathDelimiter(), '.');
$mailbox->setPathDelimiter('/');
$this->assertEquals($mailbox->getPathDelimiter(), '/');
}
/**
* Test, that the attachments are not ignored by default.
*/
public function testGetAttachmentsAreNotIgnoredByDefault(): void
{
$this->assertEquals($this->getMailbox()->getAttachmentsIgnore(), false);
}
/**
* Provides test data for testing attachments ignore.
*
* @psalm-return array<string, array{0:bool}>
*/
public function attachmentsIgnoreProvider(): array
{
/** @psalm-var array<string, array{0:bool}> */
return [
'true' => [true],
'false' => [false],
];
}
/**
* Test, that attachments can be ignored and only valid values are accepted.
*
* @dataProvider attachmentsIgnoreProvider
*/
public function testSetAttachmentsIgnore(bool $paramValue): void
{
$mailbox = $this->getMailbox();
$mailbox->setAttachmentsIgnore($paramValue);
$this->assertEquals($mailbox->getAttachmentsIgnore(), $paramValue);
}
/**
* Provides test data for testing encoding.
*
* @psalm-return array{Avañeẽ: array{0: 'Avañeẽ'}, azərbaycanca: array{0: 'azərbaycanca'}, Bokmål: array{0: 'Bokmål'}, chiCheŵa: array{0: 'chiCheŵa'}, Deutsch: array{0: 'Deutsch'}, 'U.S. English': array{0: 'U.S. English'}, français: array{0: 'français'}, 'Éléments envoyés': array{0: 'Éléments envoyés'}, føroyskt: array{0: 'føroyskt'}, Kĩmĩrũ: array{0: 'Kĩmĩrũ'}, Kɨlaangi: array{0: 'Kɨlaangi'}, oʼzbekcha: array{0: 'oʼzbekcha'}, Plattdüütsch: array{0: 'Plattdüütsch'}, română: array{0: 'română'}, Sängö: array{0: 'Sängö'}, 'Tiếng Việt': array{0: 'Tiếng Việt'}, ɔl-Maa: array{0: 'ɔl-Maa'}, Ελληνικά: array{0: 'Ελληνικά'}, Ўзбек: array{0: 'Ўзбек'}, Азәрбајҹан: array{0: 'Азәрбајҹан'}, Српски: array{0: 'Српски'}, русский: array{0: 'русский'}, 'ѩзыкъ словѣньскъ': array{0: 'ѩзыкъ словѣньскъ'}, العربية: array{0: 'العربية'}, नेपाली: array{0: 'नेपाली'}, 日本語: array{0: '日本語'}, 简体中文: array{0: '简体中文'}, 繁體中文: array{0: '繁體中文'}, 한국어: array{0: '한국어'}, ąčęėįšųūžĄČĘĖĮŠŲŪŽ: array{0: 'ąčęėįšųūžĄČĘĖĮŠŲŪŽ'}}
*
* @return string[][]
*/
public function encodingTestStringsProvider(): array
{
return [
'Avañeẽ' => ['Avañeẽ'], // Guaraní
'azərbaycanca' => ['azərbaycanca'], // Azerbaijani (Latin)
'Bokmål' => ['Bokmål'], // Norwegian Bokmål
'chiCheŵa' => ['chiCheŵa'], // Chewa
'Deutsch' => ['Deutsch'], // German
'U.S. English' => ['U.S. English'], // U.S. English
'français' => ['français'], // French
'Éléments envoyés' => ['Éléments envoyés'], // issue 499
'føroyskt' => ['føroyskt'], // Faroese
'Kĩmĩrũ' => ['Kĩmĩrũ'], // Kimîîru
'Kɨlaangi' => ['Kɨlaangi'], // Langi
'oʼzbekcha' => ['oʼzbekcha'], // Uzbek (Latin)
'Plattdüütsch' => ['Plattdüütsch'], // Low German
'română' => ['română'], // Romanian
'Sängö' => ['Sängö'], // Sango
'Tiếng Việt' => ['Tiếng Việt'], // Vietnamese
'ɔl-Maa' => ['ɔl-Maa'], // Masai
'Ελληνικά' => ['Ελληνικά'], // Greek
'Ўзбек' => ['Ўзбек'], // Uzbek (Cyrillic)
'Азәрбајҹан' => ['Азәрбајҹан'], // Azerbaijani (Cyrillic)
'Српски' => ['Српски'], // Serbian (Cyrillic)
'русский' => ['русский'], // Russian
'ѩзыкъ словѣньскъ' => ['ѩзыкъ словѣньскъ'], // Church Slavic
'العربية' => ['العربية'], // Arabic
'नेपाली' => ['नेपाली'], // Nepali
'日本語' => ['日本語'], // Japanese
'简体中文' => ['简体中文'], // Chinese (Simplified)
'繁體中文' => ['繁體中文'], // Chinese (Traditional)
'한국어' => ['한국어'], // Korean
'ąčęėįšųūžĄČĘĖĮŠŲŪŽ' => ['ąčęėįšųūžĄČĘĖĮŠŲŪŽ'], // Lithuanian letters
];
}
/**
* Test, that strings encoded to UTF-7 can be decoded back to UTF-8.
*
* @dataProvider encodingTestStringsProvider
*/
public function testEncodingToUtf7DecodeBackToUtf8(string $str): void
{
$mailbox = $this->getMailbox();
$utf7_encoded_str = $mailbox->encodeStringToUtf7Imap($str);
$utf8_decoded_str = $mailbox->decodeStringFromUtf7ImapToUtf8($utf7_encoded_str);
$this->assertEquals($utf8_decoded_str, $str);
}
/**
* Test, that strings encoded to UTF-7 can be decoded back to UTF-8.
*
* @dataProvider encodingTestStringsProvider
*/
public function testMimeDecodingReturnsCorrectValues(string $str): void
{
$this->assertEquals($this->getMailbox()->decodeMimeStr($str), $str);
}
/**
* Provides test data for testing parsing datetimes.
*
* @psalm-return array{'Sun, 14 Aug 2005 16:13:03 +0000 (CEST)': array{0: '2005-08-14T16:13:03+00:00', 1: 1124035983}, 'Sun, 14 Aug 2005 16:13:03 +0000': array{0: '2005-08-14T16:13:03+00:00', 1: 1124035983}, 'Sun, 14 Aug 2005 16:13:03 +1000 (CEST)': array{0: '2005-08-14T06:13:03+00:00', 1: 1123999983}, 'Sun, 14 Aug 2005 16:13:03 +1000': array{0: '2005-08-14T06:13:03+00:00', 1: 1123999983}, 'Sun, 14 Aug 2005 16:13:03 -1000': array{0: '2005-08-15T02:13:03+00:00', 1: 1124071983}, 'Sun, 14 Aug 2005 16:13:03 +1100 (CEST)': array{0: '2005-08-14T05:13:03+00:00', 1: 1123996383}, 'Sun, 14 Aug 2005 16:13:03 +1100': array{0: '2005-08-14T05:13:03+00:00', 1: 1123996383}, 'Sun, 14 Aug 2005 16:13:03 -1100': array{0: '2005-08-15T03:13:03+00:00', 1: 1124075583}, '14 Aug 2005 16:13:03 +1000 (CEST)': array{0: '2005-08-14T06:13:03+00:00', 1: 1123999983}, '14 Aug 2005 16:13:03 +1000': array{0: '2005-08-14T06:13:03+00:00', 1: 1123999983}, '14 Aug 2005 16:13:03 -1000': array{0: '2005-08-15T02:13:03+00:00', 1: 1124071983}}
*
* @return (int|string)[][]
*/
public function datetimeProvider(): array
{
return [
'Sun, 14 Aug 2005 16:13:03 +0000 (CEST)' => ['2005-08-14T16:13:03+00:00', 1124035983],
'Sun, 14 Aug 2005 16:13:03 +0000' => ['2005-08-14T16:13:03+00:00', 1124035983],
'Sun, 14 Aug 2005 16:13:03 +1000 (CEST)' => ['2005-08-14T06:13:03+00:00', 1123999983],
'Sun, 14 Aug 2005 16:13:03 +1000' => ['2005-08-14T06:13:03+00:00', 1123999983],
'Sun, 14 Aug 2005 16:13:03 -1000' => ['2005-08-15T02:13:03+00:00', 1124071983],
'Sun, 14 Aug 2005 16:13:03 +1100 (CEST)' => ['2005-08-14T05:13:03+00:00', 1123996383],
'Sun, 14 Aug 2005 16:13:03 +1100' => ['2005-08-14T05:13:03+00:00', 1123996383],
'Sun, 14 Aug 2005 16:13:03 -1100' => ['2005-08-15T03:13:03+00:00', 1124075583],
'14 Aug 2005 16:13:03 +1000 (CEST)' => ['2005-08-14T06:13:03+00:00', 1123999983],
'14 Aug 2005 16:13:03 +1000' => ['2005-08-14T06:13:03+00:00', 1123999983],
'14 Aug 2005 16:13:03 -1000' => ['2005-08-15T02:13:03+00:00', 1124071983],
];
}
/**
* Test, different datetimes conversions using differents timezones.
*
* @dataProvider datetimeProvider
*/
public function testParsedDateDifferentTimeZones(string $dateToParse, int $epochToCompare): void
{
$parsedDt = $this->getMailbox()->parseDateTime($dateToParse);
$parsedDateTime = new DateTime($parsedDt);
$this->assertEquals((int) $parsedDateTime->format('U'), $epochToCompare);
}
/**
* Provides test data for testing parsing invalid / unparseable datetimes.
*
* @psalm-return array{'Sun, 14 Aug 2005 16:13:03 +9000 (CEST)': array{0: 'Sun, 14 Aug 2005 16:13:03 +9000 (CEST)'}, 'Sun, 14 Aug 2005 16:13:03 +9000': array{0: 'Sun, 14 Aug 2005 16:13:03 +9000'}, 'Sun, 14 Aug 2005 16:13:03 -9000': array{0: 'Sun, 14 Aug 2005 16:13:03 -9000'}}
*
* @return string[][]
*/
public function invalidDatetimeProvider(): array
{
return [
'Sun, 14 Aug 2005 16:13:03 +9000 (CEST)' => ['Sun, 14 Aug 2005 16:13:03 +9000 (CEST)'],
'Sun, 14 Aug 2005 16:13:03 +9000' => ['Sun, 14 Aug 2005 16:13:03 +9000'],
'Sun, 14 Aug 2005 16:13:03 -9000' => ['Sun, 14 Aug 2005 16:13:03 -9000'],
];
}
/**
* Test, different invalid / unparseable datetimes conversions.
*
* @dataProvider invalidDatetimeProvider
*/
public function testParsedDateWithUnparseableDateTime(string $dateToParse): void
{
$parsedDt = $this->getMailbox()->parseDateTime($dateToParse);
$this->assertEquals($parsedDt, $dateToParse);
}
/**
* Test, parsed datetime being emtpy the header date.
*/
public function testParsedDateTimeWithEmptyHeaderDate(): void
{
$this->expectException(InvalidParameterException::class);
$this->getMailbox()->parseDateTime('');
}
/**
* Provides test data for testing mime encoding.
*
* @return string[][]
*
* @psalm-return array{0: array{0: '=?iso-8859-1?Q?Sebastian_Kr=E4tzig?= <sebastian.kraetzig@example.com>', 1: 'Sebastian Krätzig <sebastian.kraetzig@example.com>'}, 1: array{0: '=?iso-8859-1?Q?Sebastian_Kr=E4tzig?=', 1: 'Sebastian Krätzig'}, 2: array{0: 'sebastian.kraetzig', 1: 'sebastian.kraetzig'}, 3: array{0: '=?US-ASCII?Q?Keith_Moore?= <km@ab.example.edu>', 1: 'Keith Moore <km@ab.example.edu>'}, 4: array{0: ' ', 1: ' '}, 5: array{0: '=?ISO-8859-1?Q?Max_J=F8rn_Simsen?= <max.joern.s@example.dk>', 1: 'Max Jørn Simsen <max.joern.s@example.dk>'}, 6: array{0: '=?ISO-8859-1?Q?Andr=E9?= Muster <andre.muster@vm1.ulg.ac.be>', 1: 'André Muster <andre.muster@vm1.ulg.ac.be>'}, 7: array{0: '=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=', 1: 'If you can read this you understand the example.'}, 8: array{0: '', 1: ''}}
*/
public function mimeEncodingProvider(): array
{
return [
['=?iso-8859-1?Q?Sebastian_Kr=E4tzig?= <sebastian.kraetzig@example.com>', 'Sebastian Krätzig <sebastian.kraetzig@example.com>'],
['=?iso-8859-1?Q?Sebastian_Kr=E4tzig?=', 'Sebastian Krätzig'],
['sebastian.kraetzig', 'sebastian.kraetzig'],
['=?US-ASCII?Q?Keith_Moore?= <km@ab.example.edu>', 'Keith Moore <km@ab.example.edu>'],
[' ', ' '],
['=?ISO-8859-1?Q?Max_J=F8rn_Simsen?= <max.joern.s@example.dk>', 'Max Jørn Simsen <max.joern.s@example.dk>'],
['=?ISO-8859-1?Q?Andr=E9?= Muster <andre.muster@vm1.ulg.ac.be>', 'André Muster <andre.muster@vm1.ulg.ac.be>'],
['=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=', 'If you can read this you understand the example.'],
['', ''], // barbushin/php-imap#501
];
}
/**
* Test, that mime encoding returns correct strings.
*
* @dataProvider mimeEncodingProvider
*/
public function testMimeEncoding(string $str, string $expected): void
{
$mailbox = $this->getMailbox();
$this->assertEquals($mailbox->decodeMimeStr($str), $expected);
}
/**
* Provides test data for testing timeouts.
*
* @psalm-return array<string, array{0:'assertNull'|'expectException', 1:int, 2:list<1|2|3|4>}>
*/
public function timeoutsProvider(): array
{
/** @psalm-var array<string, array{0:'assertNull'|'expectException', 1:int, 2:list<int>}> */
return [
'array(IMAP_OPENTIMEOUT)' => ['assertNull', 1, [IMAP_OPENTIMEOUT]],
'array(IMAP_READTIMEOUT)' => ['assertNull', 1, [IMAP_READTIMEOUT]],
'array(IMAP_WRITETIMEOUT)' => ['assertNull', 1, [IMAP_WRITETIMEOUT]],
'array(IMAP_CLOSETIMEOUT)' => ['assertNull', 1, [IMAP_CLOSETIMEOUT]],
'array(IMAP_OPENTIMEOUT, IMAP_READTIMEOUT, IMAP_WRITETIMEOUT, IMAP_CLOSETIMEOUT)' => ['assertNull', 1, [IMAP_OPENTIMEOUT, IMAP_READTIMEOUT, IMAP_WRITETIMEOUT, IMAP_CLOSETIMEOUT]],
];
}
/**
* Test, that only supported timeouts can be set.
*
* @dataProvider timeoutsProvider
*
* @param int[] $types
*
* @psalm-param 'assertNull'|'expectException' $assertMethod
* @psalm-param list<1|2|3|4> $types
*/
public function testSetTimeouts(string $assertMethod, int $timeout, array $types): void
{
$mailbox = $this->getMailbox();
if ('expectException' == $assertMethod) {
$this->expectException(InvalidParameterException::class);
$mailbox->setTimeouts($timeout, $types);
} else {
$this->assertNull($mailbox->setTimeouts($timeout, $types));
}
}
/**
* Provides test data for testing connection args.
*
* @psalm-return Generator<string, array{0: 'assertNull'|'expectException', 1: int, 2: 0, 3: array<empty, empty>}, mixed, void>
*/
public function connectionArgsProvider(): Generator
{
yield from [
'readonly, disable gssapi' => ['assertNull', OP_READONLY, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'anonymous, disable gssapi' => ['assertNull', OP_ANONYMOUS, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'half open, disable gssapi' => ['assertNull', OP_HALFOPEN, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'expunge on close, disable gssapi' => ['assertNull', CL_EXPUNGE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'debug, disable gssapi' => ['assertNull', OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'short cache, disable gssapi' => ['assertNull', OP_SHORTCACHE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'silent, disable gssapi' => ['assertNull', OP_SILENT, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'return driver prototype, disable gssapi' => ['assertNull', OP_PROTOTYPE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'don\'t do non-secure authentication, disable gssapi' => ['assertNull', OP_SECURE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, disable gssapi, 1 retry' => ['assertNull', OP_READONLY, 1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, disable gssapi, 3 retries' => ['assertNull', OP_READONLY, 3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, disable gssapi, 12 retries' => ['assertNull', OP_READONLY, 12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly debug, disable gssapi' => ['assertNull', OP_READONLY | OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, -1 retries' => ['expectException', OP_READONLY, -1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, -3 retries' => ['expectException', OP_READONLY, -3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, -12 retries' => ['expectException', OP_READONLY, -12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']],
'readonly, null options' => ['expectException', OP_READONLY, 0, [null]],
];
/** @psalm-var list<array{0:int, 1:string}> */
$options = [
[OP_DEBUG, 'debug'], // 1
[OP_READONLY, 'readonly'], // 2
[OP_ANONYMOUS, 'anonymous'], // 4
[OP_SHORTCACHE, 'short cache'], // 8
[OP_SILENT, 'silent'], // 16
[OP_PROTOTYPE, 'return driver prototype'], // 32
[OP_HALFOPEN, 'half-open'], // 64
[OP_SECURE, 'don\'t do non-secure authnetication'], // 256
[CL_EXPUNGE, 'expunge on close'], // 32768
];
foreach ($options as $i => $option) {
$value = $option[0];
for ($j = $i + 1; $j < \count($options); ++$j) {
$value |= $options[$j][0];
$fields = [];
foreach ($options as $option) {
if (0 !== ($value & $option[0])) {
$fields[] = $option[1];
}
}
$key = \implode(', ', $fields);
yield $key => ['assertNull', $value, 0, []];
yield ('INVALID + '.$key) => ['expectException', $value | 128, 0, []];
}
}
}
/**
* Test, that only supported and valid connection args can be set.
*
* @dataProvider connectionArgsProvider
*
* @psalm-param array{DISABLE_AUTHENTICATOR?:string}|array<empty, empty> $param
*/
public function testSetConnectionArgs(string $assertMethod, int $option, int $retriesNum, array $param = null): void
{
$mailbox = $this->getMailbox();
if ('expectException' == $assertMethod) {
$this->expectException(InvalidParameterException::class);
$mailbox->setConnectionArgs($option, $retriesNum, $param);
$this->assertSame($option, $mailbox->getImapOptions());
} elseif ('assertNull' == $assertMethod) {
$this->assertNull($mailbox->setConnectionArgs($option, $retriesNum, $param));
}
$mailbox->disconnect();
}
/**
* Provides test data for testing mime string decoding.
*
* @psalm-return array{'<bde36ec8-9710-47bc-9ea3-bf0425078e33@php.imap>': array{0: '<bde36ec8-9710-47bc-9ea3-bf0425078e33@php.imap>', 1: '<bde36ec8-9710-47bc-9ea3-bf0425078e33@php.imap>'}, '<CAKBqNfyKo+ZXtkz6DUAHw6FjmsDjWDB-pvHkJy6kwO82jTbkNA@mail.gmail.com>': array{0: '<CAKBqNfyKo+ZXtkz6DUAHw6FjmsDjWDB-pvHkJy6kwO82jTbkNA@mail.gmail.com>', 1: '<CAKBqNfyKo+ZXtkz6DUAHw6FjmsDjWDB-pvHkJy6kwO82jTbkNA@mail.gmail.com>'}, '<CAE78dO7vwnd_rkozHLZ5xSUnFEQA9fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>': array{0: '<CAE78dO7vwnd_rkozHLZ5xSUnFEQA9fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>', 1: '<CAE78dO7vwnd_rkozHLZ5xSUnFEQA9fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>'}, '<CAE78dO7vwnd_rkozHLZ5xSU-=nFE_QA9+fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>': array{0: '<CAE78dO7vwnd_rkozHLZ5xSU-=nFE_QA9+fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>', 1: '<CAE78dO7vwnd_rkozHLZ5xSU-=nFE_QA9+fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>'}, 'Some subject here 😘': array{0: '=?UTF-8?q?Some_subject_here_?= =?UTF-8?q?=F0=9F=98=98?=', 1: 'Some subject here 😘'}, mountainguan测试: array{0: '=?UTF-8?Q?mountainguan=E6=B5=8B=E8=AF=95?=', 1: 'mountainguan测试'}, 'This is the Euro symbol \'\'.': array{0: 'This is the Euro symbol ''.', 1: 'This is the Euro symbol ''.'}, 'Some subject here 😘 US-ASCII': array{0: '=?UTF-8?q?Some_subject_here_?= =?UTF-8?q?=F0=9F=98=98?=', 1: 'Some subject here 😘', 2: 'US-ASCII'}, 'mountainguan测试 US-ASCII': array{0: '=?UTF-8?Q?mountainguan=E6=B5=8B=E8=AF=95?=', 1: 'mountainguan测试', 2: 'US-ASCII'}, 'مقتطفات من: صن تزو. \"فن الحرب\". كتب أبل. Something': array{0: 'مقتطفات من: صن تزو. "فن الحرب". كتب أبل. Something', 1: 'مقتطفات من: صن تزو. "فن الحرب". كتب أبل. Something'}, '(事件单编号:TESTA-111111)(通报)入口有陌生人': array{0: '=?utf-8?b?KOS6i+S7tuWNlee8luWPtzpURVNUQS0xMTExMTEpKOmAmuaKpSnl?= =?utf-8?b?haXlj6PmnInpmYznlJ/kuro=?=', 1: '(事件单编号:TESTA-111111)(通报)入口有陌生人'}}
*
* @return string[][]
*/
public function mimeStrDecodingProvider(): array
{
return [
'<bde36ec8-9710-47bc-9ea3-bf0425078e33@php.imap>' => ['<bde36ec8-9710-47bc-9ea3-bf0425078e33@php.imap>', '<bde36ec8-9710-47bc-9ea3-bf0425078e33@php.imap>'],
'<CAKBqNfyKo+ZXtkz6DUAHw6FjmsDjWDB-pvHkJy6kwO82jTbkNA@mail.gmail.com>' => ['<CAKBqNfyKo+ZXtkz6DUAHw6FjmsDjWDB-pvHkJy6kwO82jTbkNA@mail.gmail.com>', '<CAKBqNfyKo+ZXtkz6DUAHw6FjmsDjWDB-pvHkJy6kwO82jTbkNA@mail.gmail.com>'],
'<CAE78dO7vwnd_rkozHLZ5xSUnFEQA9fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>' => ['<CAE78dO7vwnd_rkozHLZ5xSUnFEQA9fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>', '<CAE78dO7vwnd_rkozHLZ5xSUnFEQA9fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>'],
'<CAE78dO7vwnd_rkozHLZ5xSU-=nFE_QA9+fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>' => ['<CAE78dO7vwnd_rkozHLZ5xSU-=nFE_QA9+fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>', '<CAE78dO7vwnd_rkozHLZ5xSU-=nFE_QA9+fymcYREW2cwQ8DA2v7BTA@mail.gmail.com>'],
'Some subject here 😘' => ['=?UTF-8?q?Some_subject_here_?= =?UTF-8?q?=F0=9F=98=98?=', 'Some subject here 😘'],
'mountainguan测试' => ['=?UTF-8?Q?mountainguan=E6=B5=8B=E8=AF=95?=', 'mountainguan测试'],
"This is the Euro symbol ''." => ["This is the Euro symbol ''.", "This is the Euro symbol ''."],
'Some subject here 😘 US-ASCII' => ['=?UTF-8?q?Some_subject_here_?= =?UTF-8?q?=F0=9F=98=98?=', 'Some subject here 😘', 'US-ASCII'],
'mountainguan测试 US-ASCII' => ['=?UTF-8?Q?mountainguan=E6=B5=8B=E8=AF=95?=', 'mountainguan测试', 'US-ASCII'],
'مقتطفات من: صن تزو. "فن الحرب". كتب أبل. Something' => ['مقتطفات من: صن تزو. "فن الحرب". كتب أبل. Something', 'مقتطفات من: صن تزو. "فن الحرب". كتب أبل. Something'],
'(事件单编号:TESTA-111111)(通报)入口有陌生人' => ['=?utf-8?b?KOS6i+S7tuWNlee8luWPtzpURVNUQS0xMTExMTEpKOmAmuaKpSnl?= =?utf-8?b?haXlj6PmnInpmYznlJ/kuro=?=', '(事件单编号:TESTA-111111)(通报)入口有陌生人'],
];
}
/**
* Test, that decoding mime strings return unchanged / not broken strings.
*
* @dataProvider mimeStrDecodingProvider
*/
public function testDecodeMimeStr(string $str, string $expectedStr, string $serverEncoding = 'utf-8'): void
{
$mailbox = $this->getMailbox();
$mailbox->setServerEncoding($serverEncoding);
$this->assertEquals($mailbox->decodeMimeStr($str), $expectedStr);
}
/**
* Provides test data for testing base64 string decoding.
*
* @psalm-return array{0: array{0: 'bm8tcmVwbHlAZXhhbXBsZS5jb20=', 1: 'no-reply@example.com'}, 1: array{0: 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=', 1: 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.'}, 2: array{0: 'SSBjYW4gZWF0IGdsYXNzIGFuZCBpdCBkb2VzIG5vdCBodXJ0IG1lLg==', 1: 'I can eat glass and it does not hurt me.'}, 3: array{0: '77u/4KSV4KS+4KSa4KSCIOCktuCkleCljeCkqOCli+CkruCljeCkr+CkpOCljeCkpOClgeCkruCljSDgpaQg4KSo4KWL4KSq4KS54KS/4KSo4KS44KWN4KSk4KS/IOCkruCkvuCkruCljSDgpaU=', 1: 'काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥'}, 4: array{0: 'SmUgcGV1eCBtYW5nZXIgZHUgdmVycmUsIMOnYSBuZSBtZSBmYWl0IHBhcyBtYWwu', 1: 'Je peux manger du verre, ça ne me fait pas mal.'}, 5: array{0: 'UG90IHPEgyBtxINuw6JuYyBzdGljbMSDIMiZaSBlYSBudSBtxIMgcsSDbmXImXRlLg==', 1: 'Pot să mănânc sticlă și ea nu mă rănește.'}, 6: array{0: '5oiR6IO95ZCe5LiL546755KD6ICM5LiN5YK36Lqr6auU44CC', 1: '我能吞下玻璃而不傷身體。'}}
*
* @return string[][]
*/
public function Base64DecodeProvider(): array
{
return [
['bm8tcmVwbHlAZXhhbXBsZS5jb20=', 'no-reply@example.com'],
['TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=', 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.'],
['SSBjYW4gZWF0IGdsYXNzIGFuZCBpdCBkb2VzIG5vdCBodXJ0IG1lLg==', 'I can eat glass and it does not hurt me.'],
['77u/4KSV4KS+4KSa4KSCIOCktuCkleCljeCkqOCli+CkruCljeCkr+CkpOCljeCkpOClgeCkruCljSDgpaQg4KSo4KWL4KSq4KS54KS/4KSo4KS44KWN4KSk4KS/IOCkruCkvuCkruCljSDgpaU=', 'काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥'],
['SmUgcGV1eCBtYW5nZXIgZHUgdmVycmUsIMOnYSBuZSBtZSBmYWl0IHBhcyBtYWwu', 'Je peux manger du verre, ça ne me fait pas mal.'],
['UG90IHPEgyBtxINuw6JuYyBzdGljbMSDIMiZaSBlYSBudSBtxIMgcsSDbmXImXRlLg==', 'Pot să mănânc sticlă și ea nu mă rănește.'],
['5oiR6IO95ZCe5LiL546755KD6ICM5LiN5YK36Lqr6auU44CC', '我能吞下玻璃而不傷身體。'],
];
}
/**
* @dataProvider Base64DecodeProvider
*/
public function testBase64Decode(string $input, string $expected): void
{
$this->assertSame($expected, \imap_base64(\preg_replace('~[^a-zA-Z0-9+=/]+~s', '', $input)));
$this->assertSame($expected, \base64_decode($input, false));
}
/**
* @psalm-return array{0: array{0: string, 1: '', 2: Exceptions\InvalidParameterException::class, 3: 'setAttachmentsDir() expects a string as first parameter!'}, 1: array{0: string, 1: ' ', 2: Exceptions\InvalidParameterException::class, 3: 'setAttachmentsDir() expects a string as first parameter!'}, 2: array{0: string, 1: string, 2: Exceptions\InvalidParameterException::class, 3: string}}
*
* @return string[][]
*/
public function attachmentDirFailureProvider(): array
{
return [
[
__DIR__,
'',
InvalidParameterException::class,
'setAttachmentsDir() expects a string as first parameter!',
],
[
__DIR__,
' ',
InvalidParameterException::class,
'setAttachmentsDir() expects a string as first parameter!',
],
[
__DIR__,
__FILE__,
InvalidParameterException::class,
'Directory "'.__FILE__.'" not found',
],
];
}
/**
* Test that setting the attachments directory fails when expected.
*
* @dataProvider attachmentDirFailureProvider
*
* @psalm-param class-string<\Exception> $expectedException
*/
public function testAttachmentDirFailure(string $initialDir, string $attachmentsDir, string $expectedException, string $expectedExceptionMessage): void
{
$mailbox = new Mailbox('', '', '', $initialDir);
$this->assertSame(\trim($initialDir), $mailbox->getAttachmentsDir());
$this->expectException($expectedException);
$this->expectExceptionMessage($expectedExceptionMessage);
$mailbox->setAttachmentsDir($attachmentsDir);
}
protected function getMailbox(): Fixtures\Mailbox
{
return new Fixtures\Mailbox($this->imapPath, $this->login, $this->password, $this->attachmentsDir, $this->serverEncoding);
}
}