使用 Zend Framework 2 提供二进制数据和部分内容的正确方法

Lan*_*nbo 5 php download http-headers zend-framework2

我想允许使用某种访问控制来提供二进制文件。由于控件相当复杂,我不能简单地让 Apache 提供文件,我必须使用我的 Zend Framework 2 应用程序通过 PHP 提供文件。动作是这样的:

public function sendAction() {
        $filename = /* database action */;
        $size = filesize($filename);
        $response = $this->getResponse();

        if($this->getRequest()->getHeaders()->has('Range')) {
            list($unit, $range) = explode('=', $this->getRequest()->getHeaders()->get('Range')->toString());
            $ranges = explode(',', $range);
            $ranges = explode('-', $ranges[0]);

            $start = (int)$ranges[0];
            $end = (int)(isset($ranges[1]) ? $ranges[1] : $size - 1);
            $length = $start - $end;

            $response->getHeaders()->addHeaders(array('Content-Type' => 'audio/mpeg', 'Accept-Ranges' => 'bytes', 'Content-Length' => $length - 1));
            $response->setStatusCode(206);

            $f = fopen($filename, 'r');
            if($start) fseek($f, $start);
            $out = '';
            while($length) {
                $read = ($length > 8192) ? 8192 : $length;
                $length -= $read;
                $out .= fread($fp,$read);
            }
            fclose($f);

            $response->setContent($out);
        } else {
            $response
                 ->setContent(file_get_contents($filename))
                 ->getHeaders()->addHeaders(array('Content-Type' => 'audio/mpeg', 'Accept-Ranges' => 'bytes'));
        }

        return $this->getResponse();
}
Run Code Online (Sandbox Code Playgroud)

一方面,我确信这是非常低效的,因为文件总是在提供服务之前完全加载到 RAM 中。

但是,这似乎不起作用。当我尝试访问该文件时,我audio/mpeg在 Chrome 中获得了正确的播放器,但随后浏览器取消了请求并停止。我根本无法播放音频。

我在网上找不到任何关于如何以正确的方式在 Zend 2 中实现 206 响应的提示,也许有人可以在这里帮助我。

Tom*_*ski 4

你应该使用流。

我的应用程序中的示例代码

public function documentAction()
{
    $name = $this->params('name');
    try {

        if (!$this->getServiceLocator()->get('AuthStorage')->hasIdentity()) {
            throw new \Exception('You must login.');
        }

        $file = getcwd().'/data/uploads/'.pathinfo($name)['basename'];
        if (file_exists($file)) {
            $response = new \Zend\Http\Response\Stream();
            $headers = new \Zend\Http\Headers();
            $headers->addHeaderLine('Content-type', 'application/pdf');
            $response->setHeaders($headers);
            $response->setStream(fopen($file, 'r'));
            return $response;
        } else {
            throw new \Exception('File not exist');
        }
    }
    catch (\Exception $e) {
        $this->flashMessenger()->setNamespace('error')->addMessage('404');
        return $this->redirect()->toUrl('/');
    }
}    
Run Code Online (Sandbox Code Playgroud)