Commit 72ff81f7 by Qiang Xue

Web WIP

parent 0657381f
...@@ -308,7 +308,7 @@ class Component extends \yii\base\Object ...@@ -308,7 +308,7 @@ class Component extends \yii\base\Object
* where `$event` is an [[Event]] object which includes parameters associated with the event. * where `$event` is an [[Event]] object which includes parameters associated with the event.
* *
* @param string $name the event name * @param string $name the event name
* @param callback $handler the event handler * @param string|array|\Closure $handler the event handler
* @see off * @see off
*/ */
public function on($name, $handler) public function on($name, $handler)
...@@ -320,7 +320,7 @@ class Component extends \yii\base\Object ...@@ -320,7 +320,7 @@ class Component extends \yii\base\Object
* Detaches an existing event handler. * Detaches an existing event handler.
* This method is the opposite of [[on]]. * This method is the opposite of [[on]].
* @param string $name event name * @param string $name event name
* @param callback $handler the event handler to be removed * @param string|array|\Closure $handler the event handler to be removed
* @return boolean if a handler is found and detached * @return boolean if a handler is found and detached
* @see on * @see on
*/ */
......
...@@ -87,4 +87,51 @@ class FileHelper ...@@ -87,4 +87,51 @@ class FileHelper
$desiredFile = dirname($file) . DIRECTORY_SEPARATOR . $sourceLanguage . DIRECTORY_SEPARATOR . basename($file); $desiredFile = dirname($file) . DIRECTORY_SEPARATOR . $sourceLanguage . DIRECTORY_SEPARATOR . basename($file);
return is_file($desiredFile) ? $desiredFile : $file; return is_file($desiredFile) ? $desiredFile : $file;
} }
/**
* Determines the MIME type of the specified file.
* This method will first try to determine the MIME type based on
* [finfo_open](http://php.net/manual/en/function.finfo-open.php). If this doesn't work, it will
* fall back to [[getMimeTypeByExtension()]].
* @param string $file the file name.
* @param string $magicFile name of the optional magic database file, usually something like `/path/to/magic.mime`.
* This will be passed as the second parameter to [finfo_open](http://php.net/manual/en/function.finfo-open.php).
* @param boolean $checkExtension whether to use the file extension to determine the MIME type in case
* `finfo_open()` cannot determine it.
* @return string the MIME type (e.g. `text/plain`). Null is returned if the MIME type cannot be determined.
*/
public static function getMimeType($file, $magicFile = null, $checkExtension = true)
{
if (function_exists('finfo_open')) {
$info = finfo_open(FILEINFO_MIME_TYPE, $magicFile);
if ($info && ($result = finfo_file($info, $file)) !== false) {
return $result;
}
}
return $checkExtension ? self::getMimeTypeByExtension($file) : null;
}
/**
* Determines the MIME type based on the extension name of the specified file.
* This method will use a local map between extension names and MIME types.
* @param string $file the file name.
* @param string $magicFile the path of the file that contains all available MIME type information.
* If this is not set, the default file aliased by `@yii/util/mimeTypes.php` will be used.
* @return string the MIME type. Null is returned if the MIME type cannot be determined.
*/
public static function getMimeTypeByExtension($file, $magicFile = null)
{
if ($magicFile === null) {
$magicFile = \Yii::getAlias('@yii/util/mimeTypes.php');
}
$mimeTypes = require($magicFile);
if (($ext = pathinfo($file, PATHINFO_EXTENSION)) !== '') {
$ext = strtolower($ext);
if (isset($mimeTypes[$ext])) {
return $mimeTypes[$ext];
}
}
return null;
}
} }
<?php
/**
* MIME types.
*
* This file contains most commonly used MIME types
* according to file extension names.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
return array(
'ai' => 'application/postscript',
'aif' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'anx' => 'application/annodex',
'asc' => 'text/plain',
'au' => 'audio/basic',
'avi' => 'video/x-msvideo',
'axa' => 'audio/annodex',
'axv' => 'video/annodex',
'bcpio' => 'application/x-bcpio',
'bin' => 'application/octet-stream',
'bmp' => 'image/bmp',
'c' => 'text/plain',
'cc' => 'text/plain',
'ccad' => 'application/clariscad',
'cdf' => 'application/x-netcdf',
'class' => 'application/octet-stream',
'cpio' => 'application/x-cpio',
'cpt' => 'application/mac-compactpro',
'csh' => 'application/x-csh',
'css' => 'text/css',
'dcr' => 'application/x-director',
'dir' => 'application/x-director',
'dms' => 'application/octet-stream',
'doc' => 'application/msword',
'drw' => 'application/drafting',
'dvi' => 'application/x-dvi',
'dwg' => 'application/acad',
'dxf' => 'application/dxf',
'dxr' => 'application/x-director',
'eps' => 'application/postscript',
'etx' => 'text/x-setext',
'exe' => 'application/octet-stream',
'ez' => 'application/andrew-inset',
'f' => 'text/plain',
'f90' => 'text/plain',
'flac' => 'audio/flac',
'fli' => 'video/x-fli',
'flv' => 'video/x-flv',
'gif' => 'image/gif',
'gtar' => 'application/x-gtar',
'gz' => 'application/x-gzip',
'h' => 'text/plain',
'hdf' => 'application/x-hdf',
'hh' => 'text/plain',
'hqx' => 'application/mac-binhex40',
'htm' => 'text/html',
'html' => 'text/html',
'ice' => 'x-conference/x-cooltalk',
'ief' => 'image/ief',
'iges' => 'model/iges',
'igs' => 'model/iges',
'ips' => 'application/x-ipscript',
'ipx' => 'application/x-ipix',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'js' => 'application/x-javascript',
'kar' => 'audio/midi',
'latex' => 'application/x-latex',
'lha' => 'application/octet-stream',
'lsp' => 'application/x-lisp',
'lzh' => 'application/octet-stream',
'm' => 'text/plain',
'man' => 'application/x-troff-man',
'me' => 'application/x-troff-me',
'mesh' => 'model/mesh',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mif' => 'application/vnd.mif',
'mime' => 'www/mime',
'mov' => 'video/quicktime',
'movie' => 'video/x-sgi-movie',
'mp2' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'mpe' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpga' => 'audio/mpeg',
'ms' => 'application/x-troff-ms',
'msh' => 'model/mesh',
'nc' => 'application/x-netcdf',
'oga' => 'audio/ogg',
'ogg' => 'audio/ogg',
'ogv' => 'video/ogg',
'ogx' => 'application/ogg',
'oda' => 'application/oda',
'pbm' => 'image/x-portable-bitmap',
'pdb' => 'chemical/x-pdb',
'pdf' => 'application/pdf',
'pgm' => 'image/x-portable-graymap',
'pgn' => 'application/x-chess-pgn',
'png' => 'image/png',
'pnm' => 'image/x-portable-anymap',
'pot' => 'application/mspowerpoint',
'ppm' => 'image/x-portable-pixmap',
'pps' => 'application/mspowerpoint',
'ppt' => 'application/mspowerpoint',
'ppz' => 'application/mspowerpoint',
'pre' => 'application/x-freelance',
'prt' => 'application/pro_eng',
'ps' => 'application/postscript',
'qt' => 'video/quicktime',
'ra' => 'audio/x-realaudio',
'ram' => 'audio/x-pn-realaudio',
'ras' => 'image/cmu-raster',
'rgb' => 'image/x-rgb',
'rm' => 'audio/x-pn-realaudio',
'roff' => 'application/x-troff',
'rpm' => 'audio/x-pn-realaudio-plugin',
'rtf' => 'text/rtf',
'rtx' => 'text/richtext',
'scm' => 'application/x-lotusscreencam',
'set' => 'application/set',
'sgm' => 'text/sgml',
'sgml' => 'text/sgml',
'sh' => 'application/x-sh',
'shar' => 'application/x-shar',
'silo' => 'model/mesh',
'sit' => 'application/x-stuffit',
'skd' => 'application/x-koan',
'skm' => 'application/x-koan',
'skp' => 'application/x-koan',
'skt' => 'application/x-koan',
'smi' => 'application/smil',
'smil' => 'application/smil',
'snd' => 'audio/basic',
'sol' => 'application/solids',
'spl' => 'application/x-futuresplash',
'spx' => 'audio/ogg',
'src' => 'application/x-wais-source',
'step' => 'application/STEP',
'stl' => 'application/SLA',
'stp' => 'application/STEP',
'sv4cpio' => 'application/x-sv4cpio',
'sv4crc' => 'application/x-sv4crc',
'swf' => 'application/x-shockwave-flash',
't' => 'application/x-troff',
'tar' => 'application/x-tar',
'tcl' => 'application/x-tcl',
'tex' => 'application/x-tex',
'texi' => 'application/x-texinfo',
'texinfo' => 'application/x-texinfo',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'tr' => 'application/x-troff',
'tsi' => 'audio/TSP-audio',
'tsp' => 'application/dsptype',
'tsv' => 'text/tab-separated-values',
'txt' => 'text/plain',
'unv' => 'application/i-deas',
'ustar' => 'application/x-ustar',
'vcd' => 'application/x-cdlink',
'vda' => 'application/vda',
'viv' => 'video/vnd.vivo',
'vivo' => 'video/vnd.vivo',
'vrml' => 'model/vrml',
'wav' => 'audio/x-wav',
'wrl' => 'model/vrml',
'xbm' => 'image/x-xbitmap',
'xlc' => 'application/vnd.ms-excel',
'xll' => 'application/vnd.ms-excel',
'xlm' => 'application/vnd.ms-excel',
'xls' => 'application/vnd.ms-excel',
'xlw' => 'application/vnd.ms-excel',
'xml' => 'application/xml',
'xpm' => 'image/x-xpixmap',
'xspf' => 'application/xspf+xml',
'xwd' => 'image/x-xwindowdump',
'xyz' => 'chemical/x-pdb',
'zip' => 'application/zip',
);
<?php <?php
/** /**
* CHttpCookie class file. * Cookie class file.
* *
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/ * @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC * @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/ * @license http://www.yiiframework.com/license/
*/ */
/** /**
* A CHttpCookie instance stores a single cookie, including the cookie name, value, domain, path, expire, and secure. * Cookie represents information related with a cookie, such as [[name]], [[value]], [[domain]], etc.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$ * @since 2.0
* @package system.web
* @since 1.0
*/ */
class CHttpCookie extends CComponent class Cookie extends \yii\base\Object
{ {
/** /**
* @var string name of the cookie * @var string name of the cookie
...@@ -25,39 +22,41 @@ class CHttpCookie extends CComponent ...@@ -25,39 +22,41 @@ class CHttpCookie extends CComponent
/** /**
* @var string value of the cookie * @var string value of the cookie
*/ */
public $value=''; public $value = '';
/** /**
* @var string domain of the cookie * @var string domain of the cookie
*/ */
public $domain=''; public $domain = '';
/** /**
* @var integer the timestamp at which the cookie expires. This is the server timestamp. Defaults to 0, meaning "until the browser is closed". * @var integer the timestamp at which the cookie expires. This is the server timestamp.
* Defaults to 0, meaning "until the browser is closed".
*/ */
public $expire=0; public $expire = 0;
/** /**
* @var string the path on the server in which the cookie will be available on. The default is '/'. * @var string the path on the server in which the cookie will be available on. The default is '/'.
*/ */
public $path='/'; public $path = '/';
/** /**
* @var boolean whether cookie should be sent via secure connection * @var boolean whether cookie should be sent via secure connection
*/ */
public $secure=false; public $secure = false;
/** /**
* @var boolean whether the cookie should be accessible only through the HTTP protocol. * @var boolean whether the cookie should be accessible only through the HTTP protocol.
* By setting this property to true, the cookie will not be accessible by scripting languages, * By setting this property to true, the cookie will not be accessible by scripting languages,
* such as JavaScript, which can effectly help to reduce identity theft through XSS attacks. * such as JavaScript, which can effectively help to reduce identity theft through XSS attacks.
* Note, this property is only effective for PHP 5.2.0 or above.
*/ */
public $httpOnly=false; public $httpOnly = false;
/** /**
* Constructor. * Constructor.
* @param string $name name of this cookie * @param string $name name of this cookie
* @param string $value value of this cookie * @param string $value value of this cookie
* @param array $config name-value pairs that will be used to initialize the object properties
*/ */
public function __construct($name,$value) public function __construct($name, $value, $config = array())
{ {
$this->name=$name; $this->name = $name;
$this->value=$value; $this->value = $value;
parent::__construct($config);
} }
} }
...@@ -70,16 +70,16 @@ class CPagination extends CComponent ...@@ -70,16 +70,16 @@ class CPagination extends CComponent
/** /**
* The default page size. * The default page size.
*/ */
const DEFAULT_PAGE_SIZE=10; const DEFAULT_PAGE_SIZE = 10;
/** /**
* @var string name of the GET variable storing the current page index. Defaults to 'page'. * @var string name of the GET variable storing the current page index. Defaults to 'page'.
*/ */
public $pageVar='page'; public $pageVar = 'page';
/** /**
* @var string the route (controller ID and action ID) for displaying the paged contents. * @var string the route (controller ID and action ID) for displaying the paged contents.
* Defaults to empty string, meaning using the current route. * Defaults to empty string, meaning using the current route.
*/ */
public $route=''; public $route = '';
/** /**
* @var array of parameters (name=>value) that should be used instead of GET when generating pagination URLs. * @var array of parameters (name=>value) that should be used instead of GET when generating pagination URLs.
* Defaults to null, meaning using the currently available GET parameters. * Defaults to null, meaning using the currently available GET parameters.
...@@ -95,17 +95,17 @@ class CPagination extends CComponent ...@@ -95,17 +95,17 @@ class CPagination extends CComponent
* Defaults to true. * Defaults to true.
* @since 1.1.4 * @since 1.1.4
*/ */
public $validateCurrentPage=true; public $validateCurrentPage = true;
private $_pageSize=self::DEFAULT_PAGE_SIZE; private $_pageSize = self::DEFAULT_PAGE_SIZE;
private $_itemCount=0; private $_itemCount = 0;
private $_currentPage; private $_currentPage;
/** /**
* Constructor. * Constructor.
* @param integer $itemCount total number of items. * @param integer $itemCount total number of items.
*/ */
public function __construct($itemCount=0) public function __construct($itemCount = 0)
{ {
$this->setItemCount($itemCount); $this->setItemCount($itemCount);
} }
...@@ -123,8 +123,9 @@ class CPagination extends CComponent ...@@ -123,8 +123,9 @@ class CPagination extends CComponent
*/ */
public function setPageSize($value) public function setPageSize($value)
{ {
if(($this->_pageSize=$value)<=0) if (($this->_pageSize = $value) <= 0) {
$this->_pageSize=self::DEFAULT_PAGE_SIZE; $this->_pageSize = self::DEFAULT_PAGE_SIZE;
}
} }
/** /**
...@@ -140,8 +141,9 @@ class CPagination extends CComponent ...@@ -140,8 +141,9 @@ class CPagination extends CComponent
*/ */
public function setItemCount($value) public function setItemCount($value)
{ {
if(($this->_itemCount=$value)<0) if (($this->_itemCount = $value) < 0) {
$this->_itemCount=0; $this->_itemCount = 0;
}
} }
/** /**
...@@ -149,31 +151,30 @@ class CPagination extends CComponent ...@@ -149,31 +151,30 @@ class CPagination extends CComponent
*/ */
public function getPageCount() public function getPageCount()
{ {
return (int)(($this->_itemCount+$this->_pageSize-1)/$this->_pageSize); return (int)(($this->_itemCount + $this->_pageSize - 1) / $this->_pageSize);
} }
/** /**
* @param boolean $recalculate whether to recalculate the current page based on the page size and item count. * @param boolean $recalculate whether to recalculate the current page based on the page size and item count.
* @return integer the zero-based index of the current page. Defaults to 0. * @return integer the zero-based index of the current page. Defaults to 0.
*/ */
public function getCurrentPage($recalculate=true) public function getCurrentPage($recalculate = true)
{ {
if($this->_currentPage===null || $recalculate) if ($this->_currentPage === null || $recalculate) {
{ if (isset($_GET[$this->pageVar])) {
if(isset($_GET[$this->pageVar])) $this->_currentPage = (int)$_GET[$this->pageVar] - 1;
{ if ($this->validateCurrentPage) {
$this->_currentPage=(int)$_GET[$this->pageVar]-1; $pageCount = $this->getPageCount();
if($this->validateCurrentPage) if ($this->_currentPage >= $pageCount) {
{ $this->_currentPage = $pageCount - 1;
$pageCount=$this->getPageCount(); }
if($this->_currentPage>=$pageCount)
$this->_currentPage=$pageCount-1;
} }
if($this->_currentPage<0) if ($this->_currentPage < 0) {
$this->_currentPage=0; $this->_currentPage = 0;
}
} else {
$this->_currentPage = 0;
} }
else
$this->_currentPage=0;
} }
return $this->_currentPage; return $this->_currentPage;
} }
...@@ -183,8 +184,8 @@ class CPagination extends CComponent ...@@ -183,8 +184,8 @@ class CPagination extends CComponent
*/ */
public function setCurrentPage($value) public function setCurrentPage($value)
{ {
$this->_currentPage=$value; $this->_currentPage = $value;
$_GET[$this->pageVar]=$value+1; $_GET[$this->pageVar] = $value + 1;
} }
/** /**
...@@ -198,14 +199,16 @@ class CPagination extends CComponent ...@@ -198,14 +199,16 @@ class CPagination extends CComponent
* @param integer $page the page that the URL should point to. This is a zero-based index. * @param integer $page the page that the URL should point to. This is a zero-based index.
* @return string the created URL * @return string the created URL
*/ */
public function createPageUrl($controller,$page) public function createPageUrl($controller, $page)
{ {
$params=$this->params===null ? $_GET : $this->params; $params = $this->params === null ? $_GET : $this->params;
if($page>0) // page 0 is the default if ($page > 0) // page 0 is the default
$params[$this->pageVar]=$page+1; {
else $params[$this->pageVar] = $page + 1;
} else {
unset($params[$this->pageVar]); unset($params[$this->pageVar]);
return $controller->createUrl($this->route,$params); }
return $controller->createUrl($this->route, $params);
} }
/** /**
...@@ -214,8 +217,8 @@ class CPagination extends CComponent ...@@ -214,8 +217,8 @@ class CPagination extends CComponent
*/ */
public function applyLimit($criteria) public function applyLimit($criteria)
{ {
$criteria->limit=$this->getLimit(); $criteria->limit = $this->getLimit();
$criteria->offset=$this->getOffset(); $criteria->offset = $this->getOffset();
} }
/** /**
...@@ -225,7 +228,7 @@ class CPagination extends CComponent ...@@ -225,7 +228,7 @@ class CPagination extends CComponent
*/ */
public function getOffset() public function getOffset()
{ {
return $this->getCurrentPage()*$this->getPageSize(); return $this->getCurrentPage() * $this->getPageSize();
} }
/** /**
......
<?php
/**
* Response class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\util\FileHelper;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Response extends \yii\base\Response
{
/**
* Sends a file to user.
* @param string $fileName file name
* @param string $content content to be set.
* @param string $mimeType mime type of the content. If null, it will be guessed automatically based on the given file name.
* @param boolean $terminate whether to terminate the current application after calling this method
* @todo
*/
public function sendFile($fileName, $content, $mimeType = null, $terminate = true)
{
if ($mimeType === null && ($mimeType = FileHelper::getMimeType($fileName)) === null) {
$mimeType = 'application/octet-stream';
}
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: $mimeType");
if (ob_get_length() === false) {
header('Content-Length: ' . (function_exists('mb_strlen') ? mb_strlen($content, '8bit') : strlen($content)));
}
header("Content-Disposition: attachment; filename=\"$fileName\"");
header('Content-Transfer-Encoding: binary');
if ($terminate) {
// clean up the application first because the file downloading could take long time
// which may cause timeout of some resources (such as DB connection)
Yii::app()->end(0, false);
echo $content;
exit(0);
} else {
echo $content;
}
}
/**
* Sends existing file to a browser as a download using x-sendfile.
*
* X-Sendfile is a feature allowing a web application to redirect the request for a file to the webserver
* that in turn processes the request, this way eliminating the need to perform tasks like reading the file
* and sending it to the user. When dealing with a lot of files (or very big files) this can lead to a great
* increase in performance as the web application is allowed to terminate earlier while the webserver is
* handling the request.
*
* The request is sent to the server through a special non-standard HTTP-header.
* When the web server encounters the presence of such header it will discard all output and send the file
* specified by that header using web server internals including all optimizations like caching-headers.
*
* As this header directive is non-standard different directives exists for different web servers applications:
* <ul>
* <li>Apache: {@link http://tn123.org/mod_xsendfile X-Sendfile}</li>
* <li>Lighttpd v1.4: {@link http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file X-LIGHTTPD-send-file}</li>
* <li>Lighttpd v1.5: {@link http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file X-Sendfile}</li>
* <li>Nginx: {@link http://wiki.nginx.org/XSendfile X-Accel-Redirect}</li>
* <li>Cherokee: {@link http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile X-Sendfile and X-Accel-Redirect}</li>
* </ul>
* So for this method to work the X-SENDFILE option/module should be enabled by the web server and
* a proper xHeader should be sent.
*
* <b>Note:</b>
* This option allows to download files that are not under web folders, and even files that are otherwise protected (deny from all) like .htaccess
*
* <b>Side effects</b>:
* If this option is disabled by the web server, when this method is called a download configuration dialog
* will open but the downloaded file will have 0 bytes.
*
* <b>Example</b>:
* <pre>
* <?php
* Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg',array(
* 'saveName'=>'image1.jpg',
* 'mimeType'=>'image/jpeg',
* 'terminate'=>false,
* ));
* ?>
* </pre>
* @param string $filePath file name with full path
* @param array $options additional options:
* <ul>
* <li>saveName: file name shown to the user, if not set real file name will be used</li>
* <li>mimeType: mime type of the file, if not set it will be guessed automatically based on the file name, if set to null no content-type header will be sent.</li>
* <li>xHeader: appropriate x-sendfile header, defaults to "X-Sendfile"</li>
* <li>terminate: whether to terminate the current application after calling this method, defaults to true</li>
* <li>forceDownload: specifies whether the file will be downloaded or shown inline, defaults to true. (Since version 1.1.9.)</li>
* <li>addHeaders: an array of additional http headers in header-value pairs (available since version 1.1.10)</li>
* </ul>
* @todo
*/
public function xSendFile($filePath, $options = array())
{
if (!isset($options['forceDownload']) || $options['forceDownload']) {
$disposition = 'attachment';
} else {
$disposition = 'inline';
}
if (!isset($options['saveName'])) {
$options['saveName'] = basename($filePath);
}
if (!isset($options['mimeType'])) {
if (($options['mimeType'] = CFileHelper::getMimeTypeByExtension($filePath)) === null) {
$options['mimeType'] = 'text/plain';
}
}
if (!isset($options['xHeader'])) {
$options['xHeader'] = 'X-Sendfile';
}
if ($options['mimeType'] !== null) {
header('Content-type: ' . $options['mimeType']);
}
header('Content-Disposition: ' . $disposition . '; filename="' . $options['saveName'] . '"');
if (isset($options['addHeaders'])) {
foreach ($options['addHeaders'] as $header => $value) {
header($header . ': ' . $value);
}
}
header(trim($options['xHeader']) . ': ' . $filePath);
if (!isset($options['terminate']) || $options['terminate']) {
Yii::app()->end();
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment