response.php 4.4 KB

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