五十二、逐行阅读Yii2.0.43_Yii框架文件yii\web\Response.php(4)

一、sendFile方法,发送文件

    // 发送文件
    public function sendFile($filePath, $attachmentName = null, $options = [])
    {
        // mimeType设置
        if (!isset($options['mimeType'])) {
            $options['mimeType'] = FileHelper::getMimeTypeByExtension($filePath);
        }

        // 附件名
        if ($attachmentName === null) {
            $attachmentName = basename($filePath);
        }

        // 发送数据
        $handle = fopen($filePath, 'rb');
        $this->sendStreamAsFile($handle, $attachmentName, $options);

        return $this;
    }

二、sendContentAsFile方法,以文件形式发送指定内容

    // 以文件方式发送指定内容
    public function sendContentAsFile($content, $attachmentName, $options = [])
    {
        $headers = $this->getHeaders();

        $contentLength = StringHelper::byteLength($content);
        $range = $this->getHttpRange($contentLength);

        if ($range === false) {
            $headers->set('Content-Range', "bytes */$contentLength");
            throw new RangeNotSatisfiableHttpException();
        }

        list($begin, $end) = $range;
        if ($begin != 0 || $end != $contentLength - 1) {
            $this->setStatusCode(206);
            $headers->set('Content-Range', "bytes $begin-$end/$contentLength");
            $this->content = StringHelper::byteSubstr($content, $begin, $end - $begin + 1);
        } else {
            $this->setStatusCode(200);
            $this->content = $content;
        }

        $mimeType = isset($options['mimeType']) ? $options['mimeType'] : 'application/octet-stream';
        $this->setDownloadHeaders($attachmentName, $mimeType, !empty($options['inline']), $end - $begin + 1);

        $this->format = self::FORMAT_RAW;

        return $this;
    }

三、sendStreamAsFile方法,以文件形式发送流

    // 以文件方式发送指定流
    public function sendStreamAsFile($handle, $attachmentName, $options = [])
    {
        $headers = $this->getHeaders();

        // 数据大小
        if (isset($options['fileSize'])) {
            $fileSize = $options['fileSize'];
        } else {
            if ($this->isSeekable($handle)) {
                fseek($handle, 0, SEEK_END);
                $fileSize = ftell($handle);
            } else {
                $fileSize = 0;
            }
        }

        $range = $this->getHttpRange($fileSize);
        if ($range === false) {
            $headers->set('Content-Range', "bytes */$fileSize");
            throw new RangeNotSatisfiableHttpException();
        }

        list($begin, $end) = $range;
        if ($begin != 0 || $end != $fileSize - 1) {
            $this->setStatusCode(206);
            $headers->set('Content-Range', "bytes $begin-$end/$fileSize");
        } else {
            $this->setStatusCode(200);
        }

        $mimeType = isset($options['mimeType']) ? $options['mimeType'] : 'application/octet-stream';
        $this->setDownloadHeaders($attachmentName, $mimeType, !empty($options['inline']), $end - $begin + 1);

        $this->format = self::FORMAT_RAW;
        $this->stream = [$handle, $begin, $end];

        return $this;
    }

四、setDownloadHeaders方法,设置用于文件下载的默认HTTP头集

    // 设置用于文件下载的默认HTTP头集
    public function setDownloadHeaders($attachmentName, $mimeType = null, $inline = false, $contentLength = null)
    {
        $headers = $this->getHeaders();

        $disposition = $inline ? 'inline' : 'attachment';
        $headers->setDefault('Pragma', 'public')
            ->setDefault('Accept-Ranges', 'bytes')
            ->setDefault('Expires', '0')
            ->setDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
            ->setDefault('Content-Disposition', $this->getDispositionHeaderValue($disposition, $attachmentName));

        if ($mimeType !== null) {
            $headers->setDefault('Content-Type', $mimeType);
        }

        if ($contentLength !== null) {
            $headers->setDefault('Content-Length', $contentLength);
        }

        return $this;
    }

五、getHttpRange方法,解析Http请求头Range信息

    //解析Http请求头Range信息
    protected function getHttpRange($fileSize)
    {
        //Range请求头格式:
        //Range: bytes=start-end
        $rangeHeader = Yii::$app->getRequest()->getHeaders()->get('Range', '-');

        //返回整个文件字节信息
        if ($rangeHeader === '-') {
            return [0, $fileSize - 1];
        }

        //取得start和end的值
        if (!preg_match('/^bytes=(\d*)-(\d*)$/', $rangeHeader, $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;
        }

        return [$start, $end];
    }

六、xSendFile方法,使用x-sendfile将现有文件作为下载文件发送到浏览器

    //使用x-sendfile将现有文件作为下载文件发送到浏览器
    public function xSendFile($filePath, $attachmentName = null, $options = [])
    {
        //下载名称
        if ($attachmentName === null) {
            $attachmentName = basename($filePath);
        }

        //mimeType
        if (isset($options['mimeType'])) {
            $mimeType = $options['mimeType'];
        } elseif (($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) {
            $mimeType = 'application/octet-stream';
        }

        // xHeader
        if (isset($options['xHeader'])) {
            $xHeader = $options['xHeader'];
        } else {
            $xHeader = 'X-Sendfile';
        }

        $disposition = empty($options['inline']) ?
            'attachment' :
            'inline';

        $this->getHeaders()
            ->setDefault($xHeader, $filePath)
            ->setDefault('Content-Type', $mimeType)
            ->setDefault('Content-Disposition', $this->getDispositionHeaderValue($disposition, $attachmentName));

        $this->format = self::FORMAT_RAW;

        return $this;
    }

七、getDispositionHeaderValue方法,处理Content-Disposition的值

    //处理Content-Disposition的值,
    //兼容新旧浏览器
    protected function getDispositionHeaderValue($disposition, $attachmentName)
    {
        $fallbackName = str_replace(
            ['%', '/', '\\', '"', "\x7F"],
            ['_', '_', '_', '\\"', '_'],
            Inflector::transliterate($attachmentName, Inflector::TRANSLITERATE_LOOSE)
        );
        $utfName = rawurlencode(str_replace(['%', '/', '\\'], '', $attachmentName));

        $dispositionHeader = "{$disposition}; filename=\"{$fallbackName}\"";
        if ($utfName !== $fallbackName) {
            $dispositionHeader .= "; filename*=utf-8''{$utfName}";
        }

        return $dispositionHeader;
    }

总结:

 阅读了7个方法:

  • sendFile方法,发送文件
  • sendContentAsFile方法,以文件形式发送指定内容
  • sendStreamAsFile方法,以文件形式发送流
  • setDownloadHeaders方法,设置用于文件下载的默认HTTP头集
  • getHttpRange方法,解析Http请求头Range信息
  • xSendFile方法,使用x-sendfile将现有文件作为下载文件发送到浏览器
  • getDispositionHeaderValue方法,处理Content-Disposition的值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值