ZF-9630: add fetchBodyStructure to Zend_Mail_Protocol

Description

It would be nice to have an official access to FETCH BODYSTRUCTURE, including output parsing in Zend_Mail_Protocol. This would make it so much more efficient to retrieve message overviews.

Currently, this can be achieved using requestAndResponse, but the output handling has then to be done 'by hand' ...

Comments

The following function allows to parse the output and to return an object similar to imap_fetchstructure

    static function parseStructure($structureArray) {

        $types = array('text','multipart','message','application','audio','image','video');
        $encodings = array('7BIT','8BIT','BINARY','BASE64','QUOTED-PRINTABLE');
            
        if (! is_array($structureArray[0])) {
            $structureObj = new StdClass;
            $structureObj->type = ((($pos = array_search(strtolower($structureArray[0]), $types)) === false) ? count($types) : $pos);
            if ($structureArray[1] == 'NIL') {
                $structureObj->ifsubtype = 0;
            }
            else {
                $structureObj->ifsubtype = 1;
                $structureObj->subtype = $structureArray[1];
            }
            if (! is_array($structureArray[2])) {
                $structureObj->ifparameters = 0;
            }
            else {
                $structureObj->ifparameters = 1;
                $structureObj->parameters = array();
                $i=0;
                while ($i < count($structureArray[2])) {
                    $parameterObj = new StdClass;
                    $parameterObj->attribute = $structureArray[2][$i];
                    $i++;
                    $parameterObj->value = $structureArray[2][$i];
                    $i++;
                    $structureObj->parameters[] = $parameterObj;
                }
            }
            if ($structureArray[3] == 'NIL') {
                $structureObj->ifid = 0;
            }
            else {
                $structureObj->ifId = 1;
                $structureObj->id = $structureArray[3];
            }
            if ($structureArray[4] == 'NIL') {
                $structureObj->ifdescription = 0;
            }
            else {
                $structureObj->ifdescription = 1;
                $structureObj->description = $structureArray[4];
            }
            $structureObj->encoding = ((($pos = array_search(strtoupper($structureArray[5]), $encodings)) === false) ? count($encodings) : $pos);
            $structureObj->bytes = $structureArray[6];
            if (($structureObj->type == 0) && isset($structureArray[7]) && ($structureArray[7] != 'NIL')) {
                $structureObj->lines = $structureArray[7];
            }
            if (!isset($structureArray[8]) || ($structureArray[8] == 'NIL')) {
                $structureObj->ifdisposition = 0;
                $structureObj->ifdparameters = 0;
            }
            else {
                $structureObj->ifdisposition=1;
                $structureObj->disposition = $structureArray[8][0];
                if (!isset($structureArray[8][1]) || !is_array($structureArray[8][1])) {
                    $structureObj->ifdparameters = 0;
                }
                else {
                    $structureObj->ifdparameters = 1;
                    $structureObj->dparameters = array();
                    $i=0;
                    while ($i < count($structureArray[8][1])) {
                        $parameterObj = new StdClass;
                        $parameterObj->attribute = $structureArray[8][1][$i];
                        $i++;
                        $parameterObj->value = $structureArray[8][1][$i];
                        $i++;
                        $structureObj->dparameters[] = $parameterObj;
                    }
                }
            }
            return $structureObj;
        }
        else {
            $partsNb = 0;
            $structureObj = new StdClass;
            $structureObj->type = 1;
            $structureObj->parts = array();
            while (($partsNbparts[] = self::parseStructure($structureArray[$partsNb]);
                $partsNb++;
            }
            if ($structureArray[$partsNb] == 'NIL') {
                $structureObj->ifsubtype = 0;
            }
            else {
                $structureObj->ifsubtype = 1;
                $structureObj->subtype = $structureArray[$partsNb];
            }
            if (!isset($structureArray[$partsNb+1]) || ($structureArray[$partsNb+1] == 'NIL')) {
                $structureObj->ifparameters = 0;
            }
            else {
                $structureObj->ifparameters = 1;
                $structureObj->parameters = array();
                $i=0;
                while ($i < count($structureArray[$partsNb+1])) {
                    $parameterObj = new StdClass;
                    $parameterObj->attribute = $structureArray[$partsNb+1][$i];
                    $i++;
                    $parameterObj->value = $structureArray[$partsNb+1][$i];
                    $i++;
                    $structureObj->parameters[] = $parameterObj;
                }
            }
            if (!isset($structureArray[$partsNb+2]) || ($structureArray[$partsNb+2] == 'NIL')) {
                $structureObj->ifdisposition = 0;
                $structureObj->ifdparameters = 0;
            }
            else {
                $structureObj->ifdisposition = 1;
                $structureObj->disposition = $structureArray[$partsNb+2][0];
                if (!isset($structureArray[$partsNb+2][1]) || !is_array($structureArray[$partsNb+2][1])) {
                    $structureObj->ifdparameters = 0;
                }
                else {
                    $structureObj->ifdparameters = 1;
                    $structureObj->dparameters = array();
                    $i=0;
                    while ($i < count($structureArray[$partsNb+2][1])) {
                        $parameterObj = new StdClass;
                        $parameterObj->attribute = $structureArray[$partsNb+2][1][$i];
                        $i++;
                        $parameterObj->value = $structureArray[$partsNb+2][1][$i];
                        $i++;
                        $structureObj->dparameters[] = $parameterObj;
                    }
                }
            }
            return $structureObj;

        }
    }

Actually Zend_Mail_Part has a recursive iterator that can be, among other things, used to retrieve the structure of a message. That doesn't mean FETCH BODYSTRUCTURE doesn't make sense, but I think it might be a good idea to create Zend_Mail_Part_Imap and have it prefetch the structure when a Zend_Mail_Message_Imap is returned in getMessage(). The benefit is having the same interface as in all other storage classes and an object that's ready to use if you find a part in the structure that you want to do something with (like fetching it's content/body).

Dominik, thank you for your promising function.

I am relativly new to the zend framework and am trying to establish an alternative to the built-in php_imap.. functions in my scripts because of its restrictations on public webservers with apache and more than 1024 opened files (http://bugs.debian.org/cgi-bin/bugreport.cgi/…).

I really would like to use your function to replace imap_fetchstructure, which i rely on, but I do not understand how to use your function. Where is the $structureArray to be found?

Right now I am using Zend_Mail_Storage_Pop3, but I can go to Imap if needed. I am using ZF 1.11.10_minimal.

Thank you and best Regards

HeWo

Hi HeWo,

you could use some code like this:

$bodyStructure = $zend_mail_protocol_obj->requestAndResponse('FETCH', array($id, 'BODYSTRUCTURE')); $bodyStructureObj = parseStructure($bodyStructure[0][2][1]);

Let me know if you need more details, Dominik