Skip to content

Commit fb8be23

Browse files
authored
Merge pull request #560 from barbushin/develop
Next release after 4.1.0
2 parents 8e2f620 + 35737d8 commit fb8be23

19 files changed

+619
-180
lines changed

.php_cs.dist

+39-34
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,43 @@
11
<?php
22

3-
return PhpCsFixer\Config::create()
4-
->setRules([
5-
'@Symfony' => true,
6-
'@Symfony:risky' => true,
7-
'array_syntax' => [
8-
'syntax' => 'short'
9-
],
10-
'ordered_imports' => true,
11-
'phpdoc_to_comment' => false,
12-
'no_superfluous_phpdoc_tags' => true,
13-
'declare_strict_types' => true,
14-
'void_return' => true,
15-
'ordered_class_elements' => true,
16-
'global_namespace_import' => [
17-
'import_classes' => true,
18-
'import_constants' => true,
19-
'import_functions' => false,
20-
],
21-
'native_constant_invocation' => true,
22-
'native_function_invocation' => true,
23-
'php_unit_test_case_static_method_calls' => [
24-
'call_type' => 'this',
25-
],
26-
'php_unit_method_casing' => true,
27-
'php_unit_dedicate_assert' => [
28-
'target' => 'newest',
29-
],
30-
])
3+
declare(strict_types=1);
4+
5+
$finder = PhpCsFixer\Finder::create()
6+
->in(__DIR__.'/src')
7+
->in(__DIR__.'/tests')
8+
->in(__DIR__.'/examples')
9+
->append([__FILE__]);
10+
11+
$config = new PhpCsFixer\Config();
12+
$config->setRules([
13+
'@Symfony' => true,
14+
'@Symfony:risky' => true,
15+
'array_syntax' => [
16+
'syntax' => 'short',
17+
],
18+
'ordered_imports' => true,
19+
'phpdoc_to_comment' => false,
20+
'no_superfluous_phpdoc_tags' => true,
21+
'declare_strict_types' => true,
22+
'void_return' => true,
23+
'ordered_class_elements' => true,
24+
'global_namespace_import' => [
25+
'import_classes' => true,
26+
'import_constants' => true,
27+
'import_functions' => false,
28+
],
29+
'native_constant_invocation' => true,
30+
'native_function_invocation' => true,
31+
'php_unit_test_case_static_method_calls' => [
32+
'call_type' => 'this',
33+
],
34+
'php_unit_method_casing' => true,
35+
'php_unit_dedicate_assert' => [
36+
'target' => 'newest',
37+
],
38+
])
3139
->setRiskyAllowed(true)
32-
->setFinder(
33-
PhpCsFixer\Finder::create()
34-
->in(__DIR__.'/src')
35-
->in(__DIR__.'/tests')
36-
->in(__DIR__.'/examples')
37-
)
40+
->setFinder($finder)
3841
;
42+
43+
return $config;

README.md

+29-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Initially released in December 2012, the PHP IMAP Mailbox is a powerful and open
3030
| 7.2 | 3.x, 4.x |
3131
| 7.3 | 3.x, 4.x |
3232
| 7.4 | >3.0.33, 4.x |
33+
| 8.0 | >3.0.33, 4.x |
3334

3435
* PHP `fileinfo` extension must be present; so make sure this line is active in your php.ini: `extension=php_fileinfo.dll`
3536
* PHP `iconv` extension must be present; so make sure this line is active in your php.ini: `extension=php_iconv.dll`
@@ -121,12 +122,12 @@ echo "\n\nAttachments:\n";
121122
print_r($mail->getAttachments());
122123
```
123124

124-
Method imap() allows to call any imap function in a context of the the instance:
125+
Method `imap()` allows to call any [PHP IMAP function](https://www.php.net/manual/ref.imap.php) in a context of the instance. Example:
125126

126127
```php
127-
// Call imap_check();
128-
// http://php.net/manual/en/function.imap-check.php
129-
$info = $mailbox->imap('check'); //
128+
// Call imap_check() - see http://php.net/manual/function.imap-check.php
129+
$info = $mailbox->imap('check');
130+
130131

131132
// Show current time for the mailbox
132133
$currentServerTime = isset($info->Date) && $info->Date ? date('Y-m-d H:i:s', strtotime($info->Date)) : 'Unknown';
@@ -156,6 +157,30 @@ foreach($folders as $folder) {
156157
print_r($mails_ids);
157158
```
158159

160+
### Upgrading from 3.x
161+
162+
Prior to 3.1, `Mailbox` used a "magic" method (`Mailbox::imap()`), with the
163+
class `Imap` now performing it's purpose to call many `imap_*` functions with
164+
automated string encoding/decoding of arguments and return values:
165+
166+
Before:
167+
168+
```php
169+
public function checkMailbox()
170+
{
171+
return $this->imap('check');
172+
}
173+
```
174+
175+
After:
176+
177+
```php
178+
public function checkMailbox(): object
179+
{
180+
return Imap::check($this->getImapStream());
181+
}
182+
```
183+
159184
### Recommended
160185

161186
* Google Chrome extension [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef)

composer.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"sort-packages": true
2424
},
2525
"require": {
26-
"php": "^7.2",
26+
"php": "^7.2 || ^8.0 <8.1",
2727
"ext-fileinfo": "*",
2828
"ext-iconv": "*",
2929
"ext-imap": "*",
@@ -33,13 +33,14 @@
3333
"friendsofphp/php-cs-fixer": "^2.16",
3434
"jakub-onderka/php-parallel-lint": "^1.0",
3535
"maglnet/composer-require-checker": "^2.0",
36+
"nikic/php-parser": "^4.3,<4.7",
3637
"paragonie/hidden-string": "^1.0",
3738
"phpunit/phpunit": "^8.5",
3839
"povils/phpmnd": "^2.2",
3940
"psalm/plugin-phpunit": "^0.10.0",
4041
"roave/security-advisories": "dev-master",
4142
"sebastian/phpcpd": "^4.1",
42-
"vimeo/psalm": "^3.11.5"
43+
"vimeo/psalm": "^3.12"
4344
},
4445
"scripts": {
4546
"static-analysis": [

examples/get_and_parse_all_emails_with_matching_subject.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
try {
2424
$mail_ids = $mailbox->searchMailbox('SUBJECT "part of the subject"');
2525
} catch (ConnectionException $ex) {
26-
die('IMAP connection failed: '.$ex->getMessage());
26+
exit('IMAP connection failed: '.$ex->getMessage());
2727
} catch (Exception $ex) {
28-
die('An error occured: '.$ex->getMessage());
28+
exit('An error occured: '.$ex->getMessage());
2929
}
3030

3131
foreach ($mail_ids as $mail_id) {

examples/get_and_parse_all_emails_without_saving_attachments.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
try {
3434
$mail_ids = $mailbox->searchMailbox('UNSEEN');
3535
} catch (ConnectionException $ex) {
36-
die('IMAP connection failed: '.$ex->getMessage());
36+
exit('IMAP connection failed: '.$ex->getMessage());
3737
} catch (Exception $ex) {
38-
die('An error occured: '.$ex->getMessage());
38+
exit('An error occured: '.$ex->getMessage());
3939
}
4040

4141
foreach ($mail_ids as $mail_id) {

examples/get_and_parse_unseen_emails.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
try {
2424
$mail_ids = $mailbox->searchMailbox('UNSEEN');
2525
} catch (ConnectionException $ex) {
26-
die('IMAP connection failed: '.$ex->getMessage());
26+
exit('IMAP connection failed: '.$ex->getMessage());
2727
} catch (Exception $ex) {
28-
die('An error occured: '.$ex->getMessage());
28+
exit('An error occured: '.$ex->getMessage());
2929
}
3030

3131
foreach ($mail_ids as $mail_id) {

examples/get_and_parse_unseen_emails_save_attachments_one_by_one.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
try {
2222
$mail_ids = $mailbox->searchMailbox('UNSEEN');
2323
} catch (ConnectionException $ex) {
24-
die('IMAP connection failed: '.$ex->getMessage());
24+
exit('IMAP connection failed: '.$ex->getMessage());
2525
} catch (Exception $ex) {
26-
die('An error occured: '.$ex->getMessage());
26+
exit('An error occured: '.$ex->getMessage());
2727
}
2828

2929
foreach ($mail_ids as $mail_id) {

psalm.baseline.xml

+1-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="3.11.5@3c60609c218d4d4b3b257728b8089094e5c6c6c2">
2+
<files psalm-version="3.12.2@7c7ebd068f8acaba211d4a2c707c4ba90874fa26">
33
<file src="examples/get_and_parse_all_emails_without_saving_attachments.php">
44
<UnusedVariable occurrences="1">
55
<code>$mailbox</code>
@@ -12,25 +12,14 @@
1212
<code>\is_resource($maybe)</code>
1313
</DocblockTypeContradiction>
1414
</file>
15-
<file src="src/PhpImap/IncomingMail.php">
16-
<PossiblyUnusedMethod occurrences="1">
17-
<code>replaceInternalLinks</code>
18-
</PossiblyUnusedMethod>
19-
<PropertyTypeCoercion occurrences="1">
20-
<code>$this-&gt;dataInfo</code>
21-
</PropertyTypeCoercion>
22-
</file>
2315
<file src="src/PhpImap/Mailbox.php">
2416
<DocblockTypeContradiction occurrences="2">
2517
<code>\in_array($imapSearchOption, $supported_options, true)</code>
2618
<code>\in_array($key, $supported_params, true)</code>
2719
</DocblockTypeContradiction>
2820
<InvalidArgument occurrences="3">
29-
<code>$element-&gt;charset</code>
3021
<code>$element-&gt;charset</code>
3122
<code>$element-&gt;text</code>
32-
<code>$element-&gt;charset</code>
33-
<code>$element-&gt;charset</code>
3423
<code>$element-&gt;text</code>
3524
</InvalidArgument>
3625
<PossiblyUnusedMethod occurrences="24">

src/PhpImap/DataPartInfo.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,10 @@ protected function decodeAfterFetch(): string
107107

108108
protected function convertEncodingAfterFetch(): string
109109
{
110-
if (isset($this->charset) and !empty(\trim($this->charset))) {
110+
if (isset($this->charset) && !empty(\trim($this->charset))) {
111111
$this->data = $this->mail->decodeMimeStr(
112112
(string) $this->data // Data to convert
113+
\trim($this->charset)
113114
);
114115
}
115116

src/PhpImap/Imap.php

+12-6
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,16 @@ public static function clearflag_full(
181181
* @param false|resource $imap_stream
182182
*
183183
* @psalm-param value-of<self::CLOSE_FLAGS> $flag
184-
* @psalm-param 0|32768 $flag
185184
*
186185
* @return true
187186
*/
188187
public static function close($imap_stream, int $flag = 0): bool
189188
{
190189
\imap_errors(); // flush errors
191190

191+
/** @var int */
192+
$flag = $flag;
193+
192194
$result = \imap_close(self::EnsureConnection($imap_stream, __METHOD__, 1), $flag);
193195

194196
if (false === $result) {
@@ -699,12 +701,12 @@ public static function open(
699701

700702
\imap_errors(); // flush errors
701703

702-
$result = \imap_open($mailbox, $username, $password, $options, $n_retries, $params);
704+
$result = @\imap_open($mailbox, $username, $password, $options, $n_retries, $params);
703705

704706
if (!$result) {
705707
$lastError = \imap_last_error();
706708

707-
if ('' !== \trim($lastError)) {
709+
if ((\is_string($lastError)) && ('' !== \trim($lastError))) {
708710
throw new UnexpectedValueException('IMAP error:'.$lastError);
709711
}
710712

@@ -890,7 +892,6 @@ public static function setflag_full(
890892
* @param false|resource $imap_stream
891893
*
892894
* @psalm-param value-of<self::SORT_CRITERIA> $criteria
893-
* @psalm-param 1|5|0|2|6|3|4 $criteria
894895
*
895896
* @return int[]
896897
*
@@ -909,6 +910,9 @@ public static function sort(
909910
$imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1);
910911
$reverse = (int) $reverse;
911912

913+
/** @var int */
914+
$criteria = $criteria;
915+
912916
if (null !== $search_criteria && null !== $charset) {
913917
$result = \imap_sort(
914918
$imap_stream,
@@ -935,7 +939,7 @@ public static function sort(
935939
);
936940
}
937941

938-
if (!$result) {
942+
if (false === $result) {
939943
throw new UnexpectedValueException('Could not sort messages!', 0, self::HandleErrors(\imap_errors(), 'imap_sort'));
940944
}
941945

@@ -990,7 +994,6 @@ public static function subscribe(
990994

991995
/**
992996
* @psalm-param value-of<self::TIMEOUT_TYPES> $timeout_type
993-
* @psalm-param 4|1|2|3 $timeout_type
994997
*
995998
* @return true|int
996999
*/
@@ -1000,6 +1003,9 @@ public static function timeout(
10001003
) {
10011004
\imap_errors(); // flush errors
10021005

1006+
/** @var int */
1007+
$timeout_type = $timeout_type;
1008+
10031009
$result = \imap_timeout(
10041010
$timeout_type,
10051011
$timeout

src/PhpImap/IncomingMail.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,11 @@ public function embedImageAttachments(): void
219219
$cid = \str_replace('cid:', '', $match);
220220

221221
foreach ($attachments as $attachment) {
222-
if ($attachment->contentId == $cid && 'inline' == $attachment->disposition) {
222+
/**
223+
* Inline images can contain a "Content-Disposition: inline", but only a "Content-ID" is also enough.
224+
* See https://github.com/barbushin/php-imap/issues/569
225+
*/
226+
if ($attachment->contentId == $cid || 'inline' == \mb_strtolower((string) $attachment->disposition)) {
223227
$contents = $attachment->getContents();
224228
$contentType = (string) $attachment->getFileInfo(FILEINFO_MIME);
225229

src/PhpImap/IncomingMailAttachment.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
* @author Barbushin Sergey http://linkedin.com/in/barbushin
1616
*
17-
* @property string $filePath lazy attachment data file
17+
* @property string|false|null $filePath lazy attachment data file
1818
*
1919
* @psalm-type fileinfoconst = 0|2|16|1024|1040|8|32|128|256|16777216
2020
*/
@@ -129,9 +129,9 @@ public function addDataPartInfo(DataPartInfo $dataInfo): void
129129
*
130130
* @psalm-param fileinfoconst $fileinfo_const
131131
*/
132-
public function getFileInfo($fileinfo_const = FILEINFO_NONE): string
132+
public function getFileInfo(int $fileinfo_const = FILEINFO_NONE): string
133133
{
134-
if ((FILEINFO_MIME == $fileinfo_const) and (false != $this->mimeType)) {
134+
if ((FILEINFO_MIME == $fileinfo_const) && (false != $this->mimeType)) {
135135
return $this->mimeType;
136136
}
137137

0 commit comments

Comments
 (0)