|  |  | @ -275,141 +275,68 @@ class Response extends \yii\base\Response | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/** |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * Sends a file to user. |  |  |  | 	 * Sends a file to the browser. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @param string $fileName file name |  |  |  | 	 * @param string $filePath the path of the file to be sent. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @param string $content content to be set. |  |  |  | 	 * @param string $mimeType the MIME type of the content. If null, it will be guessed based on `$filePath` | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @param string $mimeType mime type of the content. If null, it will be guessed automatically based on the given file name. |  |  |  | 	 * @param string $attachmentName the file name shown to the user. If null, it will be determined from `$filePath`. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @param boolean $terminate whether to terminate the current application after calling this method |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @throws HttpException when range request is not satisfiable. |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	 */ |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	public function sendFile($fileName, $content, $mimeType = null, $terminate = true) |  |  |  | 	public function sendFile($filePath, $mimeType = null, $attachmentName = null) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	{ |  |  |  | 	{ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if ($mimeType === null && (($mimeType = FileHelper::getMimeTypeByExtension($fileName)) === null)) { |  |  |  | 		if ($mimeType === null && ($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			$mimeType = 'application/octet-stream'; |  |  |  | 			$mimeType = 'application/octet-stream'; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 		if ($attachmentName === null) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$fileSize = StringHelper::strlen($content); |  |  |  | 			$attachmentName = basename($filePath); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$contentStart = 0; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$contentEnd = $fileSize - 1; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers = $this->getHeaders(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		// tell the client that we accept range requests |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers->set('Accept-Ranges', 'bytes'); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (isset($_SERVER['HTTP_RANGE'])) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// client sent us a multibyte range, can not hold this one for now |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				throw new HttpException(416, 'Requested Range Not Satisfiable'); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// range requests starts from "-", so it means that data must be dumped the end point. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if ($range[0] === '-') { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$contentStart = $fileSize - substr($range, 1); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$range = explode('-', $range); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$contentStart = $range[0]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				// check if the last-byte-pos presents in header |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if ((isset($range[1]) && is_numeric($range[1]))) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 					$contentEnd = $range[1]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			/* Check the range and make sure it's treated according to the specs. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			 */ |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// End bytes can not be larger than $end. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$contentEnd = ($contentEnd > $fileSize) ? $fileSize - 1 : $contentEnd; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// Validate the requested range and return an error if it's not correct. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$wrongContentStart = ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if ($wrongContentStart) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				throw new HttpException(416, 'Requested Range Not Satisfiable'); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$this->setStatusCode(206); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$this->setStatusCode(200); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		$handle = fopen($filePath, 'rb'); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		$this->sendStreamAsFile($handle, $mimeType, $attachmentName); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$length = $contentEnd - $contentStart + 1; // Calculate new content length |  |  |  | 	/** | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 	 * Sends the specified content as a file to the browser. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers->set('Pragma', 'public') |  |  |  | 	 * @param string $content the content to be sent. The existing [[content]] will be discarded. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Expires', '0') |  |  |  | 	 * @param string $mimeType the MIME type of the content. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') |  |  |  | 	 * @param string $attachmentName the file name shown to the user. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Type', $mimeType) |  |  |  | 	 */ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Length', $length) |  |  |  | 	public function sendContentAsFile($content, $mimeType = 'application/octet-stream', $attachmentName = 'file') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Disposition', "attachment; filename=\"$fileName\"") |  |  |  | 	{ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Transfer-Encoding', 'binary'); |  |  |  | 		$this->getHeaders() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 			->addDefault('Pragma', 'public') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$content = StringHelper::substr($content, $contentStart, $length); |  |  |  | 			->addDefault('Accept-Ranges', 'bytes') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 			->addDefault('Expires', '0') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		if ($terminate) { |  |  |  | 			->addDefault('Content-Type', $mimeType) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			// clean up the application first because the file downloading could take long time |  |  |  | 			->addDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			// which may cause timeout of some resources (such as DB connection) |  |  |  | 			->addDefault('Content-Transfer-Encoding', 'binary') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			ob_start(); |  |  |  | 			->addDefault('Content-Length', StringHelper::strlen($content)) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			Yii::$app->end(0, false); |  |  |  | 			->addDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			ob_end_clean(); |  |  |  | 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			$this->content = $content; |  |  |  | 		$this->content = $content; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			exit(0); |  |  |  | 		$this->send(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		} else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$this->content = $content; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	public function sendStream($handle, $options = array()) |  |  |  | 	/** | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * Sends the specified stream as a file to the browser. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @param resource $handle the handle of the stream to be sent. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @param string $mimeType the MIME type of the stream content. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @param string $attachmentName the file name shown to the user. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @throws HttpException if the requested range cannot be satisfied. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	public function sendStreamAsFile($handle, $mimeType = 'application/octet-stream', $attachmentName = 'file') | 
			
		
	
		
		
			
				
					
					|  |  |  | 	{ |  |  |  | 	{ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		$headers = $this->getHeaders(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		fseek($handle, 0, SEEK_END); |  |  |  | 		fseek($handle, 0, SEEK_END); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$fileSize = ftell($handle); |  |  |  | 		$fileSize = ftell($handle); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$contentStart = 0; |  |  |  | 		$range = $this->getHttpRange($fileSize); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$contentEnd = $fileSize - 1; |  |  |  | 		if ($range === false) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 			$headers->set('Content-Range', "bytes */$fileSize"); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers = $this->getHeaders(); |  |  |  | 			throw new HttpException(416, Yii::t('yii', 'Requested range not satisfiable')); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 		} | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		if (isset($_SERVER['HTTP_RANGE'])) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// client sent us a multibyte range, can not hold this one for now |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				throw new HttpException(416, Yii::t('yii', 'Requested range not satisfiable')); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// range requests starts from "-", so it means that data must be dumped the end point. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if ($range[0] === '-') { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$contentStart = $fileSize - substr($range, 1); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$range = explode('-', $range); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$contentStart = $range[0]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				// check if the last-byte-pos presents in header |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if ((isset($range[1]) && is_numeric($range[1]))) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 					$contentEnd = $range[1]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			/* Check the range and make sure it's treated according to the specs. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			 */ |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// End bytes can not be larger than $end. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$contentEnd = $contentEnd > $fileSize ? $fileSize - 1 : $contentEnd; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// Validate the requested range and return an error if it's not correct. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				throw new HttpException(416, Yii::t('yii', 'Requested range not satisfiable')); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		list($begin, $end) = $range; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if ($begin !=0 || $end != $fileSize - 1) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$this->setStatusCode(206); |  |  |  | 			$this->setStatusCode(206); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize"); |  |  |  | 			$headers->set('Content-Range', "bytes $begin-$end/$fileSize"); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		} else { |  |  |  | 		} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$this->setStatusCode(200); |  |  |  | 			$this->setStatusCode(200); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -418,42 +345,66 @@ class Response extends \yii\base\Response | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$headers->set('Content-Type', $options['mimeType']); |  |  |  | 			$headers->set('Content-Type', $options['mimeType']); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$length = $contentEnd - $contentStart + 1; |  |  |  | 		$length = $end - $begin + 1; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$disposition = empty($options['disposition']) ? 'attachment' : $options['disposition']; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (!isset($options['saveName'])) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$options['saveName'] = 'data'; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers->set('Pragma', 'public') |  |  |  | 		$headers->addDefault('Pragma', 'public') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Expires', '0') |  |  |  | 			->addDefault('Accept-Ranges', 'bytes') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') |  |  |  | 			->addDefault('Expires', '0') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Disposition', "$disposition; filename=\"{$options['saveName']}\"") |  |  |  | 			->addDefault('Content-Type', $mimeType) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Length', $length) |  |  |  | 			->addDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			->set('Content-Transfer-Encoding', 'binary'); |  |  |  | 			->addDefault('Content-Transfer-Encoding', 'binary') | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			->addDefault('Content-Length', $length) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			->addDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (isset($options['headers'])) { |  |  |  | 		$this->send(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			foreach ($options['headers'] as $header => $value) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$headers->add($header, $value); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		fseek($handle, $contentStart); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		fseek($handle, $begin); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		set_time_limit(0); // Reset time limit for big files |  |  |  | 		set_time_limit(0); // Reset time limit for big files | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$chunkSize = 8 * 1024 * 1024; // 8MB per chunk |  |  |  | 		$chunkSize = 8 * 1024 * 1024; // 8MB per chunk | 
			
		
	
		
		
			
				
					
					|  |  |  | 		while (!feof($handle) && ($fPointer = ftell($handle)) <= $contentEnd) { |  |  |  | 		while (!feof($handle) && ($pos = ftell($handle)) <= $end) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if ($fPointer + $chunkSize > $contentEnd) { |  |  |  | 			if ($pos + $chunkSize > $end) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				$chunkSize = $contentEnd - $fPointer + 1; |  |  |  | 				$chunkSize = $end - $pos + 1; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			echo fread($handle, $chunkSize); |  |  |  | 			echo fread($handle, $chunkSize); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. |  |  |  | 			flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		fclose($handle); |  |  |  | 		fclose($handle); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/** |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * Determines the HTTP range given in the request. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @param integer $fileSize the size of the file that will be used to validate the requested HTTP range. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @return array|boolean the range (begin, end), or false if the range request is invalid. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	protected function getHttpRange($fileSize) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	{ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (!isset($_SERVER['HTTP_RANGE']) || $_SERVER['HTTP_RANGE'] === '-') { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return array(0, $fileSize - 1); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (!preg_match('/^bytes=(\d*)-(\d*)$/', $_SERVER['HTTP_RANGE'], $matches)) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if ($matches[1] === '') { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			$start = $fileSize - $matches[2]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			$end = $fileSize - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} elseif ($matches[2] !== '') { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			$start = $matches[1]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			$end = $matches[2]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			if ($end >= $fileSize) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				$end = $fileSize - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			$start = $matches[1]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			$end = $fileSize - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if ($start < 0 || $start > $end) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return array($start, $end); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * Sends existing file to a browser as a download using x-sendfile. |  |  |  | 	 * 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 |  |  |  | 	 * X-Sendfile is a feature allowing a web application to redirect the request for a file to the webserver | 
			
		
	
	
		
		
			
				
					|  |  | @ -496,46 +447,27 @@ class Response extends \yii\base\Response | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * **Example** |  |  |  | 	 * **Example** | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 *  |  |  |  | 	 *  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * ~~~ |  |  |  | 	 * ~~~ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg', array( |  |  |  | 	 * Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg'); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 *      'saveName' => 'image1.jpg', |  |  |  | 	 * ~~~ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 *      'mimeType' => 'image/jpeg', |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 *      'terminate' => false, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * )); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	 * |  |  |  | 	 * | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @param string $filePath file name with full path |  |  |  | 	 * @param string $filePath file name with full path | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * @param array $options additional options: |  |  |  | 	 * @param string $mimeType the MIME type of the file. If null, it will be determined based on `$filePath`. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * |  |  |  | 	 * @param string $attachmentName file name shown to the user. If null, it will be determined from `$filePath`. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * - saveName: file name shown to the user. If not set, the name will be determined from `$filePath`. |  |  |  | 	 * @param string $xHeader the name of the x-sendfile header. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	 * - mimeType: MIME type of the file. If not set, it will be determined based on the file name. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * - xHeader: appropriate x-sendfile header, defaults to "X-Sendfile". |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * - disposition: either "attachment" or "inline". This specifies whether the file will be downloaded |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 *   or shown inline. Defaults to "attachment". |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * - headers: an array of additional http headers in name-value pairs. |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	 */ |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	public function xSendFile($filePath, $options = array()) |  |  |  | 	public function xSendFile($filePath, $mimeType = null, $attachmentName = null, $xHeader = 'X-Sendfile') | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	{ |  |  |  | 	{ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers = $this->getHeaders(); |  |  |  | 		if ($mimeType === null && ($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 			$mimeType = 'application/octet-stream'; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers->set(empty($options['xHeader']) ? 'X-Sendfile' : $options['xHeader'], $filePath); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (!isset($options['mimeType'])) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (($options['mimeType'] = FileHelper::getMimeTypeByExtension($filePath)) === null) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				$options['mimeType'] = 'text/plain'; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers->set('Content-Type', $options['mimeType']); |  |  |  | 		if ($attachmentName === null) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 			$attachmentName = basename($filePath); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		$disposition = empty($options['disposition']) ? 'attachment' : $options['disposition']; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (!isset($options['saveName'])) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			$options['saveName'] = basename($filePath); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$headers->set('Content-Disposition', "$disposition; filename=\"{$options['saveName']}\""); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (isset($options['headers'])) { |  |  |  | 		$this->getHeaders() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			foreach ($options['headers'] as $header => $value) { |  |  |  | 			->addDefault($xHeader, $filePath) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				$headers->add($header, $value); |  |  |  | 			->addDefault('Content-Type', $mimeType) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			->addDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		$this->send(); |  |  |  | 		$this->send(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  |  | 
 |