2017-03-21 45 views
9

我試圖在websever上實時處理用戶上傳的文件, ,但似乎只有在完成文件上傳後,APACHE纔會調用PHP。在Web服務器上上傳文件而無需先在本地存儲?

當我上傳使用curl的文件,並設置

傳輸編碼:「分塊」

我取得了一些成功,但通過瀏覽器不能做同樣的事情。

  • 我用Dropzone.js但是當我試圖設置相同的標題,它表示傳輸-Encoding是不安全的報頭,因此不設置它。

這個答案解釋了那裏有什麼問題。 Can't set Transfer-Encoding :"Chunked from Browser"

簡而言之問題是,當用戶將文件上傳到網絡服務器,我想網絡服務器來啓動,只要第一個字節是可用的處理它。 通過過程我的意思是,管道它到一個命名管道。

不想讓500MB先上傳到服務器,然後開始處理它。

但是對於當前的Web服務器(APACHE-PHP),我似乎無法完成它。

有人可以請解釋一下,使用什麼技術堆棧或變通方法,以便我可以通過瀏覽器上傳大文件,並在第一個字節可用時立即開始處理它。

+0

如果您有興趣我可以發佈答案 – bxN5

+0

您可以使用fineuploader以5 MB大塊上傳到Amazon AWS並啓動一個cron來檢查新的AWS文件併爲Named Pipe處理它嗎? –

+0

@ bxN5:是的請發佈,目前我正在努力做同樣的busboy圖書館,'數據'功能我管道大塊兒童過程..! – Himanshu97

回答

2

它是可以使用的NodeJS /多方做到這一點。 Here他們有一個直接上傳到Amazon S3的例子。This是表單,它將內容類型設置爲multipart/form-data。而here是表單零件處理的功能。 part參數的類型爲ReadableStream,這將允許使用data事件對輸入進行每塊處理。

節點js中可讀流的更多信息是here

1

如果你真的想這麼做(抱歉,不要認爲這是個好主意),你應該嘗試尋找一個可以完成你的工作的FUSE文件系統。

也許已經有一個https://github.com/libfuse/libfuse/wiki/Filesystems

或者你應該寫你自己的。

但是一旦上傳完成記憶和後處理腳本完成他的工作臨時文件將被刪除

+0

我很害怕,這不是我正在尋找的。 我只想將上傳的文件流式傳輸到外部應用程序,而不是先存儲它。 – Himanshu97

1

你的意思是你想用PHP生活流?

<?php 

class VideoStream 
{ 
    private $path = ""; 
    private $stream = ""; 
    private $buffer = 102400; 
    private $start = -1; 
    private $end = -1; 
    private $size = 0; 

    function __construct($filePath) 
    { 
     $this->path = $filePath; 
    } 

    /** 
    * Open stream 
    */ 
    private function open() 
    { 
     if (!($this->stream = fopen($this->path, 'rb'))) { 
      die('Could not open stream for reading'); 
     } 

    } 

    /** 
    * 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->size = filesize($this->path); 
     $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) { 
      $bytesToRead = $this->buffer; 
      if(($i+$bytesToRead) > $this->end) { 
       $bytesToRead = $this->end - $i + 1; 
      } 
      $data = fread($this->stream, $bytesToRead); 
      echo $data; 
      flush(); 
      $i += $bytesToRead; 
     } 
    } 

    /** 
    * Start streaming video content 
    */ 
    function start() 
    { 
     $this->open(); 
     $this->setHeader(); 
     $this->stream(); 
     $this->end(); 
    } 
} 

要使用這個類,你將不得不寫簡單的代碼類似如下:

$stream = new VideoStream($filePath); 
$stream->start(); 
+1

我認爲他正在研究一些更好的實時工作空間。 – DeerSpotter

1

你可以上傳與HTML5的繼續上傳工具(如Resumable.js)和處理上傳的部分作爲文件他們收到了。

或者作爲一種解決方法,您可以找到上傳文件的路徑(通常位於/ tmp),然後編寫後臺作業以將其流式傳輸到第三方應用程序。這可能會更困難。

可能還有其他的解決方案......

相關問題