getfile.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. /**
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2009, StatusNet, Inc.
  5. *
  6. * Return a requested file
  7. *
  8. * PHP version 5
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. * @category PrivateAttachments
  24. * @package StatusNet
  25. * @author Jeffery To <jeffery.to@gmail.com>
  26. * @copyright 2009 StatusNet, Inc.
  27. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  28. * @link http://status.net/
  29. */
  30. if (!defined('GNUSOCIAL')) { exit(1); }
  31. /**
  32. * An action for returning a requested file
  33. *
  34. * The StatusNet system will do an implicit user check if the site is
  35. * private before allowing this to continue
  36. *
  37. * @category PrivateAttachments
  38. * @package StatusNet
  39. * @author Jeffery To <jeffery.to@gmail.com>
  40. * @copyright 2009 StatusNet, Inc.
  41. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  42. * @link http://status.net/
  43. */
  44. class GetfileAction extends Action
  45. {
  46. /**
  47. * Path of file to return
  48. */
  49. var $path = null;
  50. /**
  51. * Get file name
  52. *
  53. * @param array $args $_REQUEST array
  54. *
  55. * @return success flag
  56. */
  57. protected function prepare(array $args=array())
  58. {
  59. parent::prepare($args);
  60. $filename = $this->trimmed('filename');
  61. $path = null;
  62. if ($filename && File::validFilename($filename)) {
  63. $path = File::path($filename);
  64. }
  65. if (empty($path) or !file_exists($path)) {
  66. // TRANS: Client error displayed when requesting a non-existent file.
  67. $this->clientError(_('No such file.'), 404);
  68. }
  69. if (!is_readable($path)) {
  70. // TRANS: Client error displayed when requesting a file without having read access to it.
  71. $this->clientError(_('Cannot read file.'), 403);
  72. }
  73. $this->path = $path;
  74. return true;
  75. }
  76. /**
  77. * Is this page read-only?
  78. *
  79. * @return boolean true
  80. */
  81. function isReadOnly($args)
  82. {
  83. return true;
  84. }
  85. /**
  86. * Last-modified date for file
  87. *
  88. * @return int last-modified date as unix timestamp
  89. */
  90. function lastModified()
  91. {
  92. if (common_config('site', 'use_x_sendfile')) {
  93. return null;
  94. }
  95. return filemtime($this->path);
  96. }
  97. /**
  98. * etag for file
  99. *
  100. * This returns the same data (inode, size, mtime) as Apache would,
  101. * but in decimal instead of hex.
  102. *
  103. * @return string etag http header
  104. */
  105. function etag()
  106. {
  107. if (common_config('site', 'use_x_sendfile')) {
  108. return null;
  109. }
  110. $cache = Cache::instance();
  111. if($cache) {
  112. $key = Cache::key('attachments:etag:' . $this->path);
  113. $etag = $cache->get($key);
  114. if($etag === false) {
  115. $etag = crc32(file_get_contents($this->path));
  116. $cache->set($key,$etag);
  117. }
  118. return $etag;
  119. }
  120. $stat = stat($this->path);
  121. return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
  122. }
  123. /**
  124. * Handle input, produce output
  125. *
  126. * @return void
  127. */
  128. protected function handle()
  129. {
  130. // undo headers set by PHP sessions
  131. $sec = session_cache_expire() * 60;
  132. header('Expires: ' . date(DATE_RFC1123, time() + $sec));
  133. header('Cache-Control: max-age=' . $sec);
  134. parent::handle();
  135. $path = $this->path;
  136. $finfo = new finfo(FILEINFO_MIME_TYPE);
  137. header('Content-Type: ' . $finfo->file($path));
  138. if (common_config('site', 'use_x_sendfile')) {
  139. header('X-Sendfile: ' . $path);
  140. } else {
  141. header('Content-Length: ' . filesize($path));
  142. readfile($path);
  143. }
  144. }
  145. }