Test Failed
Push — master ( 647c72...cd42b5 )
by
unknown
10:25
created

server/includes/download_message.php (1 issue)

Severity
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
It is not recommended to use PHP's closing tag ?> in files other than templates.

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.

Loading history...
178