【问题标题】:Read range chunks chunked with php读取用 php 分块的范围块
【发布时间】:2013-08-05 13:20:20
【问题描述】:

我有一个输入字段,我可以在其中粘贴下载网址。 之后,我使用 AJAX 请求来获取文件信息,例如 headerinfo、content-length、mime type & 以防我使用 curl 接受范围。

然后我开始一个连续的 xhr2 请求循环,其中包含我的 php 文件的范围。

http://www.example.com/chunks.php?url=http://url.com/someFile.ext&range=0-1024
http://www.example.com/chunks.php?url=http://url.com/someFile.ext&range=1024-2048
....

我也可以改成

http://www.example.com/chunks.php?url=http://url.com/someFile.ext&range=0-1024
http://www.example.com/chunks.php?url=http://url.com/someFile.ext&range=1025-2049
....

取决于我的脚本从哪里开始读取文件。

我的第一种方法是使用 cUrl 并设置范围

<?php
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$_GET['url']);
curl_setopt($ch,CURLOPT_RANGE,$_GET['range']);
curl_setopt($ch,CURLOPT_BINARYTRANSFER,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result=curl_exec($ch);
curl_close($ch);
echo $result;
?>

效果很好,但如果范围块大于 1mb,则客户端 onprogress 事件使用 ajax 时没有动画。

我可以使用自定义的CURLOPT_READFUNCTION...但我不知道它是如何工作的...所以我改变了方法并使用了简单的fopen

<?php
$r=explode('-',$_GET['range']);//get (from to) ranges
$cc=($r[1]-$r[0]); //Calculate Client Chunk length
$sc=128; //Set the Server chunk length

$b=""; //Buffer
$bytes=0; //bytes read

$h=fopen($_GET['url'],"rb"); // open the url
fseek($h,$r[0]); // jump to the from pointer retrieved from links

while($bytes<$cc){ //while bytes read is smaller than my client chunk
 $sc=(($bytes+$sc)>$cc?($cc-$bytes):$sc); //prolley an error here 
 //if the server chunk + bytes read is bigger than the client chunk
 //then the server chunk is clinet chunk - bytes read
 $b=fread($h,$sc); // read the buffer
 $bytes+=strlen($b); //add the buffer length to bytes read  
 echo $b;// echo the buffer
 ob_flush(); // flush 
 flush(); // flush
}
fclose($h); //close
?>

现在这可以工作了...我在客户端上得到了正确的动画,并且最终大小也是正确的,因为我使用 fseek && fread,所以指针应该没问题 (0-1024,1024-2048)。

但文件已损坏。

现在经过一些测试......这非常慢。

更好的方法是cUrl 和CURLOPT_READFUNCTION 或fsoket 打开...

所以我猜:

<?php
function $READ(){
 //here i need small chuncks of the response flushed. 
}
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$_GET['url']);
curl_setopt($ch,CURLOPT_RANGE,$_GET['range']);
curl_setopt($ch,CURLOPT_BINARYTRANSFER,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_READFUNCTION,$READ);
$result=curl_exec($ch);
curl_close($ch);
echo $result;
?>

如果你有更好的解决方案,我愿意接受所有使用 javascript 和 php 的东西。

这样做的目的是创建一个带简历的下载管理器,将文件存储到window.webkitRequestFileSystem 中,而不会填满浏览器的内存。

假设客户端有 8mb 的块,而服务器的块是 256kb ..

然后每 8mb 的块被附加到先前使用 window.webkitRequestFileSystem 创建的文件中

每 256kb 我都会更新平均下载速度,这样我就可以制作出漂亮的动画。

服务器上的 php 仅使用 256kb ram,客户端浏览器可以每 8mb 清空垃圾收集(理论上)。

EDIT2

对于这段代码,我找到了解决方案:

代码允许您获取范围,例如:0-100 并将这 100 字节的输出分块!!

这允许您拥有一个具有连续完美 PROGRESSBAR 的 AJAX 脚本

<?php
function w($ch,$chunk){ 
 echo $chunk;
 ob_flush();
 flush();
 return strlen($chunk);
};
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$_GET['url']);
curl_setopt($ch,CURLOPT_RANGE,$_GET['range']);
curl_setopt($ch,CURLOPT_BINARYTRANSFER,1);
curl_setopt($ch,CURLOPT_WRITEFUNCTION,w);
curl_exec($ch);
curl_close($ch);
?>

但我希望你们有更好的解决方案!谢谢

【问题讨论】:

  • 我敢打赌字节 1024 翻了一番。
  • fseek($h,1024)-> 指向 1024 并开始读取 1025... 但我认为最好使用 cUrl 或 fsoket ..

标签: javascript php curl


【解决方案1】:

我可以让它与 PHP curl 的 CURLOPT_WRITEFUNCTION callback setting 一起工作。以下示例回调函数curl_write_flush 用于该 curl 选项,将接收到的每个块写入并将输出刷新到浏览器。

<?php

/**
 * CURLOPT_WRITEFUNCTION which flushes the output buffer and the SAPI buffer.
 *
 * @param resource $curl_handle
 * @param string   $chunk
 */
function curl_write_flush($curl_handle, $chunk)
{ 
    echo $chunk;

    ob_flush(); // flush output buffer (Output Control configuration specific)
    flush();    // flush output body (SAPI specific)

    return strlen($chunk); // tell Curl there was output (if any).
};

$curl_handle = curl_init($_GET['url']);
curl_setopt($curl_handle, CURLOPT_RANGE, $_GET['range']);
curl_setopt($curl_handle, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, 'curl_write_flush');
curl_exec($curl_handle);
curl_close($curl_handle);

我尝试使用小文件和大文件,效果很好,但您无法设置自定义块大小。

下载流的速度与我通过 ISP 获得的速度相同。

如果你有更好的答案,我愿意回答。

【讨论】:

  • CURLOPT_BUFFERSIZE:每次读取使用的缓冲区大小。但是,不能保证此请求会得到满足。
  • 我的意思是有 100 分的赏金...如果您根据我的代码发布一个简单的示例,您可以获得赏金。问题“示例...?”并不打算成为一件坏事。
  • 无论如何感谢您的回答和纠正我糟糕的英语。
猜你喜欢
  • 2014-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
相关资源
最近更新 更多