- php使用HttpFoundation進行下載下傳檔案–php處理下載下傳
1、使用composer安裝HttpFoundation元件
composer require symfony/http-foundation -v 3.4.*
2、目錄結構
3、FileDownload.php對httpfoundation元件下載下傳功能封裝(支援中文檔案名)
<?php
namespace download;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Request;
class FileDownload extends BinaryFileResponse{
/**
* 構造函數
* @param string $file 檔案路徑
* @param integer $status 響應狀态
* @param array $headers 響應頭資訊
* @param boolean $public Cache-Control
* @param string $contentDisposition Content-Disposition
* @param boolean $autoEtag Etag
* @param boolean $autoLastModified LastModified
* @return BinaryFileResponse
*/
public function __construct($file, $status = 200, $headers = [], $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
{
$file = $this->encoding($file, 'GBK', 'UTF-8');
parent::__construct($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified);
}
/**
* 使用php進行檔案下載下傳
* @param string $filename 顯示檔案名(不包含字尾)
*/
public function download($showname = '')
{
$showname = $this->getShowName($showname);
$this->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $showname);
$request = Request::createFromGlobals();
$this->prepare($request)->send();
}
/**
* 使用X-SendFile進行檔案下載下傳
* @param string $filename 顯示檔案名(不包含字尾)
*/
public function xDownload($showname, $Sendfile = 'X-Sendfile')
{
$showname = $this->getShowName($showname);
$this->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $showname);
$request = Request::createFromGlobals();
$request->headers->set('X-Sendfile-Type', $Sendfile);
//設定使用X-SendFile下載下傳檔案
BinaryFileResponse::trustXSendfileTypeHeader();
$this->prepare($request)->send();
}
/**
* 擷取顯示檔案名
* @param string $file 檔案
* @return string
*/
protected function getShowName($file)
{
if(!empty($file))
{
return $file.'.'.$this->file->getExtension();
}
return $this->encoding($this->file->getBasename());
}
/**
* 轉換字元編碼
* @param string $str 檔案路徑
* @param string $to 轉換後的編碼
* @param string $from 轉換前的編碼
* @return string
*/
protected function encoding($str, $to = 'UTF-8', $from = 'GBK')
{
if(empty($str))
{
return false;
}
if(Util::os() == 'WINNT')
{
return Util::convertEncoding($str, $to, $from);
}
return $str;
}
/**
* 修複與 HTTP 規範不相容的問題
* @param Request $request 請求對象執行個體
* @return this
*/
public function prepare(Request $request)
{
if (!$this->headers->has('Content-Type'))
{
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
}
if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL'))
{
$this->setProtocolVersion('1.1');
}
$this->ensureIEOverSSLCompatibility($request);
$this->offset = 0;
$this->maxlen = -1;
if (false === $fileSize = $this->file->getSize())
{
return $this;
}
$this->headers->set('Content-Length', $fileSize);
if (!$this->headers->has('Accept-Ranges'))
{
$this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none');
}
if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type'))
{
$type = $request->headers->get('X-Sendfile-Type');
$path = $this->file->getRealPath();
if (false === $path)
{
$path = $this->file->getPathname();
}
$path = $this->encoding($path);
if ('x-accel-redirect' === strtolower($type))
{
foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping)
{
$mapping = explode('=', $mapping, 2);
if (2 === \count($mapping))
{
$pathPrefix = trim($mapping[0]);
$location = trim($mapping[1]);
if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix)
{
$path = $location.substr($path, \strlen($pathPrefix));
$this->headers->set($type, $path);
$this->maxlen = 0;
break;
}
}
}
}
else
{
$this->headers->set($type, $path);
$this->maxlen = 0;
}
}
elseif ($request->headers->has('Range'))
{
if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range')))
{
$range = $request->headers->get('Range');
list($start, $end) = explode('-', substr($range, 6), 2) + [0];
$end = ('' === $end) ? $fileSize - 1 : (int) $end;
if ('' === $start)
{
$start = $fileSize - $end;
$end = $fileSize - 1;
}
else
{
$start = (int) $start;
}
if ($start <= $end)
{
if ($start < 0 || $end > $fileSize - 1)
{
$this->setStatusCode(416);
$this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
}
elseif (0 !== $start || $end !== $fileSize - 1)
{
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
$this->offset = $start;
$this->setStatusCode(206);
$this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
$this->headers->set('Content-Length', $end - $start + 1);
}
}
}
}
return $this;
}
protected function hasValidIfRangeHeader($header)
{
if ($this->getEtag() === $header)
{
return true;
}
if (null === $lastModified = $this->getLastModified())
{
return false;
}
return $lastModified->format('D, d M Y H:i:s').' GMT' === $header;
}
}
4、Util.php
<?php
namespace download;
class Util {
/**
* 擷取系統類型
* @return string
*/
public static function os(){
return PHP_OS;
}
/**
* 轉換字元編碼
* @param string $str 檔案路徑
* @param string $to 轉換後的編碼
* @param string $from 轉換前的編碼
* @return string
*/
public static function convertEncoding($str, $to = 'GBK', $from = 'UTF-8')
{
if(empty($str))
{
return false;
}
return mb_convert_encoding($str, $to, $from);
}
}
4、index.php 測試檔案下載下傳
<?php
require_once "./vendor/autoload.php";
require_once './download/FileDownload.php';
require_once './download/Util.php';
use download\FileDownload;
try
{
$file = "./源碼.zip";
$fileDownload = FileDownload::create($file, 200);
$fileDownload->download();
//使用Xsendfile下載下傳檔案
//$fileDownload->xdownload('測試源碼');
//自定義下載下傳檔案名(不包含字尾)
//$fileDownload->download('測試');
//下載下傳後删除源檔案
//$fileDownload->deleteFileAfterSend(true)->download();
}
catch(Exception $e)
{
echo $e->getMessage();
}