PHP下载文件的正确方式

关于file_get_contents

我们都习惯使用 file_get_contents 函数来很方便的实现读取文件,远程资源访问。

file_get_contents ( string $filename , bool $use_include_path = false , resource $context = ? , int $offset = -1 , int $maxlen = ? ) : string

filename
要读取的文件的名称。

use_include_path
注意:

As of PHP 5 the FILE_USE_INCLUDE_PATH can be used to trigger include path search.

context
A valid context resource created with stream_context_create(). 如果你不需要自定义 context,可以用 null 来忽略。

offset
The offset where the reading starts on the original stream.

Seeking (offset) is not supported with remote files. Attempting to seek on non-local files may work with small offsets, but this is unpredictable because it works on the buffered stream.

maxlen
Maximum length of data read. The default is to read until end of file is reached. Note that this parameter is applied to the stream processed by the filters.

说到远程资源,就牵涉到服务端的协议类型,不同的类型自然有不同的请求方式,PHP内置fopen包装器提供的协议有很多,当然你也可以自定义协议:

file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流

所以PHP会分析你的地址,采用对应的协议去获取资源,这也是为什么file_get_contents既可以访问本地资源,也可以访问远程资源。

有的协议需要带上参数或者身份信息,这就是所谓的上下文context参数。

其实file_get_contents的原理也很简单,就拿http请求为例:

file_get_contents("https://activity.book.com.cn/1615218508027YKwtdbTlMpOFHZFm8GVK.mp4");

建立tcp连接,接收数据,并存储在临时变量中,所以说它必须一次性接受完数据(内部也是分批read),之后才能处理,它的offset参数不适用于远程资源,这个也好理解,如果是本地文件可以通过游标来实现偏移,但是对于远程资源,你必须从头接收这些数据,而无法选择跳过,你可能要说,那可以舍弃前面的只返回offset之后的数据啊,实现起来当然没有问题,但是这样一来内部就必须是逐个字节来read,否则无法精确控制offset的值,这样将大大降低性能,所以基于此,file_get_contents的作者对offset做了限制(只在读取本地资源时有效),但是maxlen参数是有效的,这个也好理解,多余的就不读了呗。

了解了这些之后,我们就知道file_get_contents读取远程资源的时候,内存占用较多,且比较浪费内存,当然,在请求小文件,请求接口的时候影响不大,如果是下载几十兆,几百兆的资源就不适合了。要知道网络数据传输实际上都是流式的,所以在读取的时候使用流式的读取效率会更高,这就是我们的 fread, fgets, fgetc, fgetss, stream_get_line函数。

使用fread

比如将下载的文件存储到本地文件,使用流式处理。

$remotefile = fopen("https://activity.book.com.cn/1615218508027YKwtdbTlMpOFHZFm8GVK.mp4", 'r');
$fh = fopen($localfile, 'w');

while (!feof($remotefile)) {
	$output = fread($remotefile, 8192);
	fwrite($fh, $output);
}

fclose($remotefile);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值