在网站中的文件下载一般会有2种方式,永久链接和程序动态输出。
- 静态链接下载的好处是可以通过客户端软件进行断点续传,但是缺点是无法保护程序的安全性,无法控制客户端的权限问题。
- 程 序动态输出则与静态链接下载刚好相反,可以控制权限的问题,但是无法保证客户端下载断点续传的问题,虽然大部分浏览器也支持动态程序输出文件的断点续传, 但是需要客户端一直保持在有权限的状态下。如果客户端的Session关闭时权限丢失,那么下载就会结束掉,需要重新验证权限并重新开始下载。
下载文件的问题与解决方案
当下载的文件过大,或者网络带宽不够高的情况下,只有静态链接下载才会让下载的用户满意。
但是你不想客户把这个下载的链接地址传播开来,如果你在短时间内把文件名或者目录名改了,又会直接影响到用户的下载。
所以最终我们需要在有限的时间内能满足正在下载的用户,又能修改文件的访问路径。
假设一个2G的文件,下载时间在几个小时到2天的范围内能完成下载。那么我们就应该让最开始下载的那个链接至少保持2天,在第3天的时候删除它,这样我们就想到了数据结构中的队列来解决这个问题,请看下图:
明白这个队列的原理,我们接下来就在不需要数据库的情况下建立一个txt文件来存放3个随机的URL加上一个第四个计算好的URL。然后让这个程序在cronjob的中运行,可以在每天的晚上00:00运行,让队列移动一格。
PHP实现队列
文 件1为存放的队列,queue.txt格式为8个随机字符串是从ABCDEFFGHHIJKLMNOPQRSTUVWXYZ0123456789中随机抽 取的,作为文件的存放目录。目录有一个下划线作为分隔,1代表文件夹存在并有用户在下载,0代表文件夹没有在使用中,将在队列移动时把替换到第一个文件 夹。因为文件夹改变了,文件下载的URL也随之改变了。
下面是这个queue.txt每天的变化情况。
|
第一天 |
第二天 |
第三天 |
第四天 |
|
AAAAAAAA_1 |
BBBBBBBB_1 |
CCCCCCCC_1 |
DDDDDDDD_1 |
|
BBBBBBBB_1 |
CCCCCCCC_1 |
DDDDDDDD_1 |
EEEEEEEE_1 |
|
CCCCCCCC_1 |
DDDDDDDD_1 |
EEEEEEEE_1 |
FFFFFFFF_1 |
|
DDDDDDDD_0 |
EEEEEEEE_0 |
FFFFFFFF_0 |
GGGGGGGG_0 |
每天自动运行的PHP程序auto_change_folder.php,它的作用是将第四个文件夹替换到第一个文件夹。
<?php
$length = 8;
$filename = ‘queue.txt’;
$root = dirname(__FILE__);
$handle = fopen($filename, "r");
$folders = $codes = array();
while (!feof($handle)) {
$buffer = fgets($handle);
if ($buffer) {
$folder = explode(‘_’, trim($buffer));
$folders[] = $folder;
$codes[] = $folder[0];
}
}
fclose($handle);
$count = 0;
$need_folder = $pre_folder = $code = ”;
foreach($folders as $k=>$f) {
if($f[1] && is_dir($f[0]) && file_exists($f[0].’/file.zip’)) {
$count++;
}
elseif($f[1] && !(is_dir($f[0]) && file_exists($f[0].’/file.zip’))) {
unset($folders[$k]);
}
elseif($f[1] == 0) {
$need_folder = $f[0];
$folders[$k][1] = 1;
break;
}
}
$pre_folder = $folders[$count-1][0];
if($count == 3) {
$remove_folder = array_shift($folders);
echo $remove_folder[0], " ", $pre_folder." ".$need_folder." ";
if(@rename($root.’/’.$remove_folder[0], $root.’/’.$need_folder)) {
}
else {
die("Rename folder failed.");
}
}
else {
die("Folder not right.");
}
$alpha = ‘ABCDEFFGHHIJKLMNOPQRSTUVWXYZ0123456789′;
$allowed_chars = str_split($alpha);
do {
for ($i = 0; $i < $length; $i++) {
$code .= $allowed_chars[array_rand($allowed_chars)];
}
} while(in_array($code, $codes));
array_push($folders, array($code, 0));
$output = ”;
foreach($folders as $k=>$f) {
$output .= implode(‘_’, $f);
if($f[1]) {
$output .= "
";
}
}
file_put_contents($filename, $output);
?>
把这个auto_change_folder.php文件放入cronjob中运行。
0 0 * * * wget -O /dev/null http://blog.lixiphp.com/files/big/auto_change_folder.php
PHP文件获取最新的文件下载地址
当然静态地址不可能每天都手动去获取,当然要通过PHP自动获取,这样这个地址可以随便显示出来让用户下载。
我们把这个文件命名为auto_download_here.php,当然这个程序要去判断最终目标文件是否存在。
<?php
$filename = ‘queue.txt’;
$root = dirname(__FILE__);
$handle = fopen($filename, "r");
$folders = $codes = array();
$count = 0;
$need_folder = ”;
while (!feof($handle)) {
$buffer = fgets($handle);
if ($buffer) {
$folder = explode(‘_’, trim($buffer));
if($folder[1] && is_dir($folder[0]) && file_exists($folder[0].’/file.zip’)) {
$count++;
}
elseif($folder[1] && !(is_dir($folder[0]) && file_exists($folder[0].’/file.zip’))) {
unset($folder);
}
elseif($folder[1] == 0) {
$need_folder = $f[0];
break;
}
$folders[] = $folder;
}
}
fclose($handle);
$pre_folder = $folders[$count-1][0];
header("Location: $pre_folder/file.zip");
?>
完了,我们进入演示环节吧!
自动下载地址切换下载演示
文件下载地址:http://demo.lixiphp.com/switch_download/auto_download_here.php
每天自动更新程序:http://demo.lixiphp.com/switch_download/auto_change_folder.php
队列查看地址:http://demo.lixiphp.com/switch_download/queue.txt
备注:
- 如果想更新文件夹长度,可以修改auto_change_folder.php第二行,$length = 8; 默认长度是8;
- 文件保留天数与队列长度有关;
- 文件夹丢失后,队列将无法自动运行;
- 文件夹的权限需要为0777;