在PHP中将FileStreams送给HTML5,而无需将文件写入文件系统



我是PHP的新手,绝对是流媒体视频的新手。

我在SQL Server的FileStream列中存储了MP4视频,我想将它们流式传输到HTML5视频。

我已经设法使用以下流类(http://codesamplez.com/programming/php-html5-video-streaming-tutorial(,通过提供'file_put_contents($ filepath,$ queryResult,$ queryResult(来提供临时文件,,'但是必须依靠写作然后清理文件系统中的中间文件是有问题的。

我是否错过了一个关键概念,该概念可以让我直接从数据库流到视频" src",而不必在之间写入文件?

预先感谢!

如果自己创建临时文件,然后删除它。然后,您可以使用PHP的内置 tempfile()

在read-write(w (模式中创建一个带有唯一名称的临时文件,并返回文件句柄。关闭时,文件将自动删除(例如,通过调用fclose((,或者没有剩余的引用对由tmpfile(((或脚本结束时返回的文件句柄。

private function open()
{
    if ( !($this->stream = tmpfile()) ) {
        fwrite($this->stream, $videodata);
        rewind($this->stream);
        die('Could not open stream for reading');
    }
    // now your temp file is ready to be read.
} 

所以现在您不承担临时责任。删除PHP将为您处理。如果您需要自定义温度。文件名或获取详细信息您可以使用此http://php.net/manual/en/function.sys-get-temp-dir.php

如果您根本不想使用文件,而宁愿纯粹在内存解决方案中使用,则可以尝试使用内存流

private function open()
{
    if ( !($this->stream = fopen('php://memory', 'wb+') ) ) {
        fwrite($this->stream, $videodata);
        rewind($this->stream);
        die('Could not open stream for reading');
    }
    // now your in-memory file is ready to be read.
} 

您可以在存储器流上的fread,fwrite,file_get_contents或使用TCP流将其扔到网络上。但是我必须说,第二个解决方案有点密集,因此不适合流庞大文件。

编写临时文件似乎对我来说是一个临时的解决方法。当您从数据库中获取流并需要将流提供给客户端时,根本不需要存储数据。

您需要做的就是替换链接的示例的部分,该示例从文件中读取(以及Echo的二进制内容到客户端的二进制内容(,然后从SQL读取。

在您的链接示例函数流((中,替换此部分

    while(!feof($this->stream) && $i <= $this->end) {
        $bytesToRead = $this->buffer;
        if(($i+$bytesToRead) > $this->end) {
            $bytesToRead = $this->end - $i + 1;
        }
        $data = fread($this->stream, $bytesToRead);
        echo $data;
        flush();
        $i += $bytesToRead;
    }

替换这样的东西:

/* Execute the query. */  
$stmt = sqlsrv_query($conn, $tsql, $params);  
if( $stmt === false )  
{  
     echo "Error in statement execution.</br>";  
     die( print_r( sqlsrv_errors(), true));  
}  
/* Retrieve and display the data.  
The return data is retrieved as a binary stream. */  
if ( sqlsrv_fetch( $stmt ) )  
{  
   $videostream = sqlsrv_get_field( $stmt, 0,   
                      SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));  
   //header("Content-Type: image/jpg");  
   fpassthru($videostream );  
}  
else  
{  
     echo "Error in retrieving data.</br>";  
     die(print_r( sqlsrv_errors(), true));  
}  

对于后代,这是我的最终结果,似乎不需要临时文件就可以很好地工作。

不确定将查询包含在课堂上并将$ mediafileid传递到班上是否更有意义,但是现在我已经离开了。

其原始信用信息包含整个修改类别:

function ExecutereadMediaSP($MediaFileID){
    try{
    $connection = ConnectToDB();
    ini_set('memory_limit', '-1');
    // logs basic info about media viewer.  Mainly for a basic hit counter.
    LogMediaRequest($connection, $MediaFileID);
    //Selects binary data from SQL Server based on MediaFileID.  Passes this to Stream Class.  May be able to make further improvements later.
    $sql = "SELECT ... data from FILESTREAM column based on file ID ...";   
    $rst = $connection->prepare($sql);
    $rst->execute();
    $rst->bindColumn(1, $filecontent, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
    $row = $rst->fetch(PDO::FETCH_ASSOC);//sql can only return one row due to unique identifier
    //Stream file 
    $stream = new VideoStream($filecontent);
    $stream->start();
    //Clean up.
    $rst->closeCursor();
    unset($rst);
    $connection = null;
    } catch (Exception $e) {
        error_log("Error in getting videon".$e->getMessage(),0);
    }
}

/**
 * VideoStream - PHP class that supports (adaptive) streaming of files
 *
 * @author Rana
 * modified by HazCod to use stream_get_contents and correct session shutoff
 * https://github.com/HazCod
 * @link http://codesamplez.com/programming/php-html5-video-streaming-tutorial
 */
class VideoStream
{
    private $path = "";
    private $stream = "";
    private $buffer = 102400;
    private $start  = -1;
    private $end    = -1;
    private $size   = 0;
    function __construct($filecontent) 
    {

        try{
        // Opens file handle resource to replace use of actual file in the file system.
        $file_handle = fopen('php://memory', 'r+', false, stream_context_create()); 
        // Writes data from SQL Query to file wrapper.
        fwrite($file_handle, $filecontent);
        // Moves pointer to beginning of file.
        fseek($file_handle, 0);
        // Gets info on the "file."  Required to get filesize.
        $fstat = array();
        // gather statistics
        $fstat = fstat($file_handle);
        //Set File Size for Stream Class.
        $this->size  = $fstat['size'];
        // Define Stream as "File."
        $this->stream = $file_handle;
        } catch (PDOException $e) {
            error_log("Error in getting videon".$e->getMessage(),0);
        }
    }
    /**
     * Set proper header to serve the video content
     */
    private function setHeader()
    {   
        ob_get_clean();
        header("Content-Type: video/mp4");
        header("Cache-Control: max-age=2592000, public");
        header("Expires: ".gmdate('D, d M Y H:i:s', time()+2592000) . ' GMT');
      //  header("Last-Modified: ".gmdate('D, d M Y H:i:s', @filemtime($this->path)) . ' GMT' );
        $this->start = 0;
        $this->end   = $this->size - 1;
       // header("Accept-Ranges: 0-".$this->end);
        if (isset($_SERVER['HTTP_RANGE'])) {
            $c_start = $this->start;
            $c_end = $this->end;
            list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
            if (strpos($range, ',') !== false) {
                header('HTTP/1.1 416 Requested Range Not Satisfiable');
                header("Content-Range: bytes $this->start-$this->end/$this->size");
                exit;
            }
            if ($range == '-') {
                $c_start = $this->size - substr($range, 1);
            }else{
                $range = explode('-', $range);
                $c_start = $range[0];
                $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
            }
            $c_end = ($c_end > $this->end) ? $this->end : $c_end;
            if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
                header('HTTP/1.1 416 Requested Range Not Satisfiable');
                header("Content-Range: bytes $this->start-$this->end/$this->size");
                exit;
            }
            $this->start = $c_start;
            $this->end = $c_end;
            $length = $this->end - $this->start + 1;
            fseek($this->stream, $this->start);
            header('HTTP/1.1 206 Partial Content');
            header("Content-Length: ".$length);
            header("Content-Range: bytes $this->start-$this->end/".$this->size);
        }
        else
        {
            header("Content-Length: ".$this->size);
        }  
    }
    /**
     * close curretly opened stream
     */
    private function end()
    {
        fclose($this->stream);
        exit;
    }
    /**
     * perform the streaming of calculated range
     */
    private function stream()
    {
        $i = $this->start;
        set_time_limit(0);
        while(!feof($this->stream) && $i <= $this->end && connection_aborted() == 0) {
            $bytesToRead = $this->buffer;
            if(($i+$bytesToRead) > $this->end) {
                $bytesToRead = $this->end - $i + 1;
            }
            $data = stream_get_contents($this->stream, $bytesToRead);
            echo $data;
            flush();
            $i += $bytesToRead;
        }
    }
    /**
     * Start streaming video content
     */
    function start()
    {
        session_write_close(); //ensure our session is written away before streaming, else we cannot use it elsewhere
        $this->setHeader();
        $this->stream();
        $this->end();
    }
}

最新更新