PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Cake/View/MediaView.php

https://bitbucket.org/udeshika/fake_twitter
PHP | 249 lines | 129 code | 24 blank | 96 comment | 32 complexity | 16bfb118395a31fd60191771a5f34a52 MD5 | raw file
  1. <?php
  2. /**
  3. * Methods to display or download any type of file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package Cake.View
  16. * @since CakePHP(tm) v 1.2.0.5714
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. App::uses('View', 'View');
  20. App::uses('CakeRequest', 'Network');
  21. /**
  22. * Media View provides a custom view implementation for sending files to visitors. Its great
  23. * for making the response of a controller action be a file that is saved somewhere on the filesystem.
  24. *
  25. * An example use comes from the CakePHP internals. MediaView is used to serve plugin and theme assets,
  26. * as they are not normally accessible from an application's webroot. Unlike other views, MediaView
  27. * uses several viewVars that have special meaning:
  28. *
  29. * - `id` The filename on the server's filesystem, including extension.
  30. * - `name` The filename that will be sent to the user, specified without the extension.
  31. * - `download` Set to true to set a `Content-Disposition` header. This is ideal for file downloads.
  32. * - `extension` The extension of the file being served. This is used to set the mimetype
  33. * - `path` The absolute path, including the trailing / on the server's filesystem to `id`.
  34. * - `mimeType` The mime type of the file if CakeResponse doesn't know about it.
  35. *
  36. * ### Usage
  37. *
  38. * {{{
  39. * class ExampleController extends AppController {
  40. * public function download () {
  41. * $this->viewClass = 'Media';
  42. * $params = array(
  43. * 'id' => 'example.zip',
  44. * 'name' => 'example',
  45. * 'download' => true,
  46. * 'extension' => 'zip',
  47. * 'path' => APP . 'files' . DS
  48. * );
  49. * $this->set($params);
  50. * }
  51. * }
  52. * }}}
  53. *
  54. * @package Cake.View
  55. */
  56. class MediaView extends View {
  57. /**
  58. * Indicates whether response gzip compression was enabled for this class
  59. *
  60. * @var boolean
  61. */
  62. protected $_compressionEnabled = false;
  63. /**
  64. * Reference to the Response object responsible for sending the headers
  65. *
  66. * @var CakeResponse
  67. */
  68. public $response = null;
  69. /**
  70. * Constructor
  71. *
  72. * @param Controller $controller The controller with viewVars
  73. */
  74. public function __construct($controller = null) {
  75. parent::__construct($controller);
  76. if (is_object($controller) && isset($controller->response)) {
  77. $this->response = $controller->response;
  78. } else {
  79. $this->response = new CakeResponse;
  80. }
  81. }
  82. /**
  83. * Display or download the given file
  84. *
  85. * @param string $view Not used
  86. * @param string $layout Not used
  87. * @return mixed
  88. * @throws NotFoundException
  89. */
  90. public function render($view = null, $layout = null) {
  91. $name = $download = $extension = $id = $modified = $path = $cache = $mimeType = $compress = null;
  92. extract($this->viewVars, EXTR_OVERWRITE);
  93. if (is_dir($path)) {
  94. $path = $path . $id;
  95. } else {
  96. $path = APP . $path . $id;
  97. }
  98. if (!is_file($path)) {
  99. if (Configure::read('debug')) {
  100. throw new NotFoundException(sprintf('The requested file %s was not found', $path));
  101. }
  102. throw new NotFoundException('The requested file was not found');
  103. }
  104. if (is_array($mimeType)) {
  105. $this->response->type($mimeType);
  106. }
  107. if (isset($extension) && $this->_isActive()) {
  108. $extension = strtolower($extension);
  109. $chunkSize = 8192;
  110. $buffer = '';
  111. $fileSize = @filesize($path);
  112. $handle = fopen($path, 'rb');
  113. if ($handle === false) {
  114. return false;
  115. }
  116. if (!empty($modified) && !is_numeric($modified)) {
  117. $modified = strtotime($modified, time());
  118. } else {
  119. $modified = time();
  120. }
  121. if ($this->response->type($extension) === false) {
  122. $download = true;
  123. }
  124. if ($cache) {
  125. $this->response->cache($modified, $cache);
  126. } else {
  127. $this->response->header(array(
  128. 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
  129. 'Expires' => '0',
  130. 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0',
  131. 'Pragma' => 'no-cache'
  132. ));
  133. }
  134. if ($download) {
  135. $agent = env('HTTP_USER_AGENT');
  136. if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent)) {
  137. $contentType = 'application/octetstream';
  138. } else if (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
  139. $contentType = 'application/force-download';
  140. }
  141. if (!empty($contentType)) {
  142. $this->response->type($contentType);
  143. }
  144. if (is_null($name)) {
  145. $name = $id;
  146. }
  147. $this->response->download($name);
  148. $this->response->header(array('Accept-Ranges' => 'bytes'));
  149. $httpRange = env('HTTP_RANGE');
  150. if (isset($httpRange)) {
  151. list($toss, $range) = explode('=', $httpRange);
  152. $size = $fileSize - 1;
  153. $length = $fileSize - $range;
  154. $this->response->header(array(
  155. 'Content-Length' => $length,
  156. 'Content-Range' => 'bytes ' . $range . $size . '/' . $fileSize
  157. ));
  158. $this->response->statusCode(206);
  159. fseek($handle, $range);
  160. } else {
  161. $this->response->header('Content-Length', $fileSize);
  162. }
  163. } else {
  164. $this->response->header(array(
  165. 'Content-Length' => $fileSize
  166. ));
  167. }
  168. $this->_clearBuffer();
  169. if ($compress) {
  170. $this->_compressionEnabled = $this->response->compress();
  171. }
  172. $this->response->send();
  173. return $this->_sendFile($handle);
  174. }
  175. return false;
  176. }
  177. /**
  178. * Reads out a file handle, and echos the content to the client.
  179. *
  180. * @param resource $handle A file handle or stream
  181. * @return void
  182. */
  183. protected function _sendFile($handle) {
  184. $chunkSize = 8192;
  185. $buffer = '';
  186. while (!feof($handle)) {
  187. if (!$this->_isActive()) {
  188. fclose($handle);
  189. return false;
  190. }
  191. set_time_limit(0);
  192. $buffer = fread($handle, $chunkSize);
  193. echo $buffer;
  194. if (!$this->_compressionEnabled) {
  195. $this->_flushBuffer();
  196. }
  197. }
  198. fclose($handle);
  199. }
  200. /**
  201. * Returns true if connection is still active
  202. *
  203. * @return boolean
  204. */
  205. protected function _isActive() {
  206. return connection_status() == 0 && !connection_aborted();
  207. }
  208. /**
  209. * Clears the contents of the topmost output buffer and discards them
  210. *
  211. * @return boolean
  212. */
  213. protected function _clearBuffer() {
  214. return @ob_end_clean();
  215. }
  216. /**
  217. * Flushes the contents of the output buffer
  218. *
  219. * @return void
  220. */
  221. protected function _flushBuffer() {
  222. @flush();
  223. @ob_flush();
  224. }
  225. }