diff options
Diffstat (limited to 'applications/core/lib/Zend/Mime')
| -rw-r--r-- | applications/core/lib/Zend/Mime/Decode.php | 243 | ||||
| -rw-r--r-- | applications/core/lib/Zend/Mime/Exception.php | 36 | ||||
| -rw-r--r-- | applications/core/lib/Zend/Mime/Message.php | 285 | ||||
| -rw-r--r-- | applications/core/lib/Zend/Mime/Part.php | 216 | 
4 files changed, 780 insertions, 0 deletions
| diff --git a/applications/core/lib/Zend/Mime/Decode.php b/applications/core/lib/Zend/Mime/Decode.php new file mode 100644 index 0000000..cc4de8b --- /dev/null +++ b/applications/core/lib/Zend/Mime/Decode.php @@ -0,0 +1,243 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to [email protected] so we can send you a copy immediately. + * + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ + +/** + * @see Zend_Mime + */ +require_once 'Zend/Mime.php'; + +/** + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ +class Zend_Mime_Decode +{ +    /** +     * Explode MIME multipart string into seperate parts +     * +     * Parts consist of the header and the body of each MIME part. +     * +     * @param  string $body     raw body of message +     * @param  string $boundary boundary as found in content-type +     * @return array parts with content of each part, empty if no parts found +     * @throws Zend_Exception +     */ +    public static function splitMime($body, $boundary) +    { +        // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r? +        $body = str_replace("\r", '', $body); + +        $start = 0; +        $res = array(); +        // find every mime part limiter and cut out the +        // string before it. +        // the part before the first boundary string is discarded: +        $p = strpos($body, '--' . $boundary . "\n", $start); +        if ($p === false) { +            // no parts found! +            return array(); +        } + +        // position after first boundary line +        $start = $p + 3 + strlen($boundary); + +        while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) { +            $res[] = substr($body, $start, $p-$start); +            $start = $p + 3 + strlen($boundary); +        } + +        // no more parts, find end boundary +        $p = strpos($body, '--' . $boundary . '--', $start); +        if ($p===false) { +            throw new Zend_Exception('Not a valid Mime Message: End Missing'); +        } + +        // the remaining part also needs to be parsed: +        $res[] = substr($body, $start, $p-$start); +        return $res; +    } + +    /** +     * decodes a mime encoded String and returns a +     * struct of parts with header and body +     * +     * @param  string $message  raw message content +     * @param  string $boundary boundary as found in content-type +     * @param  string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} +     * @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found +     * @throws Zend_Exception +     */ +    public static function splitMessageStruct($message, $boundary, $EOL = Zend_Mime::LINEEND) +    { +        $parts = self::splitMime($message, $boundary); +        if (count($parts) <= 0) { +            return null; +        } +        $result = array(); +        foreach ($parts as $part) { +            self::splitMessage($part, $headers, $body, $EOL); +            $result[] = array('header' => $headers, +                              'body'   => $body    ); +        } +        return $result; +    } + +    /** +     * split a message in header and body part, if no header or an +     * invalid header is found $headers is empty +     * +     * The charset of the returned headers depend on your iconv settings. +     * +     * @param  string $message raw message with header and optional content +     * @param  array  $headers output param, array with headers as array(name => value) +     * @param  string $body    output param, content of message +     * @param  string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} +     * @return null +     */ +    public static function splitMessage($message, &$headers, &$body, $EOL = Zend_Mime::LINEEND) +    { +        // check for valid header at first line +        $firstline = strtok($message, "\n"); +        if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) { +            $headers = array(); +            // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r? +            $body = str_replace(array("\r", "\n"), array('', $EOL), $message); +            return; +        } + +        // find an empty line between headers and body +        // default is set new line +        if (strpos($message, $EOL . $EOL)) { +            list($headers, $body) = explode($EOL . $EOL, $message, 2); +        // next is the standard new line +        } else if ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) { +            list($headers, $body) = explode("\r\n\r\n", $message, 2); +        // next is the other "standard" new line +        } else if ($EOL != "\n" && strpos($message, "\n\n")) { +            list($headers, $body) = explode("\n\n", $message, 2); +        // at last resort find anything that looks like a new line +        } else { +            @list($headers, $body) = @preg_split("%([\r\n]+)\\1%U", $message, 2); +        } + +        $headers = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR); + +        if ($headers === false ) { +            // an error occurs during the decoding +            return; +        } + +        // normalize header names +        foreach ($headers as $name => $header) { +            $lower = strtolower($name); +            if ($lower == $name) { +                continue; +            } +            unset($headers[$name]); +            if (!isset($headers[$lower])) { +                $headers[$lower] = $header; +                continue; +            } +            if (is_array($headers[$lower])) { +                $headers[$lower][] = $header; +                continue; +            } +            $headers[$lower] = array($headers[$lower], $header); +        } +    } + +    /** +     * split a content type in its different parts +     * +     * @param  string $type       content-type +     * @param  string $wantedPart the wanted part, else an array with all parts is returned +     * @return string|array wanted part or all parts as array('type' => content-type, partname => value) +     */ +    public static function splitContentType($type, $wantedPart = null) +    { +        return self::splitHeaderField($type, $wantedPart, 'type'); +    } + +    /** +     * split a header field like content type in its different parts +     * +     * @param  string $type       header field +     * @param  string $wantedPart the wanted part, else an array with all parts is returned +     * @param  string $firstName  key name for the first part +     * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value) +     * @throws Zend_Exception +     */ +    public static function splitHeaderField($field, $wantedPart = null, $firstName = 0) +    { +        $wantedPart = strtolower($wantedPart); +        $firstName = strtolower($firstName); + +        // special case - a bit optimized +        if ($firstName === $wantedPart) { +            $field = strtok($field, ';'); +            return $field[0] == '"' ? substr($field, 1, -1) : $field; +        } + +        $field = $firstName . '=' . $field; +        if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) { +            throw new Zend_Exception('not a valid header field'); +        } + +        if ($wantedPart) { +            foreach ($matches[1] as $key => $name) { +                if (strcasecmp($name, $wantedPart)) { +                    continue; +                } +                if ($matches[2][$key][0] != '"') { +                    return $matches[2][$key]; +                } +                return substr($matches[2][$key], 1, -1); +            } +            return null; +        } + +        $split = array(); +        foreach ($matches[1] as $key => $name) { +            $name = strtolower($name); +            if ($matches[2][$key][0] == '"') { +                $split[$name] = substr($matches[2][$key], 1, -1); +            } else { +                $split[$name] = $matches[2][$key]; +            } +        } + +        return $split; +    } + +    /** +     * decode a quoted printable encoded string +     * +     * The charset of the returned string depends on your iconv settings. +     * +     * @param  string encoded string +     * @return string decoded string +     */ +    public static function decodeQuotedPrintable($string) +    { +        return iconv_mime_decode($string, ICONV_MIME_DECODE_CONTINUE_ON_ERROR); +    } +} diff --git a/applications/core/lib/Zend/Mime/Exception.php b/applications/core/lib/Zend/Mime/Exception.php new file mode 100644 index 0000000..2c22e9b --- /dev/null +++ b/applications/core/lib/Zend/Mime/Exception.php @@ -0,0 +1,36 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to [email protected] so we can send you a copy immediately. + * + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ + + +/** + * Zend_Exception + */ +require_once 'Zend/Exception.php'; + + +/** + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ +class Zend_Mime_Exception extends Zend_Exception +{} + diff --git a/applications/core/lib/Zend/Mime/Message.php b/applications/core/lib/Zend/Mime/Message.php new file mode 100644 index 0000000..613be1d --- /dev/null +++ b/applications/core/lib/Zend/Mime/Message.php @@ -0,0 +1,285 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to [email protected] so we can send you a copy immediately. + * + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ + + +/** + * Zend_Mime + */ +require_once 'Zend/Mime.php'; + +/** + * Zend_Mime_Part + */ +require_once 'Zend/Mime/Part.php'; + + +/** + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ +class Zend_Mime_Message +{ + +    protected $_parts = array(); +    protected $_mime = null; + +    /** +     * Returns the list of all Zend_Mime_Parts in the message +     * +     * @return array of Zend_Mime_Part +     */ +    public function getParts() +    { +        return $this->_parts; +    } + +    /** +     * Sets the given array of Zend_Mime_Parts as the array for the message +     * +     * @param array $parts +     */ +    public function setParts($parts) +    { +        $this->_parts = $parts; +    } + +    /** +     * Append a new Zend_Mime_Part to the current message +     * +     * @param Zend_Mime_Part $part +     */ +    public function addPart(Zend_Mime_Part $part) +    { +        /** +         * @todo check for duplicate object handle +         */ +        $this->_parts[] = $part; +    } + +    /** +     * Check if message needs to be sent as multipart +     * MIME message or if it has only one part. +     * +     * @return boolean +     */ +    public function isMultiPart() +    { +        return (count($this->_parts) > 1); +    } + +    /** +     * Set Zend_Mime object for the message +     * +     * This can be used to set the boundary specifically or to use a subclass of +     * Zend_Mime for generating the boundary. +     * +     * @param Zend_Mime $mime +     */ +    public function setMime(Zend_Mime $mime) +    { +        $this->_mime = $mime; +    } + +    /** +     * Returns the Zend_Mime object in use by the message +     * +     * If the object was not present, it is created and returned. Can be used to +     * determine the boundary used in this message. +     * +     * @return Zend_Mime +     */ +    public function getMime() +    { +        if ($this->_mime === null) { +            $this->_mime = new Zend_Mime(); +        } + +        return $this->_mime; +    } + +    /** +     * Generate MIME-compliant message from the current configuration +     * +     * This can be a multipart message if more than one MIME part was added. If +     * only one part is present, the content of this part is returned. If no +     * part had been added, an empty string is returned. +     * +     * Parts are seperated by the mime boundary as defined in Zend_Mime. If +     * {@link setMime()} has been called before this method, the Zend_Mime +     * object set by this call will be used. Otherwise, a new Zend_Mime object +     * is generated and used. +     * +     * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} +     * @return string +     */ +    public function generateMessage($EOL = Zend_Mime::LINEEND) +    { +        if (! $this->isMultiPart()) { +            $body = array_shift($this->_parts); +            $body = $body->getContent($EOL); +        } else { +            $mime = $this->getMime(); + +            $boundaryLine = $mime->boundaryLine($EOL); +            $body = 'This is a message in Mime Format.  If you see this, ' +                  . "your mail reader does not support this format." . $EOL; + +            foreach (array_keys($this->_parts) as $p) { +                $body .= $boundaryLine +                       . $this->getPartHeaders($p, $EOL) +                       . $EOL +                       . $this->getPartContent($p, $EOL); +            } + +            $body .= $mime->mimeEnd($EOL); +        } + +        return trim($body); +    } + +    /** +     * Get the headers of a given part as an array +     * +     * @param int $partnum +     * @return array +     */ +    public function getPartHeadersArray($partnum) +    { +        return $this->_parts[$partnum]->getHeadersArray(); +    } + +    /** +     * Get the headers of a given part as a string +     * +     * @param int $partnum +     * @return string +     */ +    public function getPartHeaders($partnum, $EOL = Zend_Mime::LINEEND) +    { +        return $this->_parts[$partnum]->getHeaders($EOL); +    } + +    /** +     * Get the (encoded) content of a given part as a string +     * +     * @param int $partnum +     * @return string +     */ +    public function getPartContent($partnum, $EOL = Zend_Mime::LINEEND) +    { +        return $this->_parts[$partnum]->getContent($EOL); +    } + +    /** +     * Explode MIME multipart string into seperate parts +     * +     * Parts consist of the header and the body of each MIME part. +     * +     * @param string $body +     * @param string $boundary +     * @return array +     */ +    protected static function _disassembleMime($body, $boundary) +    { +        $start = 0; +        $res = array(); +        // find every mime part limiter and cut out the +        // string before it. +        // the part before the first boundary string is discarded: +        $p = strpos($body, '--'.$boundary."\n", $start); +        if ($p === false) { +            // no parts found! +            return array(); +        } + +        // position after first boundary line +        $start = $p + 3 + strlen($boundary); + +        while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) { +            $res[] = substr($body, $start, $p-$start); +            $start = $p + 3 + strlen($boundary); +        } + +        // no more parts, find end boundary +        $p = strpos($body, '--' . $boundary . '--', $start); +        if ($p===false) { +            throw new Zend_Exception('Not a valid Mime Message: End Missing'); +        } + +        // the remaining part also needs to be parsed: +        $res[] = substr($body, $start, $p-$start); +        return $res; +    } + +    /** +     * Decodes a MIME encoded string and returns a Zend_Mime_Message object with +     * all the MIME parts set according to the given string +     * +     * @param string $message +     * @param string $boundary +     * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} +     * @return Zend_Mime_Message +     */ +    public static function createFromMessage($message, $boundary, $EOL = Zend_Mime::LINEEND) +    { +        require_once 'Zend/Mime/Decode.php'; +        $parts = Zend_Mime_Decode::splitMessageStruct($message, $boundary, $EOL); + +        $res = new self(); +        foreach ($parts as $part) { +            // now we build a new MimePart for the current Message Part: +            $newPart = new Zend_Mime_Part($part['body']); +            foreach ($part['header'] as $key => $value) { +                /** +                 * @todo check for characterset and filename +                 */ +                switch(strtolower($key)) { +                    case 'content-type': +                        $newPart->type = $value; +                        break; +                    case 'content-transfer-encoding': +                        $newPart->encoding = $value; +                        break; +                    case 'content-id': +                        $newPart->id = trim($value,'<>'); +                        break; +                    case 'content-disposition': +                        $newPart->disposition = $value; +                        break; +                    case 'content-description': +                        $newPart->description = $value; +                        break; +                    case 'content-location': +                        $newPart->location = $value; +                        break; +                    case 'content-language': +                        $newPart->language = $value; +                        break; +                    default: +                        throw new Zend_Exception('Unknown header ignored for MimePart:' . $key); +                } +            } +            $res->addPart($newPart); +        } +        return $res; +    } +} diff --git a/applications/core/lib/Zend/Mime/Part.php b/applications/core/lib/Zend/Mime/Part.php new file mode 100644 index 0000000..010f35b --- /dev/null +++ b/applications/core/lib/Zend/Mime/Part.php @@ -0,0 +1,216 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to [email protected] so we can send you a copy immediately. + * + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ + +/** + * Zend_Mime + */ +require_once 'Zend/Mime.php'; + +/** + * Class representing a MIME part. + * + * @category   Zend + * @package    Zend_Mime + * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @license    http://framework.zend.com/license/new-bsd     New BSD License + */ +class Zend_Mime_Part { + +    public $type = Zend_Mime::TYPE_OCTETSTREAM; +    public $encoding = Zend_Mime::ENCODING_8BIT; +    public $id; +    public $disposition; +    public $filename; +    public $description; +    public $charset; +    public $boundary; +    public $location; +    public $language; +    protected $_content; +    protected $_isStream = false; + + +    /** +     * create a new Mime Part. +     * The (unencoded) content of the Part as passed +     * as a string or stream +     * +     * @param mixed $content  String or Stream containing the content +     */ +    public function __construct($content) +    { +        $this->_content = $content; +        if (is_resource($content)) { +            $this->_isStream = true; +        } +    } + +    /** +     * @todo setters/getters +     * @todo error checking for setting $type +     * @todo error checking for setting $encoding +     */ + +    /** +     * check if this part can be read as a stream. +     * if true, getEncodedStream can be called, otherwise +     * only getContent can be used to fetch the encoded +     * content of the part +     * +     * @return bool +     */ +    public function isStream() +    { +      return $this->_isStream; +    } + +    /** +     * if this was created with a stream, return a filtered stream for +     * reading the content. very useful for large file attachments. +     * +     * @return stream +     * @throws Zend_Mime_Exception if not a stream or unable to append filter +     */ +    public function getEncodedStream() +    { +        if (!$this->_isStream) { +            require_once 'Zend/Mime/Exception.php'; +            throw new Zend_Mime_Exception('Attempt to get a stream from a string part'); +        } + +        //stream_filter_remove(); // ??? is that right? +        switch ($this->encoding) { +            case Zend_Mime::ENCODING_QUOTEDPRINTABLE: +                $filter = stream_filter_append( +                    $this->_content, +                    'convert.quoted-printable-encode', +                    STREAM_FILTER_READ, +                    array( +                        'line-length'      => 76, +                        'line-break-chars' => Zend_Mime::LINEEND +                    ) +                ); +                if (!is_resource($filter)) { +                    require_once 'Zend/Mime/Exception.php'; +                    throw new Zend_Mime_Exception('Failed to append quoted-printable filter'); +                } +                break; +            case Zend_Mime::ENCODING_BASE64: +                $filter = stream_filter_append( +                    $this->_content, +                    'convert.base64-encode', +                    STREAM_FILTER_READ, +                    array( +                        'line-length'      => 76, +                        'line-break-chars' => Zend_Mime::LINEEND +                    ) +                ); +                if (!is_resource($filter)) { +                    require_once 'Zend/Mime/Exception.php'; +                    throw new Zend_Mime_Exception('Failed to append base64 filter'); +                } +                break; +            default: +        } +        return $this->_content; +    } + +    /** +     * Get the Content of the current Mime Part in the given encoding. +     * +     * @return String +     */ +    public function getContent($EOL = Zend_Mime::LINEEND) +    { +        if ($this->_isStream) { +            return stream_get_contents($this->getEncodedStream()); +        } else { +            return Zend_Mime::encode($this->_content, $this->encoding, $EOL); +        } +    } + +    /** +     * Create and return the array of headers for this MIME part +     * +     * @access public +     * @return array +     */ +    public function getHeadersArray($EOL = Zend_Mime::LINEEND) +    { +        $headers = array(); + +        $contentType = $this->type; +        if ($this->charset) { +            $contentType .= '; charset=' . $this->charset; +        } + +        if ($this->boundary) { +            $contentType .= ';' . $EOL +                          . " boundary=\"" . $this->boundary . '"'; +        } + +        $headers[] = array('Content-Type', $contentType); + +        if ($this->encoding) { +            $headers[] = array('Content-Transfer-Encoding', $this->encoding); +        } + +        if ($this->id) { +            $headers[]  = array('Content-ID', '<' . $this->id . '>'); +        } + +        if ($this->disposition) { +            $disposition = $this->disposition; +            if ($this->filename) { +                $disposition .= '; filename="' . $this->filename . '"'; +            } +            $headers[] = array('Content-Disposition', $disposition); +        } + +        if ($this->description) { +            $headers[] = array('Content-Description', $this->description); +        } + +        if ($this->location) { +            $headers[] = array('Content-Location', $this->location); +        } + +        if ($this->language){ +            $headers[] = array('Content-Language', $this->language); +        } + +        return $headers; +    } + +    /** +     * Return the headers for this part as a string +     * +     * @return String +     */ +    public function getHeaders($EOL = Zend_Mime::LINEEND) +    { +        $res = ''; +        foreach ($this->getHeadersArray($EOL) as $header) { +            $res .= $header[0] . ': ' . $header[1] . $EOL; +        } + +        return $res; +    } +} | 
