Browse Source

#106 - video transcoder: improvements in storage engine to allow to send files by chunks and file seek support

Alex Trofimov 12 years ago
parent
commit
ce2af51767
2 changed files with 65 additions and 5 deletions
  1. 1 5
      inc/classes/BxDolStorageLocal.php
  2. 64 0
      inc/utils.inc.php

+ 1 - 5
inc/classes/BxDolStorageLocal.php

@@ -68,11 +68,7 @@ class BxDolStorageLocal extends BxDolStorage
             return false;
         }
 
-        header('Content-Type: ' . $aFile['mime_type']);
-        if ($this->_iCacheControl > 0)
-            header('Cache-Control: max-age=' . ($aFile['private'] && $this->_iCacheControl > $this->_aObject['token_life'] ? $this->_aObject['token_life'] : $this->_iCacheControl));
-
-        if (false === readfile($sFileLocation)) {
+        if (!bx_smart_readfile($sFileLocation, $aFile['file_name'], $aFile['mime_type'], $aFile['private'] && $this->_iCacheControl > $this->_aObject['token_life'] ? $this->_aObject['token_life'] : $this->_iCacheControl, $aFile['private'] ? 'private' : 'public')) {
             $this->setErrorCode(BX_DOL_STORAGE_ERR_ENGINE_GET);
             return false;
         }

+ 64 - 0
inc/utils.inc.php

@@ -1198,4 +1198,68 @@ function bx_show_service_unavailable_error_and_exit ($sMsg = false, $iRetryAfter
     exit;
 }
 
+/**
+ * The function is sumilar to php readfile, but it send all required headers and can send file by chunks and suports file seek
+ * @param $sPath path to file to output to the browser
+ * @param $sFilename filename without path, ig file is saved from browser, then this name is used, not used(empty) by default
+ * @param $sMimeType file mime type, by default 'application/octet-stream'
+ * @param $iCacheAge file cache age, by default 0
+ * @param $sCachePrivacy cache privacy 'public' (default value) or 'private'
+ * @return true on success or false on error
+ */
+function bx_smart_readfile($sPath, $sFilename = '', $sMimeType = 'application/octet-stream', $iCacheAge = 0, $sCachePrivacy = 'public')
+{
+    if(!file_exists($sPath)) {
+        header ("HTTP/1.0 404 Not Found");
+        return;
+    }
+
+    $size = filesize($sPath);
+    $time = date('r',filemtime($sPath));
+
+    $fm = @fopen($sPath,'rb');
+    if (!$fm) 
+        return false;
+
+    $begin = 0;
+    $end = $size;
+
+    if (isset($_SERVER['HTTP_RANGE'])) {
+        if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
+            $begin = intval($matches[1]);
+            if (!empty($matches[2]))
+                $end = intval($matches[2]);
+        }
+    }
+
+    if ($begin > 0 || $end < $size)
+        header('HTTP/1.0 206 Partial Content');
+    else
+        header('HTTP/1.0 200 OK');
+
+    header('Content-Type: ' . $sMimeType);
+    header('Cache-Control: ' . $sCachePrivacy . ', must-revalidate, max-age=' . $iCacheAge);
+    header('Pragma: no-cache');
+    header('Accept-Ranges: bytes');
+    header('Content-Length:' . ($end - $begin));
+    header('Content-Range: bytes ' . $begin . '-' . $end . '/' . $size);
+    if ($sFilename)
+        header('Content-Disposition: inline; filename=' . $sFilename);
+    header('Content-Transfer-Encoding: binary');
+    header('Last-Modified:' . $time);
+    header('Connection: close');
+
+    $cur = $begin;
+    fseek($fm, $begin, 0);
+
+    while (!feof($fm) && $cur < $end && (connection_status() == 0)) {
+        print fread($fm, min(1024*16, $end - $cur));
+        $cur += 1024*16;
+    }
+
+    fclose($fm);
+
+    return true;
+}
+
 /** @} */