Search code examples
phpimap

PHP imap_reopen no error returned


I have a script that connects to a mailbox. I'd like to check if I can connect to a folder that does not exist, but imap_reopen does not return errors.

<?php
$imap_url = "{mybox.mail.box:143}";

$mbox = imap_open($imap_url, "Mylogin", "Mypassword");
if ($mbox == false) {
    echo "Opening mailbox failed\n";
}

$submbox = imap_listmailbox($mbox, $imap_url, "*");
if ($submbox == false) {
    echo "Listing sub-mailboxes failed\n";
}
else {
    foreach ($submbox as $name) {
        echo $name . PHP_EOL;
    }
}   

$test = imap_reopen($mbox, $imap_url . "INBOX.MBOX3") or die(implode(", ", imap_errors()));
if ($test == false) {
    echo "Opening submbox failed\n";
}

?>

Script output :

{mybox.mail.box:143}.INBOX
{mybox.mail.box:143}.INBOX.MBOX1
{mybox.mail.box:143}.INBOX.MBOX2
PHP Notice:  Unknown: Mailbox does not exist (errflg=2) in Unknown on line 0

Do you have an idea ?

Regards,

Stiti


Solution

  • Your statement ending with or die() is actually terminating execution before the if test against the return value in $test.

    $test = imap_reopen($mbox, $imap_url . "INBOX.MBOX3") or die(implode(", ", imap_errors()));
    
    // This code is never reached because of die()!
    if ($test == false) {
        echo "Opening submbox failed\n";
    }
    

    So just remove the or die() expression and your if ($test == false) will be evaluated. I'll also use === here since it should return a true boolean:

    // Call imap_reopen() without (or die())
    $test = imap_reopen($mbox, $imap_url . "INBOX.MBOX3");
    if ($test === false) {
        echo "Opening submbox failed\n";
    }
    

    You may alternatively use

    if (!$test) {
        echo "Opening submbox failed\n";
    }
    

    Note about the PHP E_NOTICE emitted - if imap_reopen() emits that notice even when returning false, this is one instance in which you may want to use the @ operator for error suppression since you are correctly testing for errors in your if block.

    // @ is not usually recommended but if imap_reopen()
    // prints an E_NOTICE while still returning false you can
    // suppress it with @. This is among the only times it's
    // a good idea to use @ for error suppresssion
    $test = @imap_reopen($mbox, $imap_url . "INBOX.MBOX3");
    if (!$test) {...}
    

    Addendum after testing:

    Documentation on imap_reopen() is slim and ambiguous stating its return as:

    Returns TRUE if the stream is reopened, FALSE otherwise.

    Some testing seems to imply that opening a non-existent mailbox is not considered an error state for which it returns false. When opening a non-existent mailbox on an otherwise valid stream, imap_reopen() will still return true but populate an error in imap_errors().

    So you may check count(imap_errors()) > 0 for errors after opening the faulty mailbox. Couple that with a true return check, in case imap_reopen() does return a true error state.

    For example my testing produces results similar to:

    $test = imap_reopen($mbox, $imap_url . "NOTEXIST");
    var_dump($test);
    // bool(true);
    var_dump(imap_errors());                                                  array(1) {
      [0] =>
      string(28) "Mailbox doesn't exist: NOTEXIST"
    }
    

    You may work around this using logic to:

    $test = @imap_reopen($mbox, $imap_url . "INBOX.MBOX3");
    if (!$test) {
      // An error with the stream
    }
    // Returns true, but imap_errors() is populated
    else if ($test && count(imap_errors()) > 0) {
      echo "Opening submbox failed\n";
      // Do something with imap_errors() if needed
      echo implode(',', imap_errors());
    }
    else {
      // Everything is fine -  the mailbox was opened
    }
    

    For what it's worth, imap_open() exhibits the same behavior. Successfully connecting and establishing the stream (your variable $mbox) is possible with a non-existent mailbox. The stream is created and valid, but imap_errors() will contain a message Mailbox doesn't exist: <mailbox>.