diff --git a/.gitignore b/.gitignore index 187adb2..1991e63 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -/nbproject/ \ No newline at end of file +/nbproject/ +/vendor +/.idea +/composer.lock \ No newline at end of file diff --git a/FileDownloader/AppFileDownload.php b/FileDownloader/AppFileDownload.php index f1560b9..7d56657 100644 --- a/FileDownloader/AppFileDownload.php +++ b/FileDownloader/AppFileDownload.php @@ -39,11 +39,11 @@ namespace FileDownloader; -use Nette\Application\IResponse as IResponse2; -use Nette\Application\UI\Presenter; -use Nette\ComponentModel\Component; use Nette\Http\IRequest; use Nette\Http\IResponse; +use Nette\Http\Request; +use Nette\Http\Response; +use Nette\Http\Session; /** * @link http://filedownloader.projekty.mujserver.net @@ -51,15 +51,8 @@ * @author Jan Kuchař * @copyright Copyright (c) 2014 Jan Kuchar * @author Jan Kuchař - * - * @property Component $parent Parent component */ -class AppFileDownload extends BaseFileDownload implements IResponse2 { - /** - * Parent of this object - * @var Component - */ - private $parent; +class AppFileDownload extends BaseFileDownload implements \Nette\Application\IResponse { /** * Downloader used to download file (optional) @@ -68,63 +61,38 @@ class AppFileDownload extends BaseFileDownload implements IResponse2 { private $downloader; /** - * Getts new instance of self - * @param Component $parent - * @return AppFileDownload + * @var Request */ - public static function getInstance(Component $parent) { - return new AppFileDownload($parent); - } + private $request; /** - * @param Component $parent + * @var Response */ - function __construct(Component $parent) { - parent::__construct(); - $this->setParent($parent); - } + private $response; /** - * Setts AppFileDownload parent - * @param Component $parent - * @return AppFileDownload + * @var Session */ - function setParent(Component $parent) { - $this->parent = $parent; - return $this; - } + private $session; - /** - * Getts AppFileDownload parent - * @return Component - */ - function getParent() { - return $this->parent; - } - - /** - * Implementation of IPresenterResponse::send() - */ - function send(IRequest $httpRequest, IResponse $httpResponse) { - parent::download($this->downloader); + public function __construct(Request $request, Response $response, Session $session) { + parent::__construct(); + $this->request = $request; + $this->response = $response; + $this->session = $session; } - /** - * Start download of the file! - * @param IDownloader $downloader - */ - function download(IDownloader $downloader = null) { + public function setDownloader(IDownloader $downloader) { $this->downloader = $downloader; + } - // Call sendResponse on presenter (used since 2.0 instead of terminate) - if($this->parent instanceof Presenter) { - $presenter = $this->parent; - } else { - $presenter = $this->parent->lookup("Nette/Application/UI/Presenter",true); - } - - $presenter->sendResponse($this); + /* Implementation of IPresenterResponse::send() */ + public function send(IRequest $httpRequest, IResponse $httpResponse) { + parent::download($this->downloader, $this->request, $this->response, $this->session); + } + public function download(IDownloader $downloader = null, Request $request, Response $response, Session $session) { + throw new \LogicException('Use Presenter::sendResponse() to send response to client.'); } } diff --git a/FileDownloader/BaseFileDownload.php b/FileDownloader/BaseFileDownload.php index 17d1ed0..3f5c379 100644 --- a/FileDownloader/BaseFileDownload.php +++ b/FileDownloader/BaseFileDownload.php @@ -43,7 +43,9 @@ use FileDownloader\Downloader\AdvancedDownloader; use FileDownloader\Downloader\NativePHPDownloader; use Nette\Application\BadRequestException; -use Nette\Environment; +use Nette\Http\Request; +use Nette\Http\Response; +use Nette\Http\Session; use Nette\InvalidArgumentException; use Nette\InvalidStateException; use Nette\Object; @@ -75,6 +77,17 @@ * @property int $contentDisposition Content disposition: inline or attachment * @property-read float $sourceFileSize File size * @property-read int $transferID TransferId + * + * Callbacks: + * @method void onBeforeDownloaderStarts(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onBeforeOutputStarts(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onStatusChange(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onComplete(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onTransferContinue(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onNewTransferStart(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onAbort(BaseFileDownload $fileDownload, IDownloader $downloader) + * @method void onConnectionLost(BaseFileDownload $fileDownload, IDownloader $downloader) + */ abstract class BaseFileDownload extends Object { /** @@ -89,12 +102,6 @@ abstract class BaseFileDownload extends Object { */ private static $fileDownloaders=array(); - /** - * Close session before start download? (if not, it will block session until file is transferred!) - * @var bool - */ - public static $closeSession = true; - /** * Add file downlaoder * Order is priority (last added will be used first) @@ -134,8 +141,8 @@ public static function clearFileDownloaders() { */ private $vTransferID = -1; - const CONTENT_DISPOSITION_ATTACHMENT = "attachment"; - const CONTENT_DISPOSITION_INLINE = "inline"; + const CONTENT_DISPOSITION_ATTACHMENT = 'attachment'; + const CONTENT_DISPOSITION_INLINE = 'inline'; /** * Content disposition: attachment / inline @@ -195,7 +202,7 @@ public static function clearFileDownloaders() { * @param callback $callback Callback * @return BaseFileDownload */ - function addBeforeDownloaderStartsCallback($callback) { + public function addBeforeDownloaderStartsCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -213,7 +220,7 @@ function addBeforeDownloaderStartsCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addBeforeOutputStartsCallback($callback) { + public function addBeforeOutputStartsCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -231,7 +238,7 @@ function addBeforeOutputStartsCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addStatusChangeCallback($callback) { + public function addStatusChangeCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -248,7 +255,7 @@ function addStatusChangeCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addCompleteCallback($callback) { + public function addCompleteCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -268,7 +275,7 @@ function addCompleteCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addTransferContinueCallback($callback) { + public function addTransferContinueCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -287,7 +294,7 @@ function addTransferContinueCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addNewTransferStartCallback($callback) { + public function addNewTransferStartCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -305,7 +312,7 @@ function addNewTransferStartCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addAbortCallback($callback) { + public function addAbortCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -323,7 +330,7 @@ function addAbortCallback($callback) { * @param callback $callback Callback * @return BaseFileDownload */ - function addConnectionLostCallback($callback) { + public function addConnectionLostCallback($callback) { return $this->addCallback(__METHOD__, $callback); } @@ -334,15 +341,15 @@ function addConnectionLostCallback($callback) { * @return BaseFileDownload */ private function addCallback($fceName, $callback) { - preg_match("/^.*::add(.*)Callback$/", $fceName, $matches); - $varName = "on".$matches[1]; + preg_match('/^.*::add(.*)Callback$/', $fceName, $matches); + $varName = 'on' .$matches[1]; $var = &$this->$varName; $var[] = $callback; return $this; } - function __construct() { - $this->vTransferID = time()."-".rand(); + public function __construct() { + $this->vTransferID = time(). '-' .mt_rand(); foreach(self::$defaults AS $key => $val) { $this->$key = $val; } @@ -361,7 +368,7 @@ public function getTransferId() { * @param string $location Location of the source file * @return BaseFileDownload */ - function setSourceFile($location) { + public function setSourceFile($location) { if($location === null) { $this->vSourceFile = null; }else { @@ -369,7 +376,7 @@ function setSourceFile($location) { throw new BadRequestException("File not found at '" . $location . "'!"); } if (!is_readable($location)) { - throw new InvalidStateException("File is NOT readable!"); + throw new InvalidStateException('File is NOT readable!'); } $this->transferFileName = pathinfo($location, PATHINFO_BASENAME); $this->vSourceFile = realpath($location); @@ -379,11 +386,11 @@ function setSourceFile($location) { /** * Getts location of the source file - * @return BaseFileDownload + * @return string */ - function getSourceFile() { + public function getSourceFile() { if ($this->vSourceFile === null) { - throw new InvalidStateException("Location is not set!"); + throw new InvalidStateException('Location is not set!'); } return $this->vSourceFile; } @@ -393,10 +400,10 @@ function getSourceFile() { * @param string $disposition * @return BaseFileDownload */ - function setContentDisposition($disposition) { - $values = array("inline","attachment"); - if (!in_array($disposition, $values)) { - throw new InvalidArgumentException("Content disposition must be one of these: " . implode(",", $values)); + public function setContentDisposition($disposition) { + $values = array('inline', 'attachment'); + if (!in_array($disposition, $values, TRUE)) { + throw new InvalidArgumentException('Content disposition must be one of these: ' . implode(',', $values)); } $this->vContentDisposition = $disposition; return $this; @@ -406,7 +413,7 @@ function setContentDisposition($disposition) { * Getts content disposition * @return string */ - function getContentDisposition() { + public function getContentDisposition() { return $this->vContentDisposition; } @@ -414,7 +421,7 @@ function getContentDisposition() { * Getts send as name * @return string */ - function getTransferFileName() { + public function getTransferFileName() { return $this->vTransferFileName; } @@ -423,7 +430,7 @@ function getTransferFileName() { * @param string $sendAs * @return BaseFileDownload */ - function setTransferFileName($name) { + public function setTransferFileName($name) { $this->vTransferFileName = pathinfo($name, PATHINFO_BASENAME); return $this; } @@ -434,9 +441,9 @@ function setTransferFileName($name) { * @param int $speed Speed limit * @return BaseFileDownload */ - function setSpeedLimit($speed) { + public function setSpeedLimit($speed) { if (!is_int($speed)) { - throw new InvalidArgumentException("Max download speed must be integer!"); + throw new InvalidArgumentException('Max download speed must be integer!'); } if ($speed < 0) { throw new InvalidArgumentException("Max download speed can't be smaller than zero!"); @@ -445,7 +452,7 @@ function setSpeedLimit($speed) { if ($availableMem) { $availableMemWithReserve = ($availableMem-100*1024); if ($speed > $availableMemWithReserve) { - throw new InvalidArgumentException("Max download speed can't be a bigger than available memory " . $availableMemWithReserve . "b!"); + throw new InvalidArgumentException("Max download speed can't be a bigger than available memory " . $availableMemWithReserve . 'b!'); } } $this->vSpeedLimit = (int)round($speed); @@ -456,7 +463,7 @@ function setSpeedLimit($speed) { * Getts speed limit * @return int */ - function getSpeedLimit() { + public function getSpeedLimit() { return $this->vSpeedLimit; } @@ -472,7 +479,7 @@ public function getMimeType() { } $mime = ""; - if (extension_loaded('fileinfo') and function_exists("finfo_open")) { + if (extension_loaded('fileinfo') && function_exists('finfo_open')) { //TODO: test this code: if ($finfo = @finfo_open(FILEINFO_MIME)) { $mime = @finfo_file($finfo, $this->sourceFile); @@ -483,7 +490,7 @@ public function getMimeType() { } } - if(function_exists("mime_content_type")) { + if(function_exists('mime_content_type')) { $mime = mime_content_type($this->sourceFile); if (FDTools::isValidMimeType($mime)) { return $mime; @@ -491,21 +498,17 @@ public function getMimeType() { } // By file extension from ini file - $cache = Environment::getCache("FileDownloader"); - if (!IsSet($cache["mime-types"])) { - $cache["mime-types"] = parse_ini_file(dirname(__FILE__) . DIRECTORY_SEPARATOR . "mime.ini"); - } - $mimetypes = $cache["mime-types"]; + $mimeTypes = parse_ini_file(__DIR__ . DIRECTORY_SEPARATOR . 'mime.ini'); $extension = pathinfo($this->sourceFile, PATHINFO_EXTENSION); - if (array_key_exists($extension, $mimetypes)) { - $mime = $mimetypes[$extension]; + if (array_key_exists($extension, $mimeTypes)) { + $mime = $mimeTypes[$extension]; } if (FDTools::isValidMimeType($mime)) { return $mime; } else { - return "application/octet-stream"; + return 'application/octet-stream'; } } @@ -527,35 +530,35 @@ public function getSourceFileSize() { return FDTools::filesize($this->sourceFile); } + /** * Download the file! * @param IDownloader $downloader + * @param Request $request HTTP request + * @param Response $response HTTP response + * @param Session $session HTTP Session (this is needed to be able to close it + * @throws Exception */ - function download(IDownloader $downloader = null) { - $req = Environment::getHttpRequest(); - $res = Environment::getHttpResponse(); + public function download(IDownloader $inputDownloader = null, Request $request, Response $response, Session $session) { - if(self::$closeSession) { - $ses = Environment::getSession(); - if($ses->isStarted()) { - $ses->close(); - } + if($session->isStarted()) { + $session->close(); } - if($this->getContentDisposition() == "inline" AND is_null($this->enableBrowserCache)) { + if($this->enableBrowserCache === NULL && $this->getContentDisposition() === 'inline') { $this->enableBrowserCache = true; }else{ $this->enableBrowserCache = false; } - if ($downloader === null) { + if ($inputDownloader === null) { $downloaders = self::getFileDownloaders(); } else { - $downloaders = array($downloader); + $downloaders = array($inputDownloader); } if (count($downloaders) <= 0) { - throw new InvalidStateException("There is no registred downloader!"); + throw new InvalidStateException('There is no registred downloader!'); } krsort($downloaders); @@ -563,23 +566,23 @@ function download(IDownloader $downloader = null) { $lastException = null; foreach($downloaders AS $downloader) { - if($downloader instanceof IDownloader and $downloader->isCompatible($this)) { + if($downloader instanceof IDownloader && $downloader->isCompatible($this)) { try { - FDTools::clearHeaders($res); // Delete all headers + FDTools::clearHeaders($response); // Delete all headers $this->transferredBytes = 0; $this->onBeforeDownloaderStarts($this,$downloader); - $downloader->download($this); // Start download + $downloader->download($request, $response, $this); // Start download $this->onComplete($this,$downloader); die(); // If all gone ok -> die } catch (FDSkypeMeException $e) { - if($res->isSent()) { + if($response->isSent()) { throw new InvalidStateException("Headers are already sent! Can't skip downloader."); } else { continue; } } catch (Exception $e) { - if(!$res->isSent()) - FDTools::clearHeaders($res); + if(!$response->isSent()) + FDTools::clearHeaders($response); throw $e; } } @@ -587,15 +590,15 @@ function download(IDownloader $downloader = null) { // Pokud se soubor nějakým způsobem odešle - toto už se nespustí if($lastException instanceof Exception) { - FDTools::clearHeaders(Environment::getHttpResponse(),TRUE); + FDTools::clearHeaders($response,TRUE); throw $lastException; } - if($req->getHeader("Range")) - FDTools::_HTTPError(416); // Požadavek na range + if($request->getHeader('Range')) + FDTools::_HTTPError($response, 416); // Požadavek na range else - $res->setCode(500); - throw new InvalidStateException("There is no compatible downloader (all downloader returns downloader->isComplatible()=false or was skipped)!"); + $response->setCode(500); + throw new InvalidStateException('There is no compatible downloader (all downloader returns downloader->isComplatible()=false or was skipped)!'); } } diff --git a/FileDownloader/Downloader/AdvancedDownloader.php b/FileDownloader/Downloader/AdvancedDownloader.php index d9bb417..c0e152f 100644 --- a/FileDownloader/Downloader/AdvancedDownloader.php +++ b/FileDownloader/Downloader/AdvancedDownloader.php @@ -46,7 +46,8 @@ use FileDownloader\BaseFileDownload; use FileDownloader\FDTools; use FileDownloader\FileDownloaderException; -use Nette\Environment; +use Nette\Http\Request; +use Nette\Http\Response; use Nette\InvalidArgumentException; use Nette\InvalidStateException; @@ -63,7 +64,7 @@ class AdvancedDownloader extends BaseDownloader { * Check for environment configuration? * @var bool */ - static $checkEnvironmentSettings = true; + public static $checkEnvironmentSettings = true; public $size = 0; public $start = 0; @@ -85,19 +86,12 @@ class AdvancedDownloader extends BaseDownloader { */ protected $sleep; - /** - * Download file! - * @param BaseFileDownload $file - */ - function download(BaseFileDownload $transfer) { + public function download(Request $request, Response $response, BaseFileDownload $transfer) { $this->currentTransfer = $transfer; - $this->sendStandardFileHeaders($transfer,$this); + $this->sendStandardFileHeaders($request, $response, $transfer,$this); @ignore_user_abort(true); // For onAbort event - $req = Environment::getHttpRequest(); - $res = Environment::getHttpResponse(); - $filesize = $this->size = $transfer->sourceFileSize; $this->length = $this->size; // Content-length $this->start = 0; @@ -119,17 +113,17 @@ function download(BaseFileDownload $transfer) { */ //$res->setHeader("Accept-Ranges", "0-".$this->end); // single-part - now not accepted by mozilla - $res->setHeader("Accept-Ranges", "bytes"); // multi-part (through Mozilla) + $response->setHeader('Accept-Ranges', 'bytes'); // multi-part (through Mozilla) // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - if ($req->getHeader("Range", false)) // If partial download + if ($request->getHeader('Range', false)) // If partial download { try { $range_start = $this->start; $range_end = $this->end; // Extract the range string - $rangeArray = explode('=', $req->getHeader("Range"), 2); + $rangeArray = explode('=', $request->getHeader('Range'), 2); $range = $rangeArray[1]; // Make sure the client hasn't sent us a multibyte range @@ -137,13 +131,13 @@ function download(BaseFileDownload $transfer) { // (?) Shoud this be issued here, or should the first // range be used? Or should the header be ignored and // we output the whole content? - throw new FileDownloaderException("HTTP 416",416); + throw new FileDownloaderException('HTTP 416',416); } // If the range starts with an '-' we start from the beginning // If not, we forward the file pointer // And make sure to get the end byte if spesified - if ($range{0} == '-') { + if ($range{0} === '-') { // The n-number of the last bytes is requested $range_start = $this->size - (float)substr($range, 1); } @@ -161,7 +155,7 @@ function download(BaseFileDownload $transfer) { $range_end = ($range_end > $this->end) ? $this->end : $range_end; // Validate the requested range and return an error if it's not correct. if ($range_start > $range_end || $range_start > $this->size - 1 || $range_end >= $this->size) { - throw new FileDownloaderException("HTTP 416",416); + throw new FileDownloaderException('HTTP 416',416); } // All is ok - so assign variables back @@ -170,18 +164,18 @@ function download(BaseFileDownload $transfer) { $this->length = $this->end - $this->start + 1; // Calculate new content length } catch (FileDownloaderException $e) { if ($e->getCode() === 416) { - $res->setHeader("Content-Range", "bytes $this->start-$this->end/$this->size"); - FDTools::_HTTPError(416); + $response->setHeader('Content-Range', "bytes $this->start-$this->end/$this->size"); + FDTools::_HTTPError($response, 416); } else { throw $e; } } - $res->setCode(206); // Partial content + $response->setCode(206); // Partial content } // End of if partial download // Notify the client the byte range we'll be outputting - $res->setHeader("Content-Range","bytes $this->start-$this->end/$this->size"); - $res->setHeader("Content-Length",$this->length); + $response->setHeader('Content-Range',"bytes $this->start-$this->end/$this->size"); + $response->setHeader('Content-Length',$this->length); /* ### Call callbacks ### */ @@ -196,24 +190,24 @@ function download(BaseFileDownload $transfer) { $buffer = FDTools::$readFileBuffer; $sleep = false; - if(is_int($transfer->speedLimit) and $transfer->speedLimit>0) { + if(is_int($transfer->speedLimit) && $transfer->speedLimit>0) { $sleep = true; $buffer = (int)round($transfer->speedLimit); } $this->sleep = $sleep; if ($buffer < 1) { - throw new InvalidArgumentException("Buffer must be bigger than zero!"); + throw new InvalidArgumentException('Buffer must be bigger than zero!'); } $availableMem = FDTools::getAvailableMemory(); if ($availableMem && $buffer > ($availableMem - memory_get_usage())) { - throw new InvalidArgumentException("Buffer is too big! (bigger than available memory)"); + throw new InvalidArgumentException('Buffer is too big! (bigger than available memory)'); } $this->buffer = $buffer; - $fp = fopen($transfer->sourceFile,"rb"); + $fp = fopen($transfer->sourceFile, 'rb'); // TODO: Add flock() READ if (!$fp) { throw new InvalidStateException("Can't open file for reading!"); @@ -248,7 +242,7 @@ function download(BaseFileDownload $transfer) { $this->position = $this->start; } - $this->processNative($fp,$sleep); + $this->processNative($fp); $this->cleanAfterTransfer(); } @@ -282,19 +276,21 @@ protected function processNative($fp) { } protected function processByCUrl() { - if(function_exists("curl_init")) { // Curl available + if(function_exists('curl_init')) { // Curl available $transfer = $this->currentTransfer; - $ch = curl_init("file://" . realpath($transfer->sourceFile)); + $ch = curl_init('file://' . realpath($transfer->sourceFile)); $range = $this->start.'-'.$this->end; // HTTP range curl_setopt($ch, CURLOPT_RANGE, $range); curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); curl_setopt($ch, CURLOPT_BUFFERSIZE, $this->buffer); - curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this,"_curlProcessBlock")); + curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this, + '_curlProcessBlock' + )); $curlRet = curl_exec($ch); if($curlRet === false) { - throw new Exception("cUrl error number ".curl_errno($ch).": ".curl_error($ch)); + throw new Exception('cUrl error number ' .curl_errno($ch). ': ' .curl_error($ch)); } return true; }else{ @@ -332,7 +328,7 @@ protected function _afterBufferSent($tmpTime, $fp=null) { flush(); // PHP: Do not buffer it - send it to browser! @ob_flush(); - if(connection_status()!=CONNECTION_NORMAL) { + if(connection_status() !== CONNECTION_NORMAL) { if ($fp) { fclose($fp); } @@ -342,14 +338,14 @@ protected function _afterBufferSent($tmpTime, $fp=null) { } die(); } - if($this->sleep==true OR $tmpTime<=time()) { + if($this->sleep === true || $tmpTime<=time()) { $transfer->transferredBytes = $this->transferred = $this->position-$this->start; $transfer->onStatusChange($transfer,$this); - if (IsSet($tmpTime)) { + if ($tmpTime !== NULL) { $tmpTime = time() + 1; } } - if ($this->sleep == true) { + if ($this->sleep === true) { sleep(1); } } @@ -358,8 +354,8 @@ protected function _afterBufferSent($tmpTime, $fp=null) { * Is this downloader initialized? * @return bool */ - function isInitialized() { - if ($this->end == 0) { + public function isInitialized() { + if ($this->end === 0) { return false; } return true; @@ -371,7 +367,7 @@ function isInitialized() { * @param BaseFileDownload $file * @return bool TRUE if is compatible; FALSE if not */ - function isCompatible(BaseFileDownload $file) { + public function isCompatible(BaseFileDownload $file) { if(self::$checkEnvironmentSettings === true) { if (FDTools::setTimeLimit(0) !== true) { return false; diff --git a/FileDownloader/Downloader/BaseDownloader.php b/FileDownloader/Downloader/BaseDownloader.php index 916eb98..69633f4 100644 --- a/FileDownloader/Downloader/BaseDownloader.php +++ b/FileDownloader/Downloader/BaseDownloader.php @@ -41,7 +41,7 @@ use FileDownloader\BaseFileDownload; use FileDownloader\FDTools; use FileDownloader\IDownloader; -use Nette\Environment; +use Nette\Http\Request; use Nette\Http\Response; use Nette\Object; @@ -54,54 +54,51 @@ * @author Jan Kuchař */ abstract class BaseDownloader extends Object implements IDownloader { - /** * Sends a standard headers for file download - * @param BaseFileDownload $file File - * @param BaseDownloader $downloader Downloader of the file + * @param Request $request + * @param Response $rCesponse + * @param BaseFileDownload $file File + * @param BaseDownloader $downloader Downloader of the file */ - protected function sendStandardFileHeaders(BaseFileDownload $file, BaseDownloader $downloader=null) { - $res = Environment::getHttpResponse(); - $req = Environment::getHttpRequest(); + protected function sendStandardFileHeaders(Request $request, Response $response, BaseFileDownload $file, BaseDownloader $downloader=null) { //FDTools::clearHeaders($res); // Voláno už v FileDownload.php - $res->setContentType($file->mimeType, "UTF-8"); - $res->setHeader("X-File-Downloader", "File Downloader (http://filedownloader.projekty.mujserver.net)"); + $response->setContentType($file->mimeType, 'UTF-8'); + $response->setHeader('X-File-Downloader', 'File Downloader (http://filedownloader.projekty.mujserver.net)'); if ($downloader !== null) { - $res->setHeader("X-FileDownloader-Actual-Script", $downloader->getReflection()->name); + $response->setHeader('X-FileDownloader-Actual-Script', $downloader->getReflection()->name); } - $res->setHeader('Pragma', 'public'); // Fix for IE - Content-Disposition - $res->setHeader('Content-Disposition', $file->getContentDisposition() . '; filename="' . FDTools::getContentDispositionHeaderData($file->transferFileName) . '"'); - $res->setHeader('Content-Description', 'File Transfer'); - $res->setHeader('Content-Transfer-Encoding', 'binary'); - $res->setHeader('Connection', 'close'); - $res->setHeader('ETag', FDTools::getETag($file->sourceFile)); - $res->setHeader('Content-Length', FDTools::filesize($file->sourceFile)); + $response->setHeader('Pragma', 'public'); // Fix for IE - Content-Disposition + $response->setHeader('Content-Disposition', $file->getContentDisposition() . '; filename="' . FDTools::getContentDispositionHeaderData($request, $file->transferFileName) . '"'); + $response->setHeader('Content-Description', 'File Transfer'); + $response->setHeader('Content-Transfer-Encoding', 'binary'); + $response->setHeader('Connection', 'close'); + $response->setHeader('ETag', FDTools::getETag($file->sourceFile)); + $response->setHeader('Content-Length', FDTools::filesize($file->sourceFile)); // Cache control if ($file->enableBrowserCache) { - $this->setupCacheHeaders($file); + $this->setupCacheHeaders($response, $file); } else { - $this->setupNonCacheHeaders($file); + $this->setupNonCacheHeaders($response, $file); } } - protected function setupCacheHeaders(BaseFileDownload $file) { - $res = Environment::getHttpResponse(); - $res->setExpiration(time() + 99999999); - $res->setHeader('Last-Modified', "Mon, 23 Jan 1978 10:00:00 GMT"); - if (!empty($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { - $res->setCode(Response::S304_NOT_MODIFIED); + protected function setupCacheHeaders(Response $response, BaseFileDownload $file) { + $response->setExpiration(time() + 99999999); + $response->setHeader('Last-Modified', 'Mon, 23 Jan 1978 10:00:00 GMT'); + if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + $response->setCode(Response::S304_NOT_MODIFIED); //header("HTTP/1.1 304 Not Modified"); exit(); }; } - protected function setupNonCacheHeaders(BaseFileDownload $file) { - $res = Environment::getHttpResponse(); - $res->setHeader('Expires', '0'); - $res->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0'); + protected function setupNonCacheHeaders(Response $response, BaseFileDownload $file) { + $response->setHeader('Expires', '0'); + $response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0'); } } diff --git a/FileDownloader/Downloader/NativePHPDownloader.php b/FileDownloader/Downloader/NativePHPDownloader.php index c680ce7..749f0a8 100644 --- a/FileDownloader/Downloader/NativePHPDownloader.php +++ b/FileDownloader/Downloader/NativePHPDownloader.php @@ -40,6 +40,8 @@ namespace FileDownloader\Downloader; use FileDownloader\BaseFileDownload; +use Nette\Http\Request; +use Nette\Http\Response; use Nette\InvalidStateException; /** @@ -56,17 +58,17 @@ class NativePHPDownloader extends BaseDownloader { * Download file! * @param BaseFileDownload $file */ - function download(BaseFileDownload $file) { - $this->sendStandardFileHeaders($file,$this); - $file->onBeforeOutputStarts($file,$this); + public function download(Request $request, Response $response, BaseFileDownload $file) { + $this->sendStandardFileHeaders($request, $response, $file, $this); + $file->onBeforeOutputStarts($file, $this); // Bugfix: when output buffer active, there is a problem with memory // @see http://www.php.net/manual/en/function.readfile.php#81032 - while (@ob_end_flush()); // @see example at http://php.net/manual/en/function.ob-end-flush.php + while (@ob_end_flush()) {}; // @see example at http://php.net/manual/en/function.ob-end-flush.php flush(); if(!@readfile($file->sourceFile)) { - throw new InvalidStateException("PHP readfile() function fails!"); } + throw new InvalidStateException('PHP readfile() function fails!'); } // Or use this code? (from http://www.php.net/manual/en/function.readfile.php#50212) // @@ -81,7 +83,7 @@ function download(BaseFileDownload $file) { * @param bool $isLast Is this last downloader in list? * @return bool TRUE if is compatible; FALSE if not */ - function isCompatible(BaseFileDownload $file) { + public function isCompatible(BaseFileDownload $file) { return true; } } diff --git a/FileDownloader/FDTools.php b/FileDownloader/FDTools.php index 6d9f828..a887fd0 100644 --- a/FileDownloader/FDTools.php +++ b/FileDownloader/FDTools.php @@ -39,8 +39,9 @@ namespace FileDownloader; use BigFileTools; -use Nette\Environment; use Nette\Http\IResponse; +use Nette\Http\Request; +use Nette\Http\Response; use Nette\InvalidArgumentException; use Nette\InvalidStateException; use Nette\Object; @@ -70,9 +71,9 @@ class FDTools extends Object { * Returns available memery in bytes or NULL when no limit it set * @return int|null */ - static function getAvailableMemory() { - $mem = self::parsePHPIniMemoryValue(ini_get("memory_limit")); - if ($mem == 0) { + public static function getAvailableMemory() { + $mem = self::parsePHPIniMemoryValue(ini_get('memory_limit')); + if ($mem === 0) { return null; } return $mem-memory_get_usage(); @@ -83,23 +84,23 @@ static function getAvailableMemory() { * @param string $phpIniValueStr * @return int */ - static function parsePHPIniMemoryValue($phpIniValueStr) { + public static function parsePHPIniMemoryValue($phpIniValueStr) { $phpIniValueInt = (int)$phpIniValueStr; if ($phpIniValueInt <= 0) { return 0; } - switch (substr($phpIniValueStr, -1, 1)) { - case "K": + switch ($phpIniValueStr[strlen($phpIniValueStr) - 1]) { + case 'K': $phpIniValueInt *= self::KILOBYTE; break; - case "M": + case 'M': $phpIniValueInt *= self::MEGABYTE; ; break; - case "G": + case 'G': $phpIniValueInt *= self::GYGABYTE; break; - case "T": + case 'T': $phpIniValueInt *= self::TERABYTE; break; default: @@ -113,13 +114,13 @@ static function parsePHPIniMemoryValue($phpIniValueStr) { * @param IResponse $res * @return IResponse */ - static function clearHeaders(IResponse $res,$setContentType=false) { + public static function clearHeaders(IResponse $res, $setContentType=false) { $res->setCode(IResponse::S200_OK); foreach($res->getHeaders() AS $key => $val) { $res->setHeader($key, null); } if ($setContentType === true) { - $res->setContentType("text/html", "UTF-8"); + $res->setContentType('text/html', 'UTF-8'); } return $res; } @@ -129,22 +130,22 @@ static function clearHeaders(IResponse $res,$setContentType=false) { * @param int $time Time limit * @return bool */ - static function setTimeLimit($time=0) { - if (!function_exists("ini_get")) { - throw new InvalidStateException("Function ini_get must be allowed."); + public static function setTimeLimit($time=0) { + if (!function_exists('ini_get')) { + throw new InvalidStateException('Function ini_get must be allowed.'); } - if ((int) @ini_get("max_execution_time") === $time) { + if ((int) @ini_get('max_execution_time') === $time) { return true; } - if (function_exists("set_time_limit")) { + if (function_exists('set_time_limit')) { @set_time_limit($time); - } elseif (function_exists("ini_set")) { - @ini_set("max_execution_time", $time); + } elseif (function_exists('ini_set')) { + @ini_set('max_execution_time', $time); } - if ((int) @ini_get("max_execution_time") === $time) { + if ((int) @ini_get('max_execution_time') === $time) { return true; } @@ -157,49 +158,51 @@ static function setTimeLimit($time=0) { * @param string $location Location to source file * @return string ETag */ - static function getETag($location) { - return "\"" . md5($location . filemtime($location) . self::filesize($location)) . "\""; + public static function getETag($location) { + return '"' . md5($location . filemtime($location) . self::filesize($location)) . '"'; } + /** * Returns filename (but if IE fix the bug) * * @link http://cz2.php.net/manual/en/function.fpassthru.php#25801 * @author Unknown + * @param Request $request HTTP request * @param string $basename Path to file or filename * @return string */ - static function getContentDispositionHeaderData($basename) { + public static function getContentDispositionHeaderData(Request $request, $basename) { $basename = basename($basename); - $req = Environment::getHttpRequest(); - $userAgent = $req->getHeader("User-Agent"); - if ($userAgent AND strstr($userAgent, "MSIE")) { + $userAgent = $request->getHeader('User-Agent'); + if ($userAgent && strstr($userAgent, 'MSIE')) { // workaround for IE filename bug with multiple periods / multiple dots in filename // that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe $iefilename = preg_replace('/\./', '%2e', $basename, substr_count($basename, '.') - 1); - $basename = rawurlencode($basename); // Czech chars in filename + $basename = rawurlencode($iefilename); // Czech chars in filename } return $basename; } + /** * Sends http error to client * * @author Jan Kuchař - * @param int $code HTTP code + * @param Response $response + * @param int $code HTTP code * @param string $message HTTP status */ - static function _HTTPError($code,$message=null) { + public static function _HTTPError(Response $response, $code, $message=null) { $errors = array( - 416=>"Requested Range not satisfiable" + 416=> 'Requested Range not satisfiable' ); - if ($message === null and isset($errors[$code])) { + if ($message === null && isset($errors[$code])) { $message = $errors[$code]; } - $res = Environment::getHttpResponse(); - $res->setCode($code); - $res->setContentType("plain/text","UTF-8"); - die("
".$message."
"); + $response->setCode($code); + $response->setContentType('plain/text', 'UTF-8'); + die('' .$message. '
'); } /** @@ -207,7 +210,7 @@ static function _HTTPError($code,$message=null) { * @param string $mime Mime-type * @return bool */ - static function isValidMimeType($mime) { + public static function isValidMimeType($mime) { $mime = (string)$mime; // Thanks to Matúš Matula: http://forum.nette.org/cs/1952-addon-file-downloader-file-downloader?p=2#p61785 // return preg_match('#^[-\w]+/[-\w\+]+$#i', $mime); // simple check @@ -240,19 +243,19 @@ static function isValidMimeType($mime) { public static function readFile($location,$start=0,$end=null,$speedLimit=0) { $buffer = self::$readFileBuffer; $sleep = false; - if(is_int($speedLimit) and $speedLimit>0) { + if(is_int($speedLimit) && $speedLimit>0) { $sleep = true; $buffer = (int)round($speedLimit); } if ($buffer < 1) { - throw new InvalidArgumentException("Buffer must be bigger than zero!"); + throw new InvalidArgumentException('Buffer must be bigger than zero!'); } $availableMem = self::getAvailableMemory(); if ($availableMem && $buffer > ($availableMem * 0.9)) { - throw new InvalidArgumentException("Buffer is too big! (bigger than available memory)"); + throw new InvalidArgumentException('Buffer is too big! (bigger than available memory)'); } - $fp = fopen($location,"rb"); + $fp = fopen($location, 'rb'); if (!$fp) { throw new InvalidStateException("Can't open file for reading!"); } @@ -268,7 +271,7 @@ public static function readFile($location,$start=0,$end=null,$speedLimit=0) { } echo fread($fp, $buffer); flush(); - if ($sleep == true) { + if ($sleep === true) { sleep(1); } } diff --git a/FileDownloader/IDownloader.php b/FileDownloader/IDownloader.php index 14b450a..f6113a4 100644 --- a/FileDownloader/IDownloader.php +++ b/FileDownloader/IDownloader.php @@ -37,6 +37,8 @@ */ namespace FileDownloader; +use Nette\Http\Request; +use Nette\Http\Response; /** * @@ -49,16 +51,19 @@ interface IDownloader { /** * Download file! - * @param FileDownload $file + * @param Request $request HTTP request + * @param Response $response HTTP response + * @param BaseFileDownload|FileDownload $file */ - function download(BaseFileDownload $file); + public function download(Request $request, Response $response, BaseFileDownload $file); + /** * Is this downloader compatible? - * @param FileDownload $file + * @param BaseFileDownload|FileDownload $file * @return bool TRUE if is compatible; FALSE if not */ - function isCompatible(BaseFileDownload $file); + public function isCompatible(BaseFileDownload $file); } diff --git a/composer.json b/composer.json index 007ef3b..f36ab55 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ }, "require": { "php": ">= 5.3.0", - "nette/application": "~2.2", - "jkuchar/bigfiletools": "~1.1" + "nette/application": "~2.4", + "nette/deprecated": "^2.4", + "jkuchar/bigfiletools": "~1.1" } }