pub_httpdown.php,php实现文件下载

近期搞了一个安卓的客户端,想把它挂到站点上提供下载,整理实现思路如下:

(1).浏览器发送一个请求,请求访问服务器中的某个网页(如:down.php)

(2).运行该文件的时候,必然要把将要被下载的文件读入内存当中,通过fopen()函数完成该动作

(3).从内存当中读取文件,通过fread()函数完成该动作

(4).把读到的内容输出到客户端

需要注意的是,如果文件较大,文件应该是被分成多段返回给客户端的,并不是等文件在服务端全部读取完毕后,一次性返回给客户端,因为这样子会增加服务器的负荷。

所以我们需要在php代码中设置一次读取的字节数,比如我在下面的代码中通过$buffer=1024设置一次读取的字节数,每读取一次,就输出数据(即返回给浏览器)

具体实现如下,我把代码贴出来,代码都做了详细的注释,保证能看明白

public function index()

{

$file_name="Kl博客.apk";

//用以解决中文不能显示出来的问题

$file_name=iconv("utf-8","gb2312",$file_name);

$file_sub_path=$_SERVER['DOCUMENT_ROOT']./admin.php?s=."/Uploads/DownFile/";

$file_path=$file_sub_path.$file_name; //完整的文件路径

//首先要判断给定的文件存在与否

if(!file_exists($file_path)){

echo "来晚了,文件不存在";

}

else

{

$fp=fopen($file_path,"r"); //以只读的方式打开文件

$file_size=filesize($file_path);//得到文件大小

//下载文件需要用到的头

Header("Content-type: application/octet-stream"); //告诉浏览器这是一个文件流格式的文件

Header("Accept-Ranges: bytes"); //告诉客户端浏览器返回的文件大小是按照字节进行计算的

Header("Content-length:".$file_size); //告诉浏览器返回的文件大小

Header("Content-Disposition: attachment; filename=".$file_name); //告诉浏览器文件的名称

$buffer=1024; //设置缓冲区大小

$file_count=0; //读取到的文件大小变量

//向浏览器返回数据

while(!feof($fp) && $file_count

$file_con=fread($fp,$buffer); //读到一个缓冲区文件的大小

$file_count+=$buffer; //累积读到的文件大小

echo $file_con; //直接向浏览器输出

}

//echo fread($fp, $file_size);//小文件可以直接一次性读完

fclose($fp); //可以把缓冲区内最后剩余的数据输出到磁盘文件中,并释放文件指针和有关的缓冲区

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简单的网络下载文件程序。 WSADATA wdata; WSAStartup(MAKEWORD(2,2),&wdata); int sockfd; char buffer[1024]; struct sockaddr_in server_addr; struct hostent *host; int portnumber,nbytes; char host_addr[256]; char host_file[1024]; char local_file[256]; FILE * fp; char request[1024]; int isend, totalsend; int i; char * pt; memset(host_file,0,sizeof(host_file)); memcpy(host_file,"down/HB_EHSniffer36_ljh.rar",strlen("down/HB_EHSniffer36_ljh.rar")+1); if((host=gethostbyname("nmas.onlinedown.net"))==NULL)/*取得主机IP地址*/ { fprintf(stderr,"Gethostname error, %s\n", strerror(errno)); exit(1); } /* 客户程式开始建立 sockfd描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)/*建立SOCKET连接*/ { fprintf(stderr,"Socket Error:%s\a\n",strerror(errno)); exit(1); } /* 客户程式填充服务端的资料 */ memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(80); server_addr.sin_addr=*((struct in_addr *)host->h_addr); /* 客户程式发起连接请求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)/*连接网站*/ { fprintf(stderr,"Connect Error:%s\a\n",strerror(errno)); exit(1); } memset(request,0,1024); sprintf(request,"GET /%s HTTP/1.1\r\nAccept: */*\r\nCache-Control: no-cache\r\nConnection: close\r\nHost: %s\r\nPragma: no-cache\r\nReferer: http://www.onlinedown.net/soft/15450.htm\r\nRange: bytes=0-\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; )\r\n\r\n" ,host_file,"nmas.onlinedown.net"); printf("%s", request);/*准备request,将要发送给主机*/
鸣谢 首先要感谢linus,给了我们一个可以自由翱翔的平台; 其次,要感谢网络上千万的linux/windows先行者,给予的有意或无意的指点和帮助; 再次,感谢陈皓兄的《跟我一起写makefile》,引导我走过了makefile的迷雾。后来发现于凤昌兄译的《GNU Make使用手册》,也有颇多受益。 背景 从2004年,我在一个公司作服务端软件的开发,要支持linux/windows平台,主要是为了容易维护,就设计、开发了这一套比较常用的类。 2005一直在windows下作IPTV的开发,在2006年底,又回到linux下作IPV6下IPTV的开发。在空闲时间,看看两年前的那些零散类文件,开始整理这些类成库,并写了简单的使用和测试范例,放在网上和朋友们共享。 由于早期的平台从windows98和VC6.0,redhat8.0,经历了些变迁,没有太多的时间再一一仔细测试,就用现在的windowsXP和VS.2003,Fedaro Core4.0作的测试。 主要是为了相互学习,希望能和朋友们共同进步!如有引用,请标明出处,会不胜感激!禁止商业性的书籍的引用!很多不良的作者,完全是在骗钱。 功能简介 通用于linux/windows平台C++的应用。 主要是对一些系统功能,进行了简洁封装。 主要有读写锁类, 线程类, 线程池类, 定时器类, socket1.1的封装类, ini文件类, txt文件类, 可删除内容的文件类, 查找文件类, 调试输出类, 字符串类, 同步的普通队列和优先级队列类, 智能指针和内存自动管理类,数据库类. 特别声明:因为环境限制,这次测试代码中,没有测试数据库类。我以前也只是在PostgreSQL,SQL Server2000和Acess2000中实际用过。如有朋友用到,请自行修改、测试。 这些类的风格,与个人习惯密切相关。推荐QT,跨平台的类库,还是不错的;ACE就太难使用了! 编译和运行: 1. windwos下,用vs2003打开pub下的test.sln文件,所有的测试程序和类库文件就载入,编译即可。其它程序引用库时,请选中/MDd选项。 2. linux下,执行pub下的Makefile文件,编译即可。如果没有安装PostgreSql,数据库部分会编译不过。 关于inline函数 我写的这些类的函数,大部分是可以写成inline函数的,对性能提高也有很大的帮助。但是,GCC和VC的不同版本编译器的支持程度不同,可能会编译不过,所以就都没有为提高效率而写inline函数。依赖于编译器,对跨平台的程序来说,也比较麻烦! 不过,现在的硬件系统,对这些小小的性能提升,也感觉不出来的。 如有需要,请自行改写! 关于异常和错误处理 也是仁者见仁,智者见智! 习惯于C开发的朋友,大概喜欢函数错误时返回错误码。函数有返回值,就要处理,就使程序逻辑较为复杂,看去也比较的混乱。 我则喜欢用异常代替,主要是代码简洁和逻辑清晰。异常抛掷,会使流程很简洁,只显示执行正确时的流程,错误集中处理 对于那些失败即意味着中止的一个操作,我让其抛掷异常。如果是正常的分支流程,则用返回失败值。就我遇到的情况,大部分则为操作失败,调用的流程一般都要中止的。 这个判断也是比较难下的。放在一个局部,异常可能导致操作中止;但放在更上一层,则异常又可能是正确程序流程处理。 bug的反馈和修改支持 如果有重大的错误需要偶修正,请发到linhweikuo@hotmail.com的邮箱,尽量说明问题的现象,我会在一周内解决的(如果工作比较紧急的时候,不能即时就处理的)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值