cakephp2-php8/lib/Cake/View/MediaView.php

246 lines
6.3 KiB
PHP
Raw Normal View History

<?php
/**
* Methods to display or download any type of file
*
2010-10-03 16:38:58 +00:00
* PHP 5
*
2009-11-06 06:46:59 +00:00
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
2010-01-26 19:18:20 +00:00
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
2010-01-26 19:18:20 +00:00
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
2009-11-06 06:00:11 +00:00
* @link http://cakephp.org CakePHP(tm) Project
* @package cake.libs.view
* @since CakePHP(tm) v 1.2.0.5714
2009-11-06 06:51:51 +00:00
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('View', 'View');
App::uses('CakeRequest', 'Network');
/**
* Media View provides a custom view implementation for sending files to visitors. Its great
* for making the response of a controller action be a file that is saved somewhere on the filesystem.
*
* An example use comes from the CakePHP internals. MediaView is used to serve plugin and theme assets,
* as they are not normally accessible from an application's webroot. Unlike other views, MediaView
* uses several viewVars that have special meaning:
*
* - `id` The filename on the server's filesystem, including extension.
* - `name` The filename that will be sent to the user, specified without the extension.
* - `download` Set to true to set a `Content-Disposition` header. This is ideal for file downloads.
* - `extension` The extension of the file being served. This is used to set the mimetype
* - `path` The absolute path, including the trailing / on the server's filesystem to `id`.
* - `mimeType` The mime type of the file if CakeResponse doesn't know about it.
*
* ### Usage
*
* {{{
* class ExampleController extends AppController {
* function download () {
* $this->viewClass = 'Media';
* $params = array(
* 'id' => 'example.zip',
* 'name' => 'example',
* 'download' => true,
* 'extension' => 'zip',
* 'path' => APP . 'files' . DS
* );
* $this->set($params);
* }
* }
* }}}
*
* @package cake.libs.view
*/
class MediaView extends View {
/**
* Indicates whether response gzip compression was enabled for this class
*
* @var boolean
*/
2010-10-04 03:57:22 +00:00
protected $_compressionEnabled = false;
/**
* Reference to the Response object responsible for sending the headers
*
* @var CakeResponse
*/
public $response = null;
/**
* Constructor
*
* @param object $controller The controller with viewVars
*/
public function __construct($controller = null) {
parent::__construct($controller);
if (is_object($controller) && isset($controller->response)) {
$this->response = $controller->response;
} else {
$this->response = new CakeResponse;
}
}
/**
* Display or download the given file
*
* @return mixed
*/
public function render() {
$name = $download = $extension = $id = $modified = $path = $cache = $mimeType = $compress = null;
extract($this->viewVars, EXTR_OVERWRITE);
if (is_dir($path)) {
$path = $path . $id;
} else {
$path = APP . $path . $id;
}
2009-03-19 21:10:13 +00:00
if (!is_file($path)) {
if (Configure::read('debug')) {
throw new NotFoundException(sprintf('The requested file %s was not found', $path));
}
throw new NotFoundException('The requested file was not found');
}
if (is_array($mimeType)) {
$this->response->type($mimeType);
}
2009-03-19 21:10:13 +00:00
if (isset($extension) && $this->_isActive()) {
$extension = strtolower($extension);
$chunkSize = 8192;
$buffer = '';
$fileSize = @filesize($path);
$handle = fopen($path, 'rb');
if ($handle === false) {
return false;
}
if (!empty($modified) && !is_numeric($modified)) {
$modified = strtotime($modified, time());
} else {
$modified = time();
}
if ($this->response->type($extension) === false) {
$download = true;
}
if ($cache) {
$this->response->cache($modified, $cache);
} else {
$this->response->header(array(
'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
'Expires' => '0',
'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0',
'Pragma' => 'no-cache'
));
}
if ($download) {
$agent = env('HTTP_USER_AGENT');
if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent)) {
$contentType = 'application/octetstream';
} else if (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
$contentType = 'application/force-download';
}
if (!empty($contentType)) {
$this->response->type($contentType);
}
if (is_null($name)) {
$name = $id;
}
$this->response->download($name);
$this->response->header(array('Accept-Ranges' => 'bytes'));
$httpRange = env('HTTP_RANGE');
if (isset($httpRange)) {
list($toss, $range) = explode('=', $httpRange);
$size = $fileSize - 1;
$length = $fileSize - $range;
$this->response->header(array(
'Content-Length' => $length,
'Content-Range' => 'bytes ' . $range . $size . '/' . $fileSize
));
2009-03-19 21:10:13 +00:00
$this->response->statusCode(206);
fseek($handle, $range);
} else {
$this->response->header('Content-Length', $fileSize);
}
} else {
$this->response->header(array(
'Content-Length' => $fileSize
));
}
$this->_clearBuffer();
if ($compress) {
2010-10-04 03:57:22 +00:00
$this->_compressionEnabled = $this->response->compress();
}
$this->response->send();
return $this->_sendFile($handle);
}
return false;
}
/**
* Reads out a file handle, and echos the content to the client.
*
* @param resource $handle A file handle or stream
* @return void
*/
protected function _sendFile($handle) {
$chunkSize = 8192;
$buffer = '';
while (!feof($handle)) {
if (!$this->_isActive()) {
fclose($handle);
return false;
2009-03-19 21:10:13 +00:00
}
set_time_limit(0);
$buffer = fread($handle, $chunkSize);
echo $buffer;
2010-10-04 03:57:22 +00:00
if (!$this->_compressionEnabled) {
$this->_flushBuffer();
}
2009-03-19 21:10:13 +00:00
}
fclose($handle);
2009-03-19 21:10:13 +00:00
}
/**
* Returns true if connection is still active
*
* @return boolean
*/
protected function _isActive() {
return connection_status() == 0 && !connection_aborted();
}
/**
* Clears the contents of the topmost output buffer and discards them
*
* @return boolean
*/
protected function _clearBuffer() {
return @ob_end_clean();
}
/**
* Flushes the contents of the output buffer
*
* @return void
*/
protected function _flushBuffer() {
@flush();
@ob_flush();
}
}