PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/etc/apps/webmail/plugins/zipdownload/zipdownload.php

https://github.com/raiman264/zpanelx
PHP | 284 lines | 188 code | 49 blank | 47 comment | 35 complexity | d9d4e5cd241065181002dd73785e9262 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0, LGPL-2.1, CC-BY-SA-4.0, GPL-3.0
  1. <?php
  2. /**
  3. * ZipDownload
  4. *
  5. * Plugin to allow the download of all message attachments in one zip file
  6. *
  7. * @version @package_version@
  8. * @requires php_zip extension (including ZipArchive class)
  9. * @author Philip Weir
  10. * @author Thomas Bruderli
  11. */
  12. class zipdownload extends rcube_plugin
  13. {
  14. public $task = 'mail';
  15. private $charset = 'ASCII';
  16. /**
  17. * Plugin initialization
  18. */
  19. public function init()
  20. {
  21. // check requirements first
  22. if (!class_exists('ZipArchive', false)) {
  23. rcmail::raise_error(array(
  24. 'code' => 520,
  25. 'file' => __FILE__,
  26. 'line' => __LINE__,
  27. 'message' => "php_zip extension is required for the zipdownload plugin"), true, false);
  28. return;
  29. }
  30. $rcmail = rcmail::get_instance();
  31. $this->load_config();
  32. $this->charset = $rcmail->config->get('zipdownload_charset', RCUBE_CHARSET);
  33. $this->add_texts('localization');
  34. if ($rcmail->config->get('zipdownload_attachments', 1) > -1 && ($rcmail->action == 'show' || $rcmail->action == 'preview')) {
  35. $this->add_hook('template_object_messageattachments', array($this, 'attachment_ziplink'));
  36. }
  37. $this->register_action('plugin.zipdownload.zip_attachments', array($this, 'download_attachments'));
  38. $this->register_action('plugin.zipdownload.zip_messages', array($this, 'download_selection'));
  39. $this->register_action('plugin.zipdownload.zip_folder', array($this, 'download_folder'));
  40. if (($selection = $rcmail->config->get('zipdownload_selection')) || $rcmail->config->get('zipdownload_folder')) {
  41. $this->include_script('zipdownload.js');
  42. $this->api->output->set_env('zipdownload_selection', $selection);
  43. if ($rcmail->config->get('zipdownload_folder', false) && ($rcmail->action == '' || $rcmail->action == 'show')) {
  44. $zipdownload = $this->api->output->button(array('command' => 'plugin.zipdownload.zip_folder', 'type' => 'link', 'classact' => 'active', 'content' => $this->gettext('downloadfolder')));
  45. $this->api->add_content(html::tag('li', array('class' => 'separator_above'), $zipdownload), 'mailboxoptions');
  46. }
  47. }
  48. }
  49. /**
  50. * Place a link/button after attachments listing to trigger download
  51. */
  52. public function attachment_ziplink($p)
  53. {
  54. $rcmail = rcmail::get_instance();
  55. // only show the link if there is more than the configured number of attachments
  56. if (substr_count($p['content'], '<li') > $rcmail->config->get('zipdownload_attachments', 1)) {
  57. $href = $rcmail->url(array(
  58. '_action' => 'plugin.zipdownload.zip_attachments',
  59. '_mbox' => $rcmail->output->env['mailbox'],
  60. '_uid' => $rcmail->output->env['uid'],
  61. ));
  62. $link = html::a(array('href' => $href, 'class' => 'button zipdownload'),
  63. rcube::Q($this->gettext('downloadall'))
  64. );
  65. // append link to attachments list, slightly different in some skins
  66. switch (rcmail::get_instance()->config->get('skin')) {
  67. case 'classic':
  68. $p['content'] = str_replace('</ul>', html::tag('li', array('class' => 'zipdownload'), $link) . '</ul>', $p['content']);
  69. break;
  70. default:
  71. $p['content'] .= $link;
  72. break;
  73. }
  74. $this->include_stylesheet($this->local_skin_path() . '/zipdownload.css');
  75. }
  76. return $p;
  77. }
  78. /**
  79. * Handler for attachment download action
  80. */
  81. public function download_attachments()
  82. {
  83. $rcmail = rcmail::get_instance();
  84. $imap = $rcmail->get_storage();
  85. $temp_dir = $rcmail->config->get('temp_dir');
  86. $tmpfname = tempnam($temp_dir, 'zipdownload');
  87. $tempfiles = array($tmpfname);
  88. $message = new rcube_message(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET));
  89. // open zip file
  90. $zip = new ZipArchive();
  91. $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
  92. foreach ($message->attachments as $part) {
  93. $pid = $part->mime_id;
  94. $part = $message->mime_parts[$pid];
  95. $filename = $part->filename;
  96. if ($filename === null || $filename === '') {
  97. $ext = (array) rcube_mime::get_mime_extensions($part->mimetype);
  98. $ext = array_shift($ext);
  99. $filename = $rcmail->gettext('messagepart') . ' ' . $pid;
  100. if ($ext) {
  101. $filename .= '.' . $ext;
  102. }
  103. }
  104. $disp_name = $this->_convert_filename($filename);
  105. if ($part->body) {
  106. $orig_message_raw = $part->body;
  107. $zip->addFromString($disp_name, $orig_message_raw);
  108. }
  109. else {
  110. $tmpfn = tempnam($temp_dir, 'zipattach');
  111. $tmpfp = fopen($tmpfn, 'w');
  112. $imap->get_message_part($message->uid, $part->mime_id, $part, null, $tmpfp, true);
  113. $tempfiles[] = $tmpfn;
  114. fclose($tmpfp);
  115. $zip->addFile($tmpfn, $disp_name);
  116. }
  117. }
  118. $zip->close();
  119. $filename = ($message->subject ? $message->subject : 'roundcube') . '.zip';
  120. $this->_deliver_zipfile($tmpfname, $filename);
  121. // delete temporary files from disk
  122. foreach ($tempfiles as $tmpfn) {
  123. unlink($tmpfn);
  124. }
  125. exit;
  126. }
  127. /**
  128. * Handler for message download action
  129. */
  130. public function download_selection()
  131. {
  132. if (isset($_REQUEST['_uid'])) {
  133. $uids = explode(",", rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GPC));
  134. if (sizeof($uids) > 0) {
  135. $this->_download_messages($uids);
  136. }
  137. }
  138. }
  139. /**
  140. * Handler for folder download action
  141. */
  142. public function download_folder()
  143. {
  144. $imap = rcmail::get_instance()->get_storage();
  145. $mbox_name = $imap->get_folder();
  146. // initialize searching result if search_filter is used
  147. if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') {
  148. $imap->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET);
  149. }
  150. // fetch message headers for all pages
  151. $uids = array();
  152. if ($count = $imap->count($mbox_name, $imap->get_threading() ? 'THREADS' : 'ALL', FALSE)) {
  153. for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) {
  154. $a_headers = $imap->list_messages($mbox_name, ($i + 1));
  155. foreach ($a_headers as $header) {
  156. if (empty($header))
  157. continue;
  158. array_push($uids, $header->uid);
  159. }
  160. }
  161. }
  162. if (sizeof($uids) > 0)
  163. $this->_download_messages($uids);
  164. }
  165. /**
  166. * Helper method to packs all the given messages into a zip archive
  167. *
  168. * @param array List of message UIDs to download
  169. */
  170. private function _download_messages($uids)
  171. {
  172. $rcmail = rcmail::get_instance();
  173. $imap = $rcmail->get_storage();
  174. $temp_dir = $rcmail->config->get('temp_dir');
  175. $tmpfname = tempnam($temp_dir, 'zipdownload');
  176. $tempfiles = array($tmpfname);
  177. // open zip file
  178. $zip = new ZipArchive();
  179. $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
  180. foreach ($uids as $uid){
  181. $headers = $imap->get_message_headers($uid);
  182. $subject = rcube_mime::decode_mime_string((string)$headers->subject);
  183. $subject = $this->_convert_filename($subject);
  184. $subject = substr($subject, 0, 16);
  185. $disp_name = ($subject ? $subject : 'message_rfc822') . ".eml";
  186. $disp_name = $uid . "_" . $disp_name;
  187. $tmpfn = tempnam($temp_dir, 'zipmessage');
  188. $tmpfp = fopen($tmpfn, 'w');
  189. $imap->get_raw_body($uid, $tmpfp);
  190. $tempfiles[] = $tmpfn;
  191. fclose($tmpfp);
  192. $zip->addFile($tmpfn, $disp_name);
  193. }
  194. $zip->close();
  195. $this->_deliver_zipfile($tmpfname, $imap->get_folder() . '.zip');
  196. // delete temporary files from disk
  197. foreach ($tempfiles as $tmpfn) {
  198. unlink($tmpfn);
  199. }
  200. exit;
  201. }
  202. /**
  203. * Helper method to send the zip archive to the browser
  204. */
  205. private function _deliver_zipfile($tmpfname, $filename)
  206. {
  207. $browser = new rcube_browser;
  208. $rcmail = rcmail::get_instance();
  209. $rcmail->output->nocacheing_headers();
  210. if ($browser->ie && $browser->ver < 7)
  211. $filename = rawurlencode(abbreviate_string($filename, 55));
  212. else if ($browser->ie)
  213. $filename = rawurlencode($filename);
  214. else
  215. $filename = addcslashes($filename, '"');
  216. // send download headers
  217. header("Content-Type: application/octet-stream");
  218. if ($browser->ie) {
  219. header("Content-Type: application/force-download");
  220. }
  221. // don't kill the connection if download takes more than 30 sec.
  222. @set_time_limit(0);
  223. header("Content-Disposition: attachment; filename=\"". $filename ."\"");
  224. header("Content-length: " . filesize($tmpfname));
  225. readfile($tmpfname);
  226. }
  227. /**
  228. * Helper function to convert filenames to the configured charset
  229. */
  230. private function _convert_filename($str)
  231. {
  232. $str = rcube_charset::convert($str, RCUBE_CHARSET, $this->charset);
  233. return strtr($str, array(':'=>'', '/'=>'-'));
  234. }
  235. }