grommunio /
grommunio-web
| 1 | <?php |
||
| 2 | // required to handle php errors |
||
| 3 | require_once(__DIR__ . '/exceptions/class.ZarafaErrorException.php'); |
||
| 4 | require_once(__DIR__ . '/download_base.php'); |
||
| 5 | /** |
||
| 6 | * DownloadMessage |
||
| 7 | * |
||
| 8 | * A class to manage downloading of message as a file, |
||
| 9 | * it will generate the message as RFC822-formatted e-mail stream. |
||
| 10 | * It extends the DownloadBase class. |
||
| 11 | */ |
||
| 12 | class DownloadMessage extends DownloadBase |
||
| 13 | { |
||
| 14 | /** |
||
| 15 | * Function get message-stream using respective mapi function. |
||
| 16 | * It also sends the eml file to the client. |
||
| 17 | */ |
||
| 18 | function downloadMessageAsFile() |
||
| 19 | { |
||
| 20 | if($this->message && $this->store) { |
||
| 21 | // get message properties. |
||
| 22 | $messageProps = mapi_getprops($this->message, array(PR_SUBJECT, PR_EC_IMAP_EMAIL, PR_MESSAGE_CLASS)); |
||
| 23 | |||
| 24 | $stream = $this->getEmlStream($messageProps); |
||
| 25 | |||
| 26 | $filename = (!empty($messageProps[PR_SUBJECT])) ? $messageProps[PR_SUBJECT] : _('Untitled'); |
||
| 27 | $filename .= '.eml'; |
||
| 28 | |||
| 29 | // Set the file length |
||
| 30 | $stat = mapi_stream_stat($stream); |
||
| 31 | |||
| 32 | $this->setNecessaryHeaders($filename, $stat['cb']); |
||
| 33 | |||
| 34 | // Read whole message and echo it. |
||
| 35 | for($i = 0; $i < $stat['cb']; $i += BLOCK_SIZE) { |
||
| 36 | // Print stream |
||
| 37 | echo mapi_stream_read($stream, BLOCK_SIZE); |
||
| 38 | |||
| 39 | // Need to discard the buffer contents to prevent memory |
||
| 40 | // exhaustion while echoing large content. |
||
| 41 | ob_flush(); |
||
| 42 | } |
||
| 43 | } |
||
| 44 | } |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Function will create a ZIP archive and add eml files into the same. |
||
| 48 | * It also configures necessary header information which required to send the ZIP file to client. |
||
| 49 | * Send ZIP to the client if all the requested eml files included successfully into the same. |
||
| 50 | */ |
||
| 51 | function downloadMessageAsZipFile() |
||
| 52 | { |
||
| 53 | if($this->store) { |
||
| 54 | // Generate random ZIP file name at default temporary path of PHP |
||
| 55 | $randomZipName = tempnam(sys_get_temp_dir(), 'zip'); |
||
| 56 | |||
| 57 | // Create an open zip archive. |
||
| 58 | $zip = new ZipArchive(); |
||
| 59 | $result = $zip->open($randomZipName, ZipArchive::CREATE); |
||
| 60 | |||
| 61 | if ($result === TRUE) { |
||
| 62 | for($index = 0, $count = count($this->entryIds); $index < $count; $index++) { |
||
| 63 | |||
| 64 | $this->message = mapi_msgstore_openentry($this->store, hex2bin($this->entryIds[$index])); |
||
| 65 | |||
| 66 | // get message properties. |
||
| 67 | $messageProps = mapi_getprops($this->message, array(PR_SUBJECT, PR_EC_IMAP_EMAIL, PR_MESSAGE_CLASS)); |
||
| 68 | |||
| 69 | $stream = $this->getEmlStream($messageProps); |
||
| 70 | $stat = mapi_stream_stat($stream); |
||
| 71 | |||
| 72 | // Get the stream |
||
| 73 | $datastring = ''; |
||
| 74 | for($i = 0; $i < $stat['cb']; $i += BLOCK_SIZE) { |
||
| 75 | $datastring .= mapi_stream_read($stream, BLOCK_SIZE); |
||
| 76 | // Need to discard the buffer contents to prevent memory |
||
| 77 | // exhaustion. |
||
| 78 | ob_flush(); |
||
| 79 | } |
||
| 80 | |||
| 81 | $filename = (!empty($messageProps[PR_SUBJECT])) ? $messageProps[PR_SUBJECT] : _('Untitled'); |
||
| 82 | $filename .= '.eml'; |
||
| 83 | |||
| 84 | $filename = $this->handleDuplicateFileNames($filename); |
||
| 85 | // Remove slashes to prevent unwanted directories to be created in the zip file. |
||
| 86 | $filename = str_replace('\\', '_', $filename); |
||
| 87 | $filename = str_replace('/', '_', $filename); |
||
| 88 | |||
| 89 | // Add file into zip by stream |
||
| 90 | $zip->addFromString($filename, $datastring); |
||
| 91 | } |
||
| 92 | } else { |
||
| 93 | $zip->close(); |
||
| 94 | // Remove the zip file to avoid unnecessary disk-space consumption |
||
| 95 | unlink($randomZipName); |
||
| 96 | |||
| 97 | // Throw exception if ZIP is not created successfully |
||
| 98 | throw new ZarafaException(_("ZIP is not created successfully")); |
||
| 99 | } |
||
| 100 | |||
| 101 | $zip->close(); |
||
| 102 | |||
| 103 | // Set the headers |
||
| 104 | header('Pragma: public'); |
||
| 105 | header('Expires: 0'); // set expiration time |
||
| 106 | header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); |
||
| 107 | header('Content-Disposition: attachment; filename="' . addslashes(browserDependingHTTPHeaderEncode(_("Messages").date(" d-m-Y").".zip")) . '"'); |
||
| 108 | header('Content-Transfer-Encoding: binary'); |
||
| 109 | header('Content-Type: application/zip'); |
||
| 110 | header('Content-Length: ' . filesize($randomZipName)); |
||
| 111 | |||
| 112 | // Send the actual response as ZIP file |
||
| 113 | readfile($randomZipName); |
||
| 114 | |||
| 115 | // Remove the zip file to avoid unnecessary disk-space consumption |
||
| 116 | unlink($randomZipName); |
||
| 117 | } |
||
| 118 | } |
||
| 119 | |||
| 120 | /** |
||
| 121 | * Function will obtain stream from the message, For email messages it will open email as |
||
| 122 | * inet object and get the stream content as eml format, when user has IMAP enabled. |
||
| 123 | * The below mentioned properties are configured with the whole message as a stream in it, while IMAP is enabled: |
||
| 124 | * PR_EC_IMAP_EMAIL |
||
| 125 | * PR_EC_IMAP_EMAIL_SIZE |
||
| 126 | * PR_EC_IMAP_BODY |
||
| 127 | * PR_EC_IMAP_BODYSTRUCTURE |
||
| 128 | * @param Array $messageProps Properties of this particular message. |
||
| 129 | * @return Stream $stream The eml stream obtained from message. |
||
| 130 | */ |
||
| 131 | function getEmlStream($messageProps) |
||
| 132 | { |
||
| 133 | // If RFC822-formatted stream is already available in PR_EC_IMAP_EMAIL property |
||
| 134 | // than directly use it, generate otherwise. |
||
| 135 | if(isset($messageProps[PR_EC_IMAP_EMAIL]) || propIsError(PR_EC_IMAP_EMAIL, $messageProps) == MAPI_E_NOT_ENOUGH_MEMORY) { |
||
| 136 | // Stream the message to properly get the PR_EC_IMAP_EMAIL property |
||
| 137 | $stream = mapi_openproperty($this->message, PR_EC_IMAP_EMAIL, IID_IStream, 0, 0); |
||
| 138 | } else { |
||
| 139 | // Get addressbook for current session |
||
| 140 | $addrBook = $GLOBALS['mapisession']->getAddressbook(); |
||
| 141 | |||
| 142 | // Read the message as RFC822-formatted e-mail stream. |
||
| 143 | $stream = mapi_inetmapi_imtoinet($GLOBALS['mapisession']->getSession(), $addrBook, $this->message, array()); |
||
| 144 | } |
||
| 145 | |||
| 146 | return $stream; |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Check received data and decide either the eml file or |
||
| 151 | * ZIP file is requested to be downloaded. |
||
| 152 | */ |
||
| 153 | public function download() |
||
| 154 | { |
||
| 155 | if($this->allAsZip){ |
||
| 156 | // download multiple eml messages in a ZIP file |
||
| 157 | $this->downloadMessageAsZipFile(); |
||
| 158 | } else { |
||
| 159 | // download message as file |
||
| 160 | $this->downloadMessageAsFile(); |
||
| 161 | } |
||
| 162 | } |
||
| 163 | } |
||
| 164 | |||
| 165 | // create instance of class to download message as file |
||
| 166 | $messageInstance = new DownloadMessage(); |
||
| 167 | |||
| 168 | try { |
||
| 169 | // initialize variables |
||
| 170 | $messageInstance->init($_GET); |
||
| 171 | |||
| 172 | // download message |
||
| 173 | $messageInstance->download(); |
||
| 174 | } catch (Exception $e) { |
||
| 175 | $messageInstance->handleSaveMessageException($e); |
||
| 176 | } |
||
| 177 | ?> |
||
|
0 ignored issues
–
show
|
|||
| 178 |
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.
A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.