通常文件下载过程是十分简单的,建立一个链接指向到目标文件就可以了。例如下面的链接:

XML/HTML代码
  1. <a href=http://www.xxx.com/xxx.rar>点击下载文件</a>

  但是,实际情况可能会稍复杂。比如需要用户填写完整注册信息后才可以下载该文件,这时最先想到的是使用Redirect的方式。下面介绍两种方式。

  (1)用Redirect方式。先检查表格是否已经填写完毕和完整,然后将链接指到该文件,这样用户就可以下载。请看下面的示例代码:

PHP代码
  1. <?php
  2. /*文件功能:检查变量form是否完整*/
  3. if($form){
  4. //重新定向浏览器指向
  5. Header("Location: http:// http://www.xxx.com/xxx.rar");
  6. exit;
  7. }
  8. ?>

  (2)根据下载文件的序号来查找,链接的形式如下:

XML/HTML代码
  1. <a href="http://www.xxx.com/download.php?id=123456">点击下载文件</a>

  上面的链接使用ID方式接收要下载文件的编号,然后再用Redirect的方式连接到真实的文件链接。

  以上这两种方法虽然实现了文件的下载功能,但是缺点是直接暴露了文件所属的路径,而且没有防盗链的功能,所以上面的方式是简单直接但存在安全隐患的文件下载方式。在PHP中,通常是利用header()函数和fread()函数来实现安全的文件下载。

  例如,需要下载的是一个文件名为xxx.rar的文件,首先创建文件是download.php的PHP文件。通过前面的例子很容易通过文件的ID号从数据库中得到待下载文件的真实位置,在获得文件的真实存储位置后,可以通过header()函数的location参数直接重定向到这个文件。但是这样仍然是不安全的,因为某些下载软件还是可以通过重定向分析获得该文件的位置信息。因此需要用另外一种方法,就是PHP的文件处理API函数。它是通过fread()函数把文件直接输出到浏览器提示用户下载,这样所有的处理都是在服务器端完成的,因此用户就无法获得文件具体存储位置信息的,示例代码如下:

PHP代码
  1. <?php
  2. $file_name = "xxx.rar";     //下载文件名
  3. $file_dir = "./up/";        //下载文件存放目录
  4. //检查文件是否存在
  5. if (! file_exists ( $file_dir . $file_name )) {
  6. echo "文件找不到";
  7. exit ();
  8. } else {
  9. //打开文件
  10. $file = fopen ( $file_dir . $file_name, "r" );
  11. //输入文件标签
  12. Header ( "Content-type: application/octet-stream" );
  13. Header ( "Accept-Ranges: bytes" );
  14. Header ( "Accept-Length: " . filesize ( $file_dir . $file_name ) );
  15. Header ( "Content-Disposition: attachment; filename=" . $file_name );
  16. //输出文件内容
  17. //读取文件内容并直接输出到浏览器
  18. echo fread ( $file, filesize ( $file_dir . $file_name ) );
  19. fclose ( $file );
  20. exit ();
  21. }
  22. ?>

  【代码解读】

  上述代码中,程序发送Header信息是用来告诉Apache和浏览器下载文件的相关信息的。content-type的含义代表文件MIME类型是文件流格式。如果在Apache配置里面把文件的MIME类型设为application/octet-stream(如add application/octet-stream .xxx.rar),那么浏览器(客户端)就会知道,这是一个文件流格式的文件并提示用户下载。Accept-Ranges是一个响应头标,它允许服务器指明将在给定的偏移和长度处,为资源组成部分的接受请求,该头标的值被理解为请求范围的度量单位。Content-Length是指定包含于请求或响应中数据的字节长度,例如,Content-Length:382。Content-Disposition:attachment是用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name该变量的值。

  运行download.php文件,效果如下图所示。从图中可以看到文件按照预想的方式被提示下载,单击"保存"按钮将文件保存在本地。

详解PHP文件下载的原理和实现的更多相关文章

  1. 淘宝JAVA中间件Diamond详解(2)-原理介绍

    淘宝JAVA中间件Diamond详解(二)---原理介绍 大家好,通过第一篇的快速使用,大家已经对diamond有了一个基本的了解.本次为大家带来的是diamond核心原理的介绍,主要包括server ...

  2. [转帖]万字详解Oracle架构、原理、进程,学会世间再无复杂架构

    万字详解Oracle架构.原理.进程,学会世间再无复杂架构 http://www.itpub.net/2019/04/24/1694/ 里面的图特别好 数据和云 2019-04-24 09:11:59 ...

  3. SpringCloud 详解配置刷新的原理 使用jasypt自动加解密后 无法使用 springcloud 中的自动刷新/refresh功能

    之所以会查找这篇文章,是因为要解决这样一个问题: 当我使用了jasypt进行配置文件加解密后,如果再使用refresh 去刷新配置,则自动加解密会失效. 原因分析:刷新不是我之前想象的直接调用conf ...

  4. [转帖]详解Linux系统inode原理--硬链接、软链接、innodb大小和划分等

    详解Linux系统inode原理--硬链接.软链接.innodb大小和划分等 原创 波波说运维 2019-07-17 00:03:00 https://www.toutiao.com/i6713116 ...

  5. RocketMQ详解(一)原理概览

    专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...

  6. 详解PHP的执行原理和流程

    简介 先看看下面这个过程: • 我们从未手动开启过PHP的相关进程,它是随着Apache的启动而运行的: • PHP通过mod_php5.so模块和Apache相连(具体说来是SAPI,即服务器应用程 ...

  7. sed 增删改查详解以及 sed -i原理

    我为什么要详细记录sed命令:     sed 擅长取行.工作中三剑客使用频率最高,本篇文章将对sed命令常用的 增,删,改,查 进行详细讲解,以备以后工作中遗忘了查询,sed命令是作为运维人员来说, ...

  8. Android 异步通信:图文详解Handler机制工作原理

    前言 在Android开发的多线程应用场景中,Handler机制十分常用 今天,我将图文详解 Handler机制 的工作原理,希望你们会喜欢 目录 1. 定义 一套 Android 消息传递机制 2. ...

  9. JS006. 详解自执行函数原理与数据类型的快速转换 (声明语句、表达式、运算符剖析)

    今天的主角: Operator Description 一元正值符 " + "(MDN) 一元运算符, 如果操作数在之前不是number,试图将其转换为number. 圆括号运算符 ...

随机推荐

  1. IJCAI 2019 Analysis

    IJCAI 2019 Analysis 检索不到论文的关键词:retrofitting word embedding Getting in Shape: Word Embedding SubSpace ...

  2. EC

  3. IFB上挂载NETEM

    转发虚拟网卡的ingress 建立虚拟网卡的ingress转发到ifb0(每一个Pod): tc qdisc add dev calixxxxxxxxxxx ingress tc filter add ...

  4. 【flask】表单-上传文件

    依赖: flask-wtf upload_case.html <!DOCTYPE html> <html lang="en"> <head> & ...

  5. [转] javascript 正则表达式提取数字使用

    简述: 测试了一下js的正则表达式函数match 用来从一个字符串里挑出非0开头的数字, 放入一个array里, 之后join(',')之后输出 知识点: 1. 用match函数, 提取一个字符串当中 ...

  6. 更新操作 关于json字符串的拼接、json字符串与json对象之间的转换

    更新操作  后台 /** * 更新人员 * @return "updateSdr" */ public String updateTheSdr(){ jsonstr = " ...

  7. LeetCode.1021-删除最外面的括号(Remove Outermost Parentheses)

    这是小川的第380次更新,第408篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第242题(顺位题号是1021).有效的括号字符串为空(""),&qu ...

  8. mysql注入常用函数

    system_user()  系统函数名 user()   用户名 current_user()   当前用户名 session_user()    连接数据库的用户名 database()   数据 ...

  9. 【神经网络与深度学习】用训练好的caffemodel来进行分类

    现在我正在利用imagenet进行finetune训练,待训练好模型,下一步就是利用模型进行分类.故转载一些较有效的相关博客. 博客来源:http://www.cnblogs.com/denny402 ...

  10. python 并发编程 基于gevent模块实现并发的套接字通信

    之前线程池是通过操作系统切换线程,现在是程序自己控制,比操作系统切换效率要高 服务端 from gevent import monkey;monkey.patch_all() import geven ...