Zend_Mail_Storage_Imap

Logo Zend Framework

Dans le cadre de mon projet Sooka, j'ai besoin d'effectuer une recherche sur un serveur IMAP.

Ma première idée a été d'utiliser Zend_Mail_Storage_Imap, mais à la lecture de la documentation du ZF, la commande SEARCH n'est pas supportée. Je me suis donc rabattu sur les fonctions imap_* de PHP.

Mais le moins qu'on puisse dire, c'est que ces fonctions ne sont pas très pratiques. Surtout si on veut retrouver la partie texte d'un message. Il faut récupérer la structure d'un message avec imap_fetchstructure, puis itérer récursivement sur l'objet renvoyé pour retrouver la première partie avec le subtype PLAIN. Il faut ensuite déterminer le numéro de la partie (1.1 par exemple) pour pouvoir enfin le récupérer avec imap_fetchbody.

Après quelques heures passées à bricoler, je n'était pas trop satisfait de mon implémentation. C'est alors que je me suis dis que ce serai peut-être plus simple de revenir à Zend_Mail_Storage_Imap et d'y ajouter la commande SEARCH qui fait défaut.

En examinant le code, je me suis rendu compte que cette commande était déjà implémentée dans Zend_Mail_Protocol_Imap. Elle n'est pas documentée pour l'instant car l'API n'est pas encore figée et l'implémentation actuelle n'est pas suffisamment sure.

J'ai donc dérivé Zend_Mail_Storage_Imap pour lui ajouter une méthode search :

<?php
class Wiip_Mail_Storage_Imap extends Zend_Mail_Storage_Imap
{
    
/**
     * Do a search request
     *
     * @param string $criteria
     * @return array message ids
     */

    
public function search($criteria)
    {
        return 
$this->_protocol->search(array($criteria));
    }
}
?>

Exemple d'utilisation :

<?php
$imap 
= new Wiip_Mail_Storage_Imap(
    array(
        
'host' => 'imap.somewhere.com',
        
'user' => 'john.smith@somewhere.com',
        
'password' => 'secret'
    
)
);
// Recherche les messages dont la date est postérieure au 1er février 2009
$messages $imap->search('SINCE 1-Feb-2009');
?>

La méthode renvoie un tableau d'ID.

Sur ma lancée, j'ai également dérivé Zend_Mail_Message pour lui ajouter une méthode getText qui permet de retrouver la partie texte d'un E-mail. Je me suis inspiré de l'exemple fourni dans la documentation du Zend Framework.

<?php
class Wiip_Mail_Message extends Zend_Mail_Message
{
    
/**
     * Return the text part of the message (in UTF-8)
     *
     * @return string
     */

    
public function getText()
    {
        if (
$this->isMultipart()) {
            foreach (new 
RecursiveIteratorIterator($this) as $part) {
                try {
                    if (
strtok($part->contentType';') == 'text/plain') {
                        
$text $part->getContent();

                        if (
$part->contentTransferEncoding) {
                            
$contentTransfertEncoding $part->contentTransferEncoding;
                        }
                    }
                } catch (
Zend_Mail_Exception $e) {
                    
// ignore
                
}
            }
        } else {
            
$contentTransfertEncoding $this->contentTransferEncoding;
            if (
preg_match('/charset="(.+)"$/'$this->contentType$matches)) {
                
$charset $matches[1];
            }
            
$text $this->getContent();
        }

        
// Decode the content
        
switch ($contentTransfertEncoding) {
            case 
'base64':
                
$text base64_decode($text);
                break;
            
            case 
'7bit':
            case 
'quoted-printable':
                
$text quoted_printable_decode($text);
                break;

            default:
                throw new 
Exception("Unknown encoding: '{$contentTransfertEncoding}'");
        }

        
// Convert to UTF-8 if necessary
        
if (!isset($charset) or ($charset != 'UTF-8')) {
            
$text utf8_encode($text);
        }

        return 
$text;
    }
}
?>

La méthode se charge de décoder le texte et de le convertir en UTF-8.

Pour qu'un objet Wiip_Mail_Message soit renvoyé lorsqu'on appelle la méthode getMessage de Zend_Mail_Storage_Imap, il faut modifier la propriété $_messageClass.

<?php
class Wiip_Mail_Storage_Imap extends Zend_Mail_Storage_Imap
{
    protected 
$_messageClass 'Wiip_Mail_Message';

    [..]
}
?>

Exemple d'utilisation :

<?php
$message 
$imap->getMessage($id);
echo 
$message->getText();
?>

Avec ces petites modifications, je dispose à présent de deux nouveaux composants bien pratiques pour interroger un serveur IMAP et pour afficher un message E-mail.