PhpRiot
Become Zend Certified

Prepare for the ZCE exam using our quizzes (web or iPad/iPhone). More info...


When you're ready get 7.5% off your exam voucher using voucher CJQNOV23 at the Zend Store

Advanced Use

Using NOOP

If you're using a remote storage and have some long tasks you might need to keep the connection alive via noop:

<?php
foreach ($mail as $message) {

    
// do some calculations ...

    
$mail->noop(); // keep alive

    // do something else ...

    
$mail->noop(); // keep alive
}

Caching instances

Zend_Mail_Storage_Mbox, Zend_Mail_Storage_Folder_Mbox, Zend_Mail_Storage_Maildir and Zend_Mail_Storage_Folder_Maildir implement the magic methods __sleep() and __wakeup(), which means they are serializable. This avoids parsing the files or directory tree more than once. The disadvantage is that your Mbox or Maildir storage should not change. Some easy checks may be done, like reparsing the current Mbox file if the modification time changes, or reparsing the folder structure if a folder has vanished (which still results in an error, but you can search for another folder afterwards). It's better if you have something like a signal file for changes and check it before using the cached instance.

<?php
// there's no specific cache handler/class used here,
// change the code to match your cache handler
$signal_file '/home/test/.mail.last_change';
$mbox_basedir '/home/test/mail/';
$cache_id 'example mail cache ' $mbox_basedir $signal_file;

$cache = new Your_Cache_Class();
if (!
$cache->isCached($cache_id) ||
    
filemtime($signal_file) > $cache->getMTime($cache_id)) {
    
$mail = new Zend_Mail_Storage_Folder_Pop3(array('dirname' =>
                                                        
$mbox_basedir));
} else {
    
$mail $cache->get($cache_id);
}

// do stuff ...

$cache->set($cache_id$mail);

Extending Protocol Classes

Remote storages use two classes: Zend_Mail_Storage_<Name> and Zend_Mail_Protocol_<Name>. The protocol class translates the protocol commands and responses from and to PHP, like methods for the commands or variables with different structures for data. The other/main class implements the common interface.

If you need additional protocol features, you can extend the protocol class and use it in the constructor of the main class. As an example, assume we need to knock different ports before we can connect to POP3.

<?php
class Example_Mail_Exception extends Zend_Mail_Exception
{
}

class 
Example_Mail_Protocol_Exception extends Zend_Mail_Protocol_Exception
{
}

class 
Example_Mail_Protocol_Pop3_Knock extends Zend_Mail_Protocol_Pop3
{
    private 
$host$port;

    public function 
__construct($host$port null)
    {
        
// no auto connect in this class
        
$this->host $host;
        
$this->port $port;
    }

    public function 
knock($port)
    {
        
$sock = @fsockopen($this->host$port);
        if (
$sock) {
            
fclose($sock);
        }
    }

    public function 
connect($host null$port null$ssl false)
    {
        if (
$host === null) {
            
$host $this->host;
        }
        if (
$port === null) {
            
$port $this->port;
        }
        
parent::connect($host$port);
    }
}

class 
Example_Mail_Pop3_Knock extends Zend_Mail_Storage_Pop3
{
    public function 
__construct(array $params)
    {
        
// ... check $params here! ...
        
$protocol = new Example_Mail_Protocol_Pop3_Knock($params['host']);

        
// do our "special" thing
        
foreach ((array)$params['knock_ports'] as $port) {
            
$protocol->knock($port);
        }

        
// get to correct state
        
$protocol->connect($params['host'], $params['port']);
        
$protocol->login($params['user'], $params['password']);

        
// initialize parent
        
parent::__construct($protocol);
    }
}

$mail = new Example_Mail_Pop3_Knock(array('host'        => 'localhost',
                                          
'user'        => 'test',
                                          
'password'    => 'test',
                                          
'knock_ports' =>
                                              array(
110111051111)));

As you see, we always assume we're connected, logged in and, if supported, a folder is selected in the constructor of the main class. Thus if you assign your own protocol class, you always need to make sure that's done or the next method will fail if the server doesn't allow it in the current state.

Using Quota (since 1.5)

Zend_Mail_Storage_Writable_Maildir has support for Maildir++ quotas. It's disabled by default, but it's possible to use it manually, if the automatic checks are not desired (this means appendMessage(), removeMessage() and copyMessage() do no checks and do not add entries to the maildirsize file). If enabled, an exception is thrown if you try to write to the maildir and it's already over quota.

There are three methods used for quotas: getQuota(), setQuota() and checkQuota():

<?php
$mail 
= new Zend_Mail_Storage_Writable_Maildir(array('dirname' =>
                                                   
'/home/test/mail/'));
$mail->setQuota(true); // true to enable, false to disable
echo 'Quota check is now '$mail->getQuota() ? 'enabled' 'disabled'"\n";
// check quota can be used even if quota checks are disabled
echo 'You are '$mail->checkQuota() ? 'over quota' 'not over quota'"\n";

checkQuota() can also return a more detailed response:

<?php
$quota 
$mail->checkQuota(true);
echo 
'You are '$quota['over_quota'] ? 'over quota' 'not over quota'"\n";
echo 
'You have ',
     
$quota['count'],
     
' of ',
     
$quota['quota']['count'],
     
' messages and use ';
echo 
$quota['size'], ' of '$quota['quota']['size'], ' octets';

If you want to specify your own quota instead of using the one specified in the maildirsize file you can do with setQuota():

<?php
// message count and octet size supported, order does matter
$quota $mail->setQuota(array('size' => 10000'count' => 100));

To add your own quota checks use single letters as keys, and they will be preserved (but obviously not checked). It's also possible to extend Zend_Mail_Storage_Writable_Maildir to define your own quota only if the maildirsize file is missing (which can happen in Maildir++):

<?php
class Example_Mail_Storage_Maildir extends Zend_Mail_Storage_Writable_Maildir {
    
// getQuota is called with $fromStorage = true by quota checks
    
public function getQuota($fromStorage false) {
        try {
            return 
parent::getQuota($fromStorage);
        } catch (
Zend_Mail_Storage_Exception $e) {
            if (!
$fromStorage) {
                
// unknown error:
                
throw $e;
            }
            
// maildirsize file must be missing

            
list($count$size) = get_quota_from_somewhere_else();
            return array(
'count' => $count'size' => $size);
        }
    }
}

Zend Framework