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.

response.php 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. /**
  3. * Copyright (c) 2011 Bart Visscher bartv@thisnet.nl
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. class OC_Response {
  9. const STATUS_FOUND = 304;
  10. const STATUS_NOT_MODIFIED = 304;
  11. const STATUS_TEMPORARY_REDIRECT = 307;
  12. const STATUS_NOT_FOUND = 404;
  13. /**
  14. * @brief Enable response caching by sending correct HTTP headers
  15. * @param $cache_time time to cache the response
  16. * >0 cache time in seconds
  17. * 0 and <0 enable default browser caching
  18. * null cache indefinitly
  19. */
  20. static public function enableCaching($cache_time = null) {
  21. if (is_numeric($cache_time)) {
  22. header('Pragma: public');// enable caching in IE
  23. if ($cache_time > 0) {
  24. self::setExpiresHeader('PT'.$cache_time.'S');
  25. header('Cache-Control: max-age='.$cache_time.', must-revalidate');
  26. }
  27. else {
  28. self::setExpiresHeader(0);
  29. header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
  30. }
  31. }
  32. else {
  33. header('Cache-Control: cache');
  34. header('Pragma: cache');
  35. }
  36. }
  37. /**
  38. * @brief disable browser caching
  39. * @see enableCaching with cache_time = 0
  40. */
  41. static public function disableCaching() {
  42. self::enableCaching(0);
  43. }
  44. /**
  45. * @brief Set response status
  46. * @param $status a HTTP status code, see also the STATUS constants
  47. */
  48. static public function setStatus($status) {
  49. $protocol = $_SERVER['SERVER_PROTOCOL'];
  50. switch($status) {
  51. case self::STATUS_NOT_MODIFIED:
  52. $status = $status . ' Not Modified';
  53. break;
  54. case self::STATUS_TEMPORARY_REDIRECT:
  55. if ($protocol == 'HTTP/1.1') {
  56. $status = $status . ' Temporary Redirect';
  57. break;
  58. } else {
  59. $status = self::STATUS_FOUND;
  60. // fallthrough
  61. }
  62. case self::STATUS_FOUND;
  63. $status = $status . ' Found';
  64. break;
  65. case self::STATUS_NOT_FOUND;
  66. $status = $status . ' Not Found';
  67. break;
  68. }
  69. header($protocol.' '.$status);
  70. }
  71. /**
  72. * @brief Send redirect response
  73. * @param $location to redirect to
  74. */
  75. static public function redirect($location) {
  76. self::setStatus(self::STATUS_TEMPORARY_REDIRECT);
  77. header('Location: '.$location);
  78. }
  79. /**
  80. * @brief Set reponse expire time
  81. * @param $expires date-time when the response expires
  82. * string for DateInterval from now
  83. * DateTime object when to expire response
  84. */
  85. static public function setExpiresHeader($expires) {
  86. if (is_string($expires) && $expires[0] == 'P') {
  87. $interval = $expires;
  88. $expires = new DateTime('now');
  89. $expires->add(new DateInterval($interval));
  90. }
  91. if ($expires instanceof DateTime) {
  92. $expires->setTimezone(new DateTimeZone('GMT'));
  93. $expires = $expires->format(DateTime::RFC2822);
  94. }
  95. header('Expires: '.$expires);
  96. }
  97. /**
  98. * Checks and set ETag header, when the request matches sends a
  99. * 'not modified' response
  100. * @param $etag token to use for modification check
  101. */
  102. static public function setETagHeader($etag) {
  103. if (empty($etag)) {
  104. return;
  105. }
  106. $etag = '"'.$etag.'"';
  107. if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
  108. trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
  109. self::setStatus(self::STATUS_NOT_MODIFIED);
  110. exit;
  111. }
  112. header('ETag: '.$etag);
  113. }
  114. /**
  115. * Checks and set Last-Modified header, when the request matches sends a
  116. * 'not modified' response
  117. * @param $lastModified time when the reponse was last modified
  118. */
  119. static public function setLastModifiedHeader($lastModified) {
  120. if (empty($lastModified)) {
  121. return;
  122. }
  123. if (is_int($lastModified)) {
  124. $lastModified = gmdate(DateTime::RFC2822, $lastModified);
  125. }
  126. if ($lastModified instanceof DateTime) {
  127. $lastModified = $lastModified->format(DateTime::RFC2822);
  128. }
  129. if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
  130. trim($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) {
  131. self::setStatus(self::STATUS_NOT_MODIFIED);
  132. exit;
  133. }
  134. header('Last-Modified: '.$lastModified);
  135. }
  136. /**
  137. * @brief Send file as response, checking and setting caching headers
  138. * @param $filepath of file to send
  139. */
  140. static public function sendFile($filepath) {
  141. $fp = fopen($filepath, 'rb');
  142. if ($fp) {
  143. self::setLastModifiedHeader(filemtime($filepath));
  144. self::setETagHeader(md5_file($filepath));
  145. header('Content-Length: '.filesize($filepath));
  146. fpassthru($fp);
  147. }
  148. else {
  149. self::setStatus(self::STATUS_NOT_FOUND);
  150. }
  151. }
  152. }