You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

filesystem_attachments.php 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. /**
  3. * Filesystem Attachments
  4. *
  5. * This is a core plugin which provides basic, filesystem based
  6. * attachment temporary file handling. This includes storing
  7. * attachments of messages currently being composed, writing attachments
  8. * to disk when drafts with attachments are re-opened and writing
  9. * attachments to disk for inline display in current html compositions.
  10. *
  11. * Developers may wish to extend this class when creating attachment
  12. * handler plugins:
  13. * require_once('plugins/filesystem_attachments/filesystem_attachments.php');
  14. * class myCustom_attachments extends filesystem_attachments
  15. *
  16. * @license GNU GPLv3+
  17. * @author Ziba Scott <ziba@umich.edu>
  18. * @author Thomas Bruederli <roundcube@gmail.com>
  19. */
  20. class filesystem_attachments extends rcube_plugin
  21. {
  22. public $task = '?(?!login).*';
  23. function init()
  24. {
  25. // Save a newly uploaded attachment
  26. $this->add_hook('attachment_upload', array($this, 'upload'));
  27. // Save an attachment from a non-upload source (draft or forward)
  28. $this->add_hook('attachment_save', array($this, 'save'));
  29. // Remove an attachment from storage
  30. $this->add_hook('attachment_delete', array($this, 'remove'));
  31. // When composing an html message, image attachments may be shown
  32. $this->add_hook('attachment_display', array($this, 'display'));
  33. // Get the attachment from storage and place it on disk to be sent
  34. $this->add_hook('attachment_get', array($this, 'get'));
  35. // Delete all temp files associated with this user
  36. $this->add_hook('attachments_cleanup', array($this, 'cleanup'));
  37. $this->add_hook('session_destroy', array($this, 'cleanup'));
  38. }
  39. /**
  40. * Save a newly uploaded attachment
  41. */
  42. function upload($args)
  43. {
  44. $args['status'] = false;
  45. $group = $args['group'];
  46. $rcmail = rcube::get_instance();
  47. // use common temp dir for file uploads
  48. $temp_dir = $rcmail->config->get('temp_dir');
  49. $tmpfname = tempnam($temp_dir, 'rcmAttmnt');
  50. if (move_uploaded_file($args['path'], $tmpfname) && file_exists($tmpfname)) {
  51. $args['id'] = $this->file_id();
  52. $args['path'] = $tmpfname;
  53. $args['status'] = true;
  54. @chmod($tmpfname, 0600); // set correct permissions (#1488996)
  55. // Note the file for later cleanup
  56. $_SESSION['plugins']['filesystem_attachments'][$group][$args['id']] = $tmpfname;
  57. }
  58. return $args;
  59. }
  60. /**
  61. * Save an attachment from a non-upload source (draft or forward)
  62. */
  63. function save($args)
  64. {
  65. $group = $args['group'];
  66. $args['status'] = false;
  67. if (!$args['path']) {
  68. $rcmail = rcube::get_instance();
  69. $temp_dir = $rcmail->config->get('temp_dir');
  70. $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
  71. if ($fp = fopen($tmp_path, 'w')) {
  72. fwrite($fp, $args['data']);
  73. fclose($fp);
  74. $args['path'] = $tmp_path;
  75. }
  76. else {
  77. return $args;
  78. }
  79. }
  80. $args['id'] = $this->file_id();
  81. $args['status'] = true;
  82. // Note the file for later cleanup
  83. $_SESSION['plugins']['filesystem_attachments'][$group][$args['id']] = $args['path'];
  84. return $args;
  85. }
  86. /**
  87. * Remove an attachment from storage
  88. * This is triggered by the remove attachment button on the compose screen
  89. */
  90. function remove($args)
  91. {
  92. $args['status'] = @unlink($args['path']);
  93. return $args;
  94. }
  95. /**
  96. * When composing an html message, image attachments may be shown
  97. * For this plugin, the file is already in place, just check for
  98. * the existance of the proper metadata
  99. */
  100. function display($args)
  101. {
  102. $args['status'] = file_exists($args['path']);
  103. return $args;
  104. }
  105. /**
  106. * This attachment plugin doesn't require any steps to put the file
  107. * on disk for use. This stub function is kept here to make this
  108. * class handy as a parent class for other plugins which may need it.
  109. */
  110. function get($args)
  111. {
  112. return $args;
  113. }
  114. /**
  115. * Delete all temp files associated with this user
  116. */
  117. function cleanup($args)
  118. {
  119. // $_SESSION['compose']['attachments'] is not a complete record of
  120. // temporary files because loading a draft or starting a forward copies
  121. // the file to disk, but does not make an entry in that array
  122. if (is_array($_SESSION['plugins']['filesystem_attachments'])) {
  123. foreach ($_SESSION['plugins']['filesystem_attachments'] as $group => $files) {
  124. if ($args['group'] && $args['group'] != $group) {
  125. continue;
  126. }
  127. foreach ((array)$files as $filename) {
  128. if(file_exists($filename)) {
  129. unlink($filename);
  130. }
  131. }
  132. unset($_SESSION['plugins']['filesystem_attachments'][$group]);
  133. }
  134. }
  135. return $args;
  136. }
  137. function file_id()
  138. {
  139. $userid = rcube::get_instance()->user->ID;
  140. list($usec, $sec) = explode(' ', microtime());
  141. $id = preg_replace('/[^0-9]/', '', $userid . $sec . $usec);
  142. // make sure the ID is really unique (#1489546)
  143. while ($this->find_file_by_id($id)) {
  144. // increment last four characters
  145. $x = substr($id, -4) + 1;
  146. $id = substr($id, 0, -4) . sprintf('%04d', ($x > 9999 ? $x - 9999 : $x));
  147. }
  148. return $id;
  149. }
  150. private function find_file_by_id($id)
  151. {
  152. foreach ((array) $_SESSION['plugins']['filesystem_attachments'] as $group => $files) {
  153. if (isset($files[$id])) {
  154. return true;
  155. }
  156. }
  157. }
  158. }