Use streams when sending compressed zip data
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 13 Jul 2009 23:39:27 +0000 (17:39 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Mon, 13 Jul 2009 23:40:00 +0000 (17:40 -0600)
imp/docs/CHANGES
imp/folders.php
imp/lib/Folder.php
imp/lib/UI/Message.php
imp/view.php

index b2a207d..ca648d2 100644 (file)
@@ -2,6 +2,8 @@
 v5.0-git
 --------
 
+[mms] When generating and sending compressed ZIP data, use server-side temp
+      streams to minimize memory usage.
 [mms] Decode bodypart data on server if possible (RFC 3516).
 [mms] Use PHP temporary streams when working with message body data to reduce
       memory usage (Request #3359).
index a16b362..b76e7f7 100644 (file)
@@ -133,18 +133,24 @@ case 'download_folder_zip':
     if (!empty($folder_list)) {
         $mbox = $imp_folder->generateMbox($folder_list);
         if ($actionID == 'download_folder') {
-            $browser->downloadHeaders($folder_list[0] . '.mbox', null, false, strlen($mbox));
+            $data = $mbox;
+            fseek($data, 0, SEEK_END);
+            $browser->downloadHeaders($folder_list[0] . '.mbox', null, false, ftell($data));
         } else {
             $horde_compress = Horde_Compress::factory('zip');
             try {
-                $mbox = $horde_compress->compress(array(array('data' => $mbox, 'name' => $folder_list[0] . '.mbox')));
+                $data = $horde_compress->compress(array(array('data' => $mbox, 'name' => $folder_list[0] . '.mbox')), array('stream' => true));
+                fclose($mbox);
             } catch (Horde_Exception $e) {
+                fclose($mbox);
                 $notification->push($e, 'horde.error');
                 break;
             }
-            $browser->downloadHeaders($folder_list[0] . '.zip', 'application/zip', false, strlen($mbox));
+            fseek($data, 0, SEEK_END);
+            $browser->downloadHeaders($folder_list[0] . '.zip', 'application/zip', false, ftell($data));
         }
-        echo $mbox;
+        rewind($data);
+        fpassthru($data);
         exit;
     }
     break;
index add8d70..fdfca82 100644 (file)
@@ -476,11 +476,12 @@ class IMP_Folder
      * @param array $folder_list  A list of folder names to generate a mbox
      *                            file for (UTF7-IMAP).
      *
-     * @return string  An mbox format mailbox file.
+     * @return resource  A stream resource containing the text of a mbox
+     *                   format mailbox file.
      */
     public function generateMbox($folder_list)
     {
-        $body = '';
+        $body = fopen('php://temp', 'r+');
 
         if (empty($folder_list)) {
             return $body;
@@ -488,7 +489,7 @@ class IMP_Folder
 
         foreach ($folder_list as $folder) {
             try {
-                $status = $GLOBALS['imp_imap']->status($folder, Horde_Imap_Client::STATUS_MESSAGES);
+                $status = $GLOBALS['imp_imap']->ob->status($folder, Horde_Imap_Client::STATUS_MESSAGES);
             } catch (Horde_Imap_Client_Exception $e) {
                 continue;
             }
@@ -497,7 +498,7 @@ class IMP_Folder
                  * overhead. */
                 try {
                     $res = $GLOBALS['imp_imap']->ob->fetch($folder, array(
-                            Horde_Imap_Client::FETCH_FULLMSG => array('peek' => true),
+                            Horde_Imap_Client::FETCH_FULLMSG => array('peek' => true, 'stream' => true),
                             Horde_Imap_Client::FETCH_ENVELOPE => true,
                             Horde_Imap_Client::FETCH_DATE => true,
                         ), array('ids' => array($i), 'sequence' => true));
@@ -517,8 +518,11 @@ class IMP_Folder
                 /* We need this long command since some MUAs (e.g. pine)
                  * require a space in front of single digit days. */
                 $date = sprintf('%s %2s %s', $ptr['date']->format('D M'), $ptr['date']->format('j'), $ptr['date']->format('H:i:s Y'));
-                $body .= 'From ' . $from . ' ' . $date . "\r\n" .
-                    $ptr['fullmsg'] . "\r\n";
+                fwrite($body, 'From ' . $from . ' ' . $date . "\r\n");
+                rewind($ptr['fullmsg']);
+                stream_copy_to_stream($ptr['fullmsg'], $body);
+                fclose($ptr['fullmsg']);
+                fwrite($body, "\r\n");
             }
         }
 
index d755606..d6300a8 100644 (file)
@@ -319,12 +319,12 @@ class IMP_UI_Message
         /* Set up the add address icon link if contact manager is
          * available. */
         if (!is_null($addURL) && $link && $prefs->getValue('add_source')) {
-            $add_link = $registry->link('contacts/add', array('source' => $prefs->getValue('add_source')));
-            if (is_a($add_link, 'PEAR_Error')) {
+            try {
+                $registry->link('contacts/add', array('source' => $prefs->getValue('add_source')));
                 $add_link = $registry->hasMethod('contacts/import')
                     ? Horde_Util::addParameter($addURL, 'actionID', 'add_address')
                     : null;
-            }
+            } catch (Horde_Exception $e) {}
         }
 
         foreach (Horde_Mime_Address::getAddressesFromObject($addrlist) as $ob) {
index 60880e8..2ce8b4f 100644 (file)
@@ -107,18 +107,20 @@ case 'download_all':
         if (!$name) {
             $name = sprintf(_("part %s"), $val);
         }
-        $tosave[] = array('data' => $mime->getContents(), 'name' => $name);
+        $tosave[] = array('data' => $mime->getContents(array('stream' => true)), 'name' => $name);
     }
 
     if (!empty($tosave)) {
         try {
             $horde_compress = Horde_Compress::factory('zip');
-            $body = $horde_compress->compress($tosave);
+            $body = $horde_compress->compress($tosave, array('stream' => true));
         } catch (Horde_Exception $e) {
             Horde::fatal($e);
         }
-        $browser->downloadHeaders($zipfile, 'application/zip', false, strlen($body));
-        echo $body;
+        fseek($body, 0, SEEK_END);
+        $browser->downloadHeaders($zipfile, 'application/zip', false, ftell($body));
+        rewind($body);
+        fpassthru($body);
     }
     exit;
 
@@ -135,7 +137,7 @@ case 'download_render':
         if (Horde_Util::getFormData('zip')) {
             try {
                 $horde_compress = Horde_Compress::factory('zip');
-                $body = $horde_compress->compress(array(array('data' => $mime->getContents(), 'name' => $name)));
+                $body = $horde_compress->compress(array(array('data' => $mime->getContents(), 'name' => $name)), array('stream' => true));
             } catch (Horde_Exception $e) {
                 Horde::fatal($e);
             }
@@ -159,11 +161,13 @@ case 'download_render':
         break;
     }
 
-    $browser->downloadHeaders($name, $type, false, strlen($body));
     if (is_resource($body)) {
+        fseek($body, 0, SEEK_END);
+        $browser->downloadHeaders($name, $type, false, ftell($body));
         rewind($body);
         fpassthru($body);
     } else {
+        $browser->downloadHeaders($name, $type, false, strlen($body));
         echo $body;
     }
     exit;