开发中大家都是使用的utf8编码,昨天遇到一个奇坑,本是一件很小的问题,解决也浪费了个吧小时。废话不多说,植入正题:

文件下载方式:通过header二进制流文件下载

需求: 文件上传保留文件名不变

数据字段file_url值:/public/upload/files/2019/04-29/中文测试包.rar

linux(Ubuntu 18.04.2 LTS )文件目录:/home/wwwroot/web/public/upload/files/2019/04-29

windows10文件目录:D:\web\public\upload\files\2019\04-29\中文测试包.rar

我们先看下,windows下的文件下载:

$file_path = $_SERVER['DOCUMENT_ROOT'] . $file_name;//比如windows下这里我的是 "D:/web/public/upload/files/2019/04-29/中文测试包.rar"

//判断如果文件存在,则跳转到下载路径

if (!file_exists($file_path)) {die("文件不存在!");

}$fp = fopen($file_path, "r+") or die('打开文件错误'); //下载文件必须要将文件先打开。写入内存

$file_size = filesize($file_path);//返回的文件流

Header("Content-type:application/octet-stream");//按照字节格式返回

Header("Accept-Ranges:bytes");//返回文件大小

Header("Accept-Length:" . $file_size);//弹出客户端对话框,对应的文件名

Header("Content-Disposition:attachment;filename=" . substr($file_name, strrpos($file_name, '/') + 1));//防止服务器瞬间压力增大,分段读取

$buffer = 1024;while (!feof($fp)) {$file_data = fread($fp, $buffer);echo $file_data;

}fclose($fp);die("下载成功!");?>

文件不存在?神马玩意?。同样的代码ubutun生产环境下:

文件下载成功。神马情况?

原因:windows 系统默认字符集是gbk,项目采用的是uft8编码,中文文件名必须转码才能使用file_exists检测文件,不然报找不到文件:

windows下的解决方式就是上面注释的那一段开启:

$file_name = iconv("utf-8","gbk//IGNORE",$file_name); //特别注意!特别注意!特别注意这里,windows下必须开转码,不然直接文件不存

windows下再次执行后发现下载成功:

那么问题来了。开启后的代码是这样的:

$file_path = $_SERVER['DOCUMENT_ROOT'] . $file_name;//比如windows下这里我的是 "D:/web/public/upload/files/2019/04-29/中文测试包.rar"

//判断如果文件存在,则跳转到下载路径

if (!file_exists($file_path)) {die("文件不存在!");

}$fp = fopen($file_path, "r+") or die('打开文件错误'); //下载文件必须要将文件先打开。写入内存

$file_size = filesize($file_path);//返回的文件流

Header("Content-type:application/octet-stream");//按照字节格式返回

Header("Accept-Ranges:bytes");//返回文件大小

Header("Accept-Length:" . $file_size);//弹出客户端对话框,对应的文件名

Header("Content-Disposition:attachment;filename=" . substr($file_name, strrpos($file_name, '/') + 1));//防止服务器瞬间压力增大,分段读取

$buffer = 1024;while (!feof($fp)) {$file_data = fread($fp, $buffer);echo $file_data;

}fclose($fp);die("下载成功!");?>

在ubutun 服务器上我们执行:

是不是仿佛解决东墙补西墙。ubutun 下字符集可以通过:

cat /usr/share/i18n/SUPPORTED

说明系统支持中文字符,不然上传的压缩包怎么会显示:“中文测试包.rar”。

问题描述:linux系统下验证中文文件file_exists不能是中文,所以不能在上面转码成gbk.

那么问题来了: 如何做到兼容性?

我们知道PHP_OS是 php自带的一个内置常量,返回的是服务器端的操作系统标示,值为(WINNT,WIN32等),比如这样:

echo strtoupper(substr(PHP_OS,0,3))==='WIN'?'windows 服务器':'不是 widnows 服务器';

另外一种通过系统分隔符DIRECTORY_SEPARATOR ,这个也是php自带的一个内置常量,用来显示系统分隔符的命令,

不需要任何定义与包含即可直接使用。在windows下路径分隔符是\(当然/在部分系统上也是可以正常运行的),在linux上路径的分隔符是/,

DIRECTORY_SEPARATOR 这个常量存在的意义就是会根据不同的操作系统来显示不同的分隔符。

使用 DIRECTORY_SEPARATOR 判断操作系统类型比如这样:

echo DIRECTORY_SEPARATOR=='\\'?'windows 服务器':'不是 widnows 服务器';

还有一种方式:

PATH_SEPARATOR 也是一个常量,在linux系统中是一个" : "号,Windows上是一个";"号。

使用 PATH_SEPARATOR 判断操作系统类型比如这样:

echo PATH_SEPARATOR==';'?'windows 服务器':'不是 widnows 服务器';

代码兼容性我们可以验证系统类型,对windows下做判断再决定是否转码操作。

这里重点说哈关于下载后文件打开提示“文件损坏”的问题,期初我也遇到。猜测肯定是在读取文件字节流存在数据丢失,也就是没读取完整:

下面看下这段有问题的代码:有兴趣的朋友可以自己思考哈,问题在哪里?这里我就不说了,相信很多朋友也能找到问题点:

if (!is_file($file_name) && is_readable($file_name)) {die("文件不存在或不可读!");

}//判断如果文件存在,则跳转到下载路径

$file_path = $_SERVER['DOCUMENT_ROOT'] . $file_name;//比如windows下这里我的是 "D:/web/public/upload/files/2019/04-29/中文测试包.rar"

//判断如果文件存在,则跳转到下载路径

if (!file_exists($file_path)) {die("文件不存在!");

}//设置脚本的最大执行时间,设置为0则无时间限制

set_time_limit(0);ini_set('max_execution_time', '0');//通过header()发送头信息

//因为不知道文件是什么类型的,告诉浏览器输出的是字节流

header('content-type:application/octet-stream');//告诉浏览器返回的文件大小类型是字节

header('Accept-Ranges:bytes');//获得文件大小

//$filesize = filesize($filename);//此方法无法获取到远程文件大小

$header_array = get_headers($http_type . $_SERVER['HTTP_HOST'] . $file_name, true);$filesize = $header_array['Content-Length'];//告诉浏览器返回的文件大小

header('Accept-Length:' . $filesize);//告诉浏览器文件作为附件处理并且设定最终下载完成的文件名称

header('content-disposition:attachment;filename=' . substr($file_name, strrpos($file_name, '/') + 1));//针对大文件,规定每次读取文件的字节数为4096字节,直接输出数据

$buffer = 4096;$fp = fopen($file_path, 'rb');//总的缓冲的字节数

$sum_buffer = 0;//只要没到文件尾,就一直读取

while (!feof($fp) && $sum_buffer < $filesize) {echo fread($fp, $buffer);$sum_buffer += $buffer;

}//记录下载

die("下载成功!");?>

有兴趣的朋友可以找下bug,哈哈

php强制下载压缩包损坏,php 通过header下载中文文件名 压缩包损坏或文件不存在的问题...相关推荐

  1. php header下载中文名称,PHP Header下载文件在IE文件名中文乱码问题

    解决PHP Header下载文件在IE文件名中文乱码有两种常见的,一种是是把页面编码改成utf8,另一种是对中文url进入urlencode编码就可以解决了. 解决方案一,我的页面是utf-8编码,代 ...

  2. java ie下载文件名乱码问题_php中强制下载文件的代码(解决了IE下中文文件名乱码问题)...

    中间遇到一个问题是提交的中文文件名直接放到header里在IE下会变成乱码,解决方法是将文件名先urlencode一下再放入header,如下. $file_name = urlencode($_RE ...

  3. 【踩坑】Linux java中ftp下载文件,解压文件损坏,以及图片下载打开只显示下载路径的问题

    [踩坑]Linux java中ftp下载文件,解压文件损坏,以及图片下载打开只显示下载路径的问题 一. 问题重现 二. 问题解决思路 1. 确认是不是上传就导致数据出错了 2. 是不是平台问题 三. ...

  4. 小程序配置阿里云OSS下载文件,在请求头里配置生成强制下载链接,(拿到下载链接可以下载文件至本地)

    小程序配置阿里云OSS下载文件,在请求头里配置生成强制下载链接,(拿到下载链接可以下载文件至本地)(Win10电脑开发环境)**这里只说明小程序端问题**<菜鸡总结大神勿喷!蟹蟹~> 大体 ...

  5. PHP下载docx文档打开时显示 word2007无法打开Office OpenXML 文件

    症状 我自己的PHP,把word文档存入数据库后,再从数据库下载成docx文件:当打开该文件时(Word2007),出现错误提示:"无法打开Office OpenXML 文件 文件名, 因为 ...

  6. 根据URL下载单个图片与批量打包下载图片(文件同理)

    根据url下载图片看起来很简单,做起来还是有点曲折的 首先,直接file_put_content()的话可以下载图片但不知道图片保存在什么位置,所以必须要调用浏览器下载,使用header头. func ...

  7. python下载邮箱附件_基于Python3 下载邮箱附件,并解压到指定文件夹

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -*- encoding: gbk -*- # 目前只测试过网易163邮箱,qq邮箱时间格式与163有 ...

  8. mysql3.5.2 下载_mybatis 3.5.2 jar 下载

    本文更新日期:2019年9月21日 很多人找不到mybatis jar或者下载mybatis jar需要付积分,所以本页面给大家提供一个便捷的下载通道,敬请关注. 一.mybatis 3.5.2版本下 ...

  9. MODIS数据的简介和下载(三)——MODIS数据下载方式(基于MODIS Web Service)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/ESA_DSQ/article/details/70176214 这是MODIS数据的简介和下载的最后 ...

最新文章

  1. linux的网络命令整理 更新中
  2. DX使用随记--ImageComboBoxEdit
  3. jquery ajax json 数据的遍历
  4. Lucene.Net如何实现搜索结果分类统计功能
  5. Win10系统,安装虚拟机,是微软自家的 Hyper-V ?还是轻量级的 Virtual Box ?
  6. python装饰器补充
  7. html5手机签名,html5手写签名
  8. leetcode1292. 元素和小于等于阈值的正方形的最大边长(二分法+前缀和)
  9. 【转】DCMTK开源库类继承结构与DICOM3.0标准元素定义的对应关系图
  10. zzz,zzz,zz9_ZZZ的完整形式是什么?
  11. 虚拟专题:联邦学习 | 联邦可视化:一种隐私保护的可视化新模型
  12. linux指令:软连接与历史命令
  13. 每天进步一点点《ML - 线性回归》
  14. 纯真数据库mysql_纯真数据库下载或自动更新实现
  15. 热血江湖服务器节点位置,热血江湖服务器合并相关说明
  16. SecureCRT解压版使用
  17. android开启wifi热点命令,Android便携式热点的开启状态检测和SSID的获取方法
  18. 怎么在html中加校验,如何通过W3C验证?
  19. Android--设置显示大小导致APP crash
  20. 程序员遇到有远见的丈母娘

热门文章

  1. JAVA语言基础-面向对象(集合框架02List、泛型)
  2. java jdk1.8环境变量的配置
  3. 【Unity 3D】学习笔记三十六:物理引擎——刚体
  4. 算法系列【希尔排序】篇
  5. springboot(十六):使用Jenkins部署Spring Boot
  6. JS获取URL中参数值(QueryString)的4种方法分享
  7. httpd默认配置文件详解
  8. 我的职业规划是什么呢?什么都要写写画画才行
  9. VC2005与IE8的冲突解决
  10. SilverLight 一日两次碰壁