Skip to content

Commit 1ee6aad

Browse files
committed
Fix Bug #80800 imap_open() fails when the flags parameter includes CL_EXPUNGE
This also affected imap_reopen(). Add a supplementary test that the CL_EXPUNGE flag does have the intended effect. Closes GH-6732
1 parent 8813f2e commit 1ee6aad

File tree

6 files changed

+135
-4
lines changed

6 files changed

+135
-4
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ PHP NEWS
55
- Core:
66
. Fixed bug #75776 (Flushing streams with compression filter is broken). (cmb)
77

8+
- IMAP:
9+
. Fixed bug #80800 (imap_open() fails when the flags parameter includes
10+
CL_EXPUNGE). (girgias)
11+
812
- Intl:
913
. Fixed bug #80763 (msgfmt_format() does not accept DateTime references).
1014
(cmb)

ext/imap/php_imap.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,11 @@ PHP_FUNCTION(imap_open)
735735
RETURN_THROWS();
736736
}
737737

738-
if (flags && ((flags & ~(OP_READONLY | OP_ANONYMOUS | OP_HALFOPEN | CL_EXPUNGE | OP_DEBUG | OP_SHORTCACHE
738+
/* Check for PHP_EXPUNGE and not CL_EXPUNGE as the user land facing CL_EXPUNGE constant is defined
739+
* to something different to prevent clashes between CL_EXPUNGE and an OP_* constant allowing setting
740+
* the CL_EXPUNGE flag which will expunge when the mailbox is closed (be that manually, or via the
741+
* IMAPConnection object being destroyed naturally at the end of the PHP script */
742+
if (flags && ((flags & ~(OP_READONLY | OP_ANONYMOUS | OP_HALFOPEN | PHP_EXPUNGE | OP_DEBUG | OP_SHORTCACHE
739743
| OP_SILENT | OP_PROTOTYPE | OP_SECURE)) != 0)) {
740744
zend_argument_value_error(4, "must be a bitmask of the OP_* constants, and CL_EXPUNGE");
741745
RETURN_THROWS();
@@ -858,7 +862,11 @@ PHP_FUNCTION(imap_reopen)
858862
}
859863

860864
/* TODO Verify these are the only options available as they are pulled from the php.net documentation */
861-
if (options && ((options & ~(OP_READONLY | OP_ANONYMOUS | OP_HALFOPEN | OP_EXPUNGE | CL_EXPUNGE)) != 0)) {
865+
/* Check for PHP_EXPUNGE and not CL_EXPUNGE as the user land facing CL_EXPUNGE constant is defined
866+
* to something different to prevent clashes between CL_EXPUNGE and an OP_* constant allowing setting
867+
* the CL_EXPUNGE flag which will expunge when the mailbox is closed (be that manually, or via the
868+
* IMAPConnection object being destroyed naturally at the end of the PHP script */
869+
if (options && ((options & ~(OP_READONLY | OP_ANONYMOUS | OP_HALFOPEN | OP_EXPUNGE | PHP_EXPUNGE)) != 0)) {
862870
zend_argument_value_error(3, "must be a bitmask of OP_READONLY, OP_ANONYMOUS, OP_HALFOPEN, "
863871
"OP_EXPUNGE, and CL_EXPUNGE");
864872
RETURN_THROWS();

ext/imap/tests/bug80800.phpt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Bug #80800: imap_open() fails when the flags parameter includes CL_EXPUNGE
3+
--SKIPIF--
4+
<?php
5+
require_once(__DIR__.'/setup/skipif.inc');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
require_once __DIR__.'/setup/imap_include.inc';
11+
12+
$mail_box = imap_open(IMAP_DEFAULT_MAILBOX, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD, flags: CL_EXPUNGE);
13+
var_dump(imap_reopen($mail_box, IMAP_DEFAULT_MAILBOX, flags: CL_EXPUNGE));
14+
imap_close($mail_box);
15+
16+
echo 'Connected without any issues', "\n";
17+
18+
?>
19+
--EXPECT--
20+
bool(true)
21+
Connected without any issues
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Test imap_open() using the CL_EXPUNGE flag
3+
--SKIPIF--
4+
<?php
5+
require_once(__DIR__.'/setup/skipif.inc');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
// include file for required variables in imap_open()
11+
require_once(__DIR__.'/setup/imap_include.inc');
12+
13+
// set up temp mailbox with 3 messages
14+
$stream_id = setup_test_mailbox('imapopenwithclexpunge', 3, $mailbox, flags: CL_EXPUNGE);
15+
16+
// mark messages in inbox for deletion
17+
for ($i = 1; $i < 4; $i++) {
18+
imap_delete($stream_id, $i);
19+
}
20+
21+
echo "\n-- Call to imap_close() --\n";
22+
var_dump( imap_close($stream_id) );
23+
24+
// check that CL_EXPUNGE in previous imap_open() call worked
25+
$stream_id = imap_open($mailbox, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD);
26+
echo "There are now " . imap_num_msg($stream_id) . " msgs in mailbox '$mailbox'\n";
27+
28+
// Close connection
29+
var_dump( imap_close($stream_id) );
30+
?>
31+
--CLEAN--
32+
<?php
33+
$mailbox_suffix = 'imapopenwithclexpunge';
34+
require_once(__DIR__.'/setup/clean.inc');
35+
?>
36+
--EXPECTF--
37+
Create a temporary mailbox and add 3 msgs
38+
New mailbox created
39+
40+
-- Call to imap_close() --
41+
bool(true)
42+
There are now 0 msgs in mailbox '%sINBOX.phpttestimapopenwithclexpunge'
43+
bool(true)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
Test imap_reopen() using the CL_EXPUNGE flag
3+
--SKIPIF--
4+
<?php
5+
require_once(__DIR__.'/setup/skipif.inc');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
// include file for required variables in imap_open()
11+
require_once(__DIR__.'/setup/imap_include.inc');
12+
13+
$mailbox_suffix = 'imapreopenwithclexpunge';
14+
15+
// set up temp mailbox with 3 messages
16+
$stream_id = setup_test_mailbox($mailbox_suffix , 3, $mailbox);
17+
18+
var_dump(imap_reopen($stream_id, IMAP_DEFAULT_MAILBOX . '.' . IMAP_MAILBOX_PHPT_PREFIX . $mailbox_suffix, flags: CL_EXPUNGE));
19+
20+
// mark messages in inbox for deletion
21+
for ($i = 1; $i < 4; $i++) {
22+
imap_delete($stream_id, $i);
23+
}
24+
25+
echo "\n-- Call to imap_close() --\n";
26+
var_dump( imap_close($stream_id) );
27+
28+
// check that CL_EXPUNGE in previous imap_reopen() call worked
29+
$stream_id = imap_open($mailbox, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD);
30+
echo "There are now " . imap_num_msg($stream_id) . " msgs in mailbox '$mailbox'\n";
31+
32+
// Close connection
33+
var_dump( imap_close($stream_id) );
34+
?>
35+
--CLEAN--
36+
<?php
37+
$mailbox_suffix = 'imapreopenwithclexpunge';
38+
require_once(__DIR__.'/setup/clean.inc');
39+
?>
40+
--EXPECTF--
41+
Create a temporary mailbox and add 3 msgs
42+
New mailbox created
43+
bool(true)
44+
45+
-- Call to imap_close() --
46+
bool(true)
47+
There are now 0 msgs in mailbox '%sINBOX.phpttestimapreopenwithclexpunge'
48+
bool(true)

ext/imap/tests/setup/imap_include.inc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,19 @@ function displayOverviewFields($resp, array $fields = MANDATORY_OVERVIEW_FIELDS)
6363
* @param int message_count number of test msgs to be written to new mailbox
6464
* @param null $new_mailbox
6565
* @param bool $simpleMessages
66+
* @param int $flags OP_* (or CL_EXPUNGE) flags to pass to imap_open() sub-call
6667
* @return resource IMAP stream to new mailbox
6768
* @throws Exception
6869
*/
69-
function setup_test_mailbox(string $mailbox_suffix, int $message_count, &$new_mailbox = null, bool $simpleMessages = true){
70+
function setup_test_mailbox(
71+
string $mailbox_suffix,
72+
int $message_count,
73+
&$new_mailbox = null,
74+
bool $simpleMessages = true,
75+
int $flags = 0,
76+
){
7077
// open a stream to default mailbox
71-
$imap_stream = imap_open(IMAP_DEFAULT_MAILBOX, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD);
78+
$imap_stream = imap_open(IMAP_DEFAULT_MAILBOX, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD, flags: $flags);
7279

7380
if ($imap_stream === false) {
7481
throw new Exception("Cannot connect to IMAP server " . IMAP_SERVER . ": " . imap_last_error());

0 commit comments

Comments
 (0)