Request #3359: Horde_Mime_Part & streams
authorMichael M Slusarz <slusarz@curecanti.org>
Tue, 30 Jun 2009 02:51:38 +0000 (20:51 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 30 Jun 2009 04:56:17 +0000 (22:56 -0600)
Use PHP temporary streams when working with message body data to reduce
memory usage.

imp/docs/CHANGES
imp/lib/Contents.php
imp/lib/Mime/Viewer/Partial.php
imp/view.php

index e8348b6..3344207 100644 (file)
@@ -2,6 +2,8 @@
 v5.0-git
 --------
 
+[mms] Use PHP temporary streams when working with message body data to reduce
+      memory usage (Request #3359).
 [mms] Add ability to expand/collapse all folders in DIMP.
 [mms] Add Folder Options menu to DIMP.
 [mms] Add save link to full message display in DIMP.
index 3fa4dc3..36aac8f 100644 (file)
@@ -151,17 +151,24 @@ class IMP_Contents
     /**
      * Returns the entire body of the message.
      *
-     * @return string  The text of the body of the message.
+     * @param array $options  Additional options:
+     * <pre>
+     * 'stream' - (boolean) If true, return a stream.
+     *            DEFAULT: No
+     * </pre>
+     *
+     * @return mixed  The text of the part, or a stream resource if 'stream'
+     *                is true.
      */
-    public function getBody()
+    public function getBody($options = array())
     {
         if (is_null($this->_mailbox)) {
-            return $this->_message->toString();
+            return $this->_message->toString(true, !empty($options['stream']));
         }
 
         try {
             $res = $GLOBALS['imp_imap']->ob->fetch($this->_mailbox, array(
-                Horde_Imap_Client::FETCH_BODYTEXT => array(array('peek' => true))
+                Horde_Imap_Client::FETCH_BODYTEXT => array(array('peek' => true, 'stream' => !empty($options['stream'])))
             ), array('ids' => array($this->_index)));
             return $res[$this->_index]['bodytext'][0];
         } catch (Horde_Imap_Client_Exception $e) {
@@ -180,9 +187,12 @@ class IMP_Contents
      *            DEFAULT: All data is retrieved.
      * 'mimeheaders' - (boolean) Include the MIME headers also?
      *                 DEFAULT: No
+     * 'stream' - (boolean) If true, return a stream.
+     *            DEFAULT: No
      * </pre>
      *
-     * @return string  The text of the part.
+     * @return mixed  The text of the part, or a stream resource if 'stream'
+     *                is true.
      */
     public function getBodyPart($id, $options = array())
     {
@@ -199,7 +209,7 @@ class IMP_Contents
         }
 
         $query = array(
-            Horde_Imap_Client::FETCH_BODYPART => array(array('id' => $id, 'peek' => true))
+            Horde_Imap_Client::FETCH_BODYPART => array(array('id' => $id, 'peek' => true, 'stream' => !empty($options['stream'])))
         );
         if (!empty($options['length'])) {
             $query[Horde_Imap_Client::FETCH_BODYPART][0]['start'] = 0;
@@ -227,10 +237,11 @@ class IMP_Contents
     public function fullMessageText()
     {
         if (is_null($this->_mailbox)) {
-            return $this->_message->toString(true);
+            return $this->_message->toString();
         }
 
         try {
+            // TODO - use streams
             $res = $GLOBALS['imp_imap']->ob->fetch($this->_mailbox, array(
                 Horde_Imap_Client::FETCH_HEADERTEXT => array(array('peek' => true)),
                 Horde_Imap_Client::FETCH_BODYTEXT => array(array('peek' => true))
@@ -304,7 +315,7 @@ class IMP_Contents
             empty($options['nocontents']) &&
             !is_null($this->_mailbox) &&
             !$part->getContents()) {
-            $contents = $this->getBodyPart($id, array('length' => empty($options['length']) ? null : $options['length']));
+            $contents = $this->getBodyPart($id, array('length' => empty($options['length']) ? null : $options['length'], 'stream' => true));
             if (($part->getPrimaryType() == 'text') &&
                 (Horde_String::upper($part->getCharset()) == 'US-ASCII') &&
                 Horde_Mime::is8bit($contents)) {
index 4572198..3a7b236 100644 (file)
@@ -67,7 +67,7 @@ class IMP_Horde_Mime_Viewer_Partial extends Horde_Mime_Viewer_Driver
             if ($val == $number) {
                 $parts[$number] = $this->_mimepart->getContents();
             } else {
-                $ic = &IMP_Contents::singleton($val . IMP::IDX_SEP . $mbox);
+                $ic = IMP_Contents::singleton($val . IMP::IDX_SEP . $mbox);
                 $parts[$ic->getMIMEMessage()->getContentTypeParameter('number')] = $ic->getBody();
             }
         }
index 06505bc..05c034e 100644 (file)
@@ -55,12 +55,12 @@ $id = Horde_Util::getFormData('id');
  * get the necessary Horde_Mime_Part. */
 if ($actionID == 'compose_attach_preview') {
     /* Initialize the IMP_Compose:: object. */
-    $imp_compose = &IMP_Compose::singleton(Horde_Util::getFormData('composeCache'));
+    $imp_compose = IMP_Compose::singleton(Horde_Util::getFormData('composeCache'));
     $mime = $imp_compose->buildAttachment($id);
 
     /* Create a dummy IMP_Contents() object so we can use the view code below.
      * Then use the 'view_attach' handler to output. */
-    $contents = &IMP_Contents::singleton($mime);
+    $contents = IMP_Contents::singleton($mime);
     $actionID = 'view_attach';
     $id = $mime->getMimeId();
 } else {
@@ -75,7 +75,7 @@ if ($actionID == 'compose_attach_preview') {
     }
 
     try {
-        $contents = &IMP_Contents::singleton($uid . IMP::IDX_SEP . $mailbox);
+        $contents = IMP_Contents::singleton($uid . IMP::IDX_SEP . $mailbox);
     } catch (Horde_Exception $e) {
         Horde::fatal($e, __FILE__, __LINE__);
     }
@@ -103,7 +103,7 @@ case 'download_all':
     }
 
     if (!empty($tosave)) {
-        $horde_compress = &Horde_Compress::singleton('zip');
+        $horde_compress = Horde_Compress::singleton('zip');
         $body = $horde_compress->compress($tosave);
         $browser->downloadHeaders($zipfile, 'application/zip', false, strlen($body));
         echo $body;
@@ -115,9 +115,20 @@ case 'download_render':
     switch ($actionID) {
     case 'download_attach':
         $mime = $contents->getMIMEPart($id);
-        $body = $mime->getContents();
-        $type = $mime->getType(true);
-        $name = $mime->getName(true);
+        if (!$name = $mime->getName(true)) {
+           $name = _("unnamed");
+        }
+
+        /* Compress output? */
+        if (Horde_Util::getFormData('zip')) {
+            $horde_compress = Horde_Compress::singleton('zip');
+            $body = $horde_compress->compress(array(array('data' => $mime->getContents(), 'name' => $name)));
+            $name .= '.zip';
+            $type = 'application/zip';
+        } else {
+            $body = $mime->getContentsAsStream();
+            $type = $mime->getType(true);
+        }
         break;
 
     case 'download_render':
@@ -126,23 +137,18 @@ case 'download_render':
         $key = key($render);
         $body = $render[$key]['data'];
         $type = $render[$key]['type'];
-        $name = $render[$key]['name'];
+        if (!$name = $render[$key]['name']) {
+           $name = _("unnamed");
+        }
         break;
     }
 
-    if (empty($name)) {
-        $name = _("unnamed");
-    }
-
-    /* Compress output? */
-    if (($actionID == 'download_attach') && Horde_Util::getFormData('zip')) {
-        $horde_compress = &Horde_Compress::singleton('zip');
-        $body = $horde_compress->compress(array(array('data' => $body, 'name' => $name)));
-        $name .= '.zip';
-        $type = 'application/zip';
-    }
     $browser->downloadHeaders($name, $type, false, strlen($body));
-    echo $body;
+    if (is_resource($body)) {
+        fpassthru($body);
+    } else {
+        echo $body;
+    }
     exit;
 
 case 'view_attach':