PHP每天自动更新静态文件下载地址,防盗链
在网站中的文件下载一般会有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 .= "\n"; } } 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;