PHP控制Header信息以强制转换文件类型表

本文介绍如何使用PHP实现文件下载功能,并列举了多种文件类型的MIME类型,包括文档、图片、视频等,适用于不同格式文件的网络传输。
头来提供一个推荐的文件名,强迫浏览器显示保存对话框.
<?php
header(’Content-type: application/pdf’);
header(’Content-Disposition: attachment; filename=”downloaded.pdf”‘);
readfile(’original.pdf’);
?>


header 中Content-type的种类 Content-type 的说明:

'hqx' -> 'application/mac-binhex40',
'cpt' -> 'application/mac-compactpro',
'doc' -> 'application/msword',
'bin' -> 'application/octet-stream',
'dms' -> 'application/octet-stream',
'lha' -> 'application/octet-stream',
'lzh' -> 'application/octet-stream',
'exe' -> 'application/octet-stream',
'class' -> 'application/octet-stream',
'so' -> 'application/octet-stream',
'dll' -> 'application/octet-stream',
'oda' -> 'application/oda',
'pdf' -> 'application/pdf',
'ai' -> 'application/postscript',
'eps' -> 'application/postscript',
'ps' -> 'application/postscript',
'smi' -> 'application/smil',
'smil' -> 'application/smil',
'mif' -> 'application/vnd.mif',
'xls' -> 'application/vnd.ms-excel',
'ppt' -> 'application/vnd.ms-powerpoint',
'wbxml' -> 'application/vnd.wap.wbxml',
'wmlc' -> 'application/vnd.wap.wmlc',
'wmlsc' -> 'application/vnd.wap.wmlscriptc',
'bcpio' -> 'application/x-bcpio',
'vcd' -> 'application/x-cdlink',
'pgn' -> 'application/x-chess-pgn',
'cpio' -> 'application/x-cpio',
'csh' -> 'application/x-csh',
'dcr' -> 'application/x-director',
'dir' -> 'application/x-director',
'dxr' -> 'application/x-director',
'dvi' -> 'application/x-dvi',
'spl' -> 'application/x-futuresplash',
'gtar' -> 'application/x-gtar',
'hdf' -> 'application/x-hdf',
'js' -> 'application/x-javascript',
'skp' -> 'application/x-koan',
'skd' -> 'application/x-koan',
'skt' -> 'application/x-koan',
'skm' -> 'application/x-koan',
'latex' -> 'application/x-latex',
'nc' -> 'application/x-netcdf',
'cdf' -> 'application/x-netcdf',
'sh' -> 'application/x-sh',
'shar' -> 'application/x-shar',
'swf' -> 'application/x-shockwave-flash',
'sit' -> 'application/x-stuffit',
'sv4cpio' -> 'application/x-sv4cpio',
'sv4crc' -> 'application/x-sv4crc',
'tar' -> 'application/x-tar',
'tcl' -> 'application/x-tcl',
'tex' -> 'application/x-tex',
'texinfo' -> 'application/x-texinfo',
'texi' -> 'application/x-texinfo',
't' -> 'application/x-troff',
'tr' -> 'application/x-troff',
'roff' -> 'application/x-troff',
'man' -> 'application/x-troff-man',
'me' -> 'application/x-troff-me',
'ms' -> 'application/x-troff-ms',
'ustar' -> 'application/x-ustar',
'src' -> 'application/x-wais-source',
'xhtml' 'application/xhtml+xml',
'xht' -> 'application/xhtml+xml',
'zip' -> 'application/zip',
'au' -> 'audio/basic',
'snd' -> 'audio/basic',
'mid' -> 'audio/midi',
'midi' -> 'audio/midi',
'kar' -> 'audio/midi',
'mpga' -> 'audio/mpeg',
'mp2' -> 'audio/mpeg',
'mp3' -> 'audio/mpeg',
'aif' -> 'audio/x-aiff',
'aiff' -> 'audio/x-aiff',
'aifc' -> 'audio/x-aiff',
'm3u' -> 'audio/x-mpegurl',
'ram' -> 'audio/x-pn-realaudio',
'rm' -> 'audio/x-pn-realaudio',
'rpm' -> 'audio/x-pn-realaudio-plugin',
'ra' -> 'audio/x-realaudio',
'wav' -> 'audio/x-wav',
'pdb' -> 'chemical/x-pdb',
'xyz' -> 'chemical/x-xyz',
'bmp' -> 'image/bmp',
'gif' -> 'image/gif',
'ief' -> 'image/ief',
'jpeg' -> 'image/jpeg',
'jpg' -> 'image/jpeg',
'jpe' -> 'image/jpeg',
'png' -> 'image/png',
'tiff' -> 'image/tiff',
'tif' -> 'image/tiff',
'djvu' -> 'image/vnd.djvu',
'djv' -> 'image/vnd.djvu',
'wbmp' -> 'image/vnd.wap.wbmp',
'ras' -> 'image/x-cmu-raster',
'pnm' -> 'image/x-portable-anymap',
'pbm' -> 'image/x-portable-bitmap',
'pgm' -> 'image/x-portable-graymap',
'ppm' -> 'image/x-portable-pixmap',
'rgb' -> 'image/x-rgb',
'xbm' -> 'image/x-xbitmap',
'xpm' -> 'image/x-xpixmap',
'xwd' -> 'image/x-xwindowdump',
'igs' -> 'model/iges',
'iges' -> 'model/iges',
'msh' -> 'model/mesh',
'mesh' -> 'model/mesh',
'silo' -> 'model/mesh',
'wrl' -> 'model/vrml',
'vrml' -> 'model/vrml',
'css' -> 'text/css',
'html' -> 'text/html',
'htm' -> 'text/html',
'asc' -> 'text/plain',
'txt' -> 'text/plain',
'rtx' -> 'text/richtext',
'rtf' -> 'text/rtf',
'sgml' -> 'text/sgml',
'sgm' -> 'text/sgml',
'tsv' -> 'text/tab-separated-values',
'wml' -> 'text/vnd.wap.wml',
'wmls' -> 'text/vnd.wap.wmlscript',
'etx' -> 'text/x-setext',
'xsl' -> 'text/xml',
'xml' -> 'text/xml',
'mpeg' -> 'video/mpeg',
'mpg' -> 'video/mpeg',
'mpe' -> 'video/mpeg',
'qt' -> 'video/quicktime',
'mov' -> 'video/quicktime',
'mxu' -> 'video/vnd.mpegurl',
'avi' -> 'video/x-msvideo',
'movie' -> 'video/x-sgi-movie',
'ice' -> 'x-conference/x-cooltalk'

<think>我们正在解决PHP下载PNG文件时垂直分辨率被重定为96的问题。用户希望保持原始的垂直分辨率(dpi)不被改变。问题分析:当使用PHP下载PNG文件时,有时会发现图像的垂直分辨率(通常存储在图像的元数据中)被重置为96dpi。这可能是由于在图像处理过程中(例如使用GD库)重新生成了图像,而GD库默认使用96dpi。解决方案思路:1.使用其他图像处理库(如Imagick)可能可以保留原始分辨率。2.如果必须使用GD库,我们需要在生成图像后手动设置分辨率。3.确保在输出图像头部时包含正确的分辨率信息。然而,需要注意的是,PNG文件的分辨率信息存储在pHYs块中。该块包含像素的物理大小(每单位像素的水平和垂直像素数,以及单位指示符)。在GD库中,默认情况下不会设置这个块,或者设置为96dpi(大约为3780像素/米,因为1英寸=0.0254米,所以96dpi=96/0.0254≈3780像素/米)。具体步骤(使用GD库):1.读取原始PNG文件,获取其原始分辨率(如果有的话)。2.创建一个新的图像资源(如果需要处理图像,否则直接使用原始图像)。3.使用GD库处理图像后,在输出之前,通过imagepng函数写入图像数据,但imagepng函数本身不提供设置分辨率的参数。4.因此,我们需要在生成图像后,手动修改图像数据,添加pHYs块。但GD库不直接支持修改pHYs块。所以可能需要使用其他方法:方法一:使用Imagick扩展(推荐,如果服务器支持)方法二:在输出图像数据后,手动在二进制数据中插入pHYs块(较为复杂)方法一:使用ImagickImagick可以方便地设置图像的分辨率。方法二:手动修改PNG文件(不推荐,因为容易出错)我们可以先使用GD生成图像,然后通过直接修改二进制数据来添加pHYs块。但这种方法需要对PNG文件结构非常了解。因此,我们优先考虑使用Imagick。使用Imagick的示例代码:假设我们要将一个原始图像(可能是从上传或本地读取)处理后下载,并保持原始分辨率(或者设置特定的分辨率)。步骤:1.使用Imagick读取原始图像。2.设置所需的分辨率(例如300dpi)。3.输出图像。注意:如果原始图像已经有分辨率,我们可以读取并保持它。示例代码(设置垂直和水平分辨率为300dpi):```php<?php//假设原始图像路径$imagePath='path/to/your/image.png';//创建一个Imagick对象$image=newImagick($imagePath);//获取原始分辨率(可选,如果我们想保留原始分辨率,但Imagick读取时应该会保留)//但是如果我们想改变分辨率,可以设置//设置分辨率为300dpi(注意:Imagick中设置分辨率使用单位是像素每英寸)$image->setImageResolution(300,300);//注意:setImageResolution设置的是图像的分辨率,但输出PNG时,还需要确保写入pHYs块。//我们还需要设置图像单位(0:未知,1:像素每米,2:像素每英寸)。PNG的pHYs块使用像素每米。//但是Imagick在输出PNG时会自动将dpi转换为像素每米(因为1英寸=0.0254米,所以300dpi=300/0.0254≈11811像素每米)。//或者,我们也可以直接设置像素每米(但Imagick没有直接设置pHYs块的函数,所以最好用setImageResolution设置dpi,然后由Imagick自动转换)//输出图像header('Content-Type:image/png');echo$image;//或者下载文件//如果我们想强制下载//header('Content-Type:application/octet-stream');//header('Content-Disposition:attachment;filename="image.png"');//echo$image;?>```然而,如果服务器不支持Imagick,我们只能使用GD库。那么如何解决?使用GD库时,我们可以尝试以下方法:1.在创建图像后,使用imagesx和imagesy获取宽高,然后使用imagepng输出。2.但imagepng输出后,我们无法直接修改分辨率。因此,我们可以将图像输出到缓冲区,然后手动修改二进制数据,添加pHYs块。添加pHYs块的方法:PNG文件由一系列块组成。在IHDR块之后,我们可以插入pHYs块。pHYs块的结构如下:-长度:9字节(4字节长度,4字节类型,1字节单位)-类型:'pHYs'(4字节)-数据:4字节水平像素数(每米),4字节垂直像素数(每米),1字节单位(0:无单位,1:每米)例如,96dpi相当于3780像素/米(96/0.0254≈3780)。步骤:1.使用GD生成图像到缓冲区。2.获取缓冲区内容。3.在IHDR块之后插入pHYs块。4.输出修改后的内容。但是,这种方法需要精确地定位IHDR块之后的位置,并且要重新计算CRC校验码。实现起来比较复杂。参考代码(GD库,手动添加pHYs块):```php<?php//创建图像$im=imagecreatefrompng('original.png');//或者创建一个新的图像//开始输出缓冲ob_start();imagepng($im);$image_data=ob_get_clean();imagedestroy($im);//修改图像数据,添加pHYs块//目标分辨率(以像素每米示),例如300dpi->300/0.0254≈11811$dpi=300;$pixelsPerMeter=round($dpi/0.0254);//构建pHYs块$physChunk='pHYs';//块类型//数据:4字节水平像素/米,4字节垂直像素/米,1字节单位(1=每米)$physData=pack('NNC',$pixelsPerMeter,$pixelsPerMeter,1);//块长度:9字节$chunkLength=pack('N',9);//计算pHYs块的CRC:先计算类型+数据的CRC$crc=crc32($physChunk.$physData);$chunkCRC=pack('N',$crc);//完整的pHYs块$physChunkFull=$chunkLength.$physChunk.$physData.$chunkCRC;//在IHDR块之后插入pHYs块//PNG文件头8字节,然后第一个块是IHDR,长度为13字节(所以IHDR块总长度:4(长度)+4(类型)+13(数据)+4(CRC)=25字节)//所以我们在第8+25=33个字节后插入$before=substr($image_data,0,33);//包括文件头和IHDR块$after=substr($image_data,33);//插入pHYs块$newImageData=$before.$physChunkFull.$after;//输出header('Content-Type:image/png');header('Content-Disposition:attachment;filename="image.png"');echo$newImageData;?>```但是,这种方法有风险:-如果原始图像已经包含pHYs块,我们不应该再插入,而应该修改已有的pHYs块。但是上面的代码没有检查。-如果原始图像有其他块(如PLTE,或者多个IDAT块),插入位置可能不正确。因此,更健壮的做法是解析PNG文件结构,找到在IDAT块之前的位置插入pHYs块(或者替换已有的pHYs块)。但这需要更复杂的代码。考虑到复杂性和健壮性,如果可能,建议使用Imagick。结论:1.如果服务器支持Imagick,使用Imagick的setImageResolution方法设置分辨率。2.如果只能使用GD库,且对分辨率要求不严格,可以忽略此问题(因为96dpi是屏幕显示的标准,打印时通常需要更高分辨率,但PNG文件本身的分辨率信息并不影响图像数据,只作为元数据)。3.如果必须使用GD库且必须修改分辨率,可以尝试上述手动插入pHYs块的方法,但要注意其局限性和风险。针对用户问题,推荐使用Imagick扩展。相关问题:1.如何在PHP中安装Imagick扩展?2.除了Imagick,还有其他方法可以保持PNG文件的分辨率吗?3.如何获取原始PNG文件的分辨率信息?4.在GD库中,能否在创建图像时就设置分辨率?</think>### PHP下载PNG文件时垂直分辨率重置为96的解决方案 当使用PHP下载PNG文件时,垂直分辨率被重置为96 DPI的问题通常发生在使用GD库处理图像时。这是因为GD库默认将分辨率设为96 DPI。以下是完整的解决方案: #### 方法1:使用Imagick扩展(推荐) ```php <?php $filePath = 'path/to/your/image.png'; // 创建Imagick对象 $image = new Imagick($filePath); // 获取原始分辨率(可选) $res = $image->getImageResolution(); $x_res = $res['x']; $y_res = $res['y']; // 设置分辨率(单位:像素/英寸) $image->setImageResolution(300, 300); // 替换为所需DPI // 输出图像 header('Content-Type: image/png'); header('Content-Disposition: attachment; filename="downloaded.png"'); echo $image; ?> ``` **优点**:精确控制分辨率,保留所有元数据[^2]。 #### 方法2:使用GD库+手动注入分辨率数据 ```php <?php $filePath = 'path/to/your/image.png'; // 计算像素/米值(300 DPI = 11811 像素/米) $dpi = 300; $ppm = round($dpi * 100 / 2.54); // 转换为像素/米 // 创建图像资源 $im = imagecreatefrompng($filePath); // 生成图像二进制数据 ob_start(); imagepng($im); $image_data = ob_get_clean(); imagedestroy($im); // 构建pHYs块(PNG分辨率数据块) $physChunk = 'pHYs'; // 块标识 $physData = pack('NNC', $ppm, $ppm, 1); // 水平/垂直分辨率+单位(1=米) $chunkLength = pack('N', 9); // 数据长度(9字节) $crc = crc32($physChunk . $physData); $chunkCRC = pack('N', $crc); // 在IHDR块后插入pHYs块 $newImageData = substr($image_data, 0, 33) . // PNG头+IHDR块 $chunkLength . $physChunk . $physData . $chunkCRC . substr($image_data, 33); // 输出文件 header('Content-Type: image/png'); header('Content-Disposition: attachment; filename="downloaded.png"'); echo $newImageData; ?> ``` #### 关键注意事项: 1. **分辨率单位**:PNG使用$ \text{像素/米} $存储分辨率,转换公式为: $$ \text{像素/米} = \frac{\text{DPI} \times 100}{2.54} $$ 例如:300 DPI = $ \frac{300 \times 100}{2.54} \approx 11811 \text{ 像素/米} $ 2. **GD库限制**:GD会剥离所有元数据,包括: - EXIF信息 - ICC颜色配置文件 - 文本注释[^1] 3. **服务器配置**: ```bash # 安装Imagick扩展 sudo apt-get install php-imagick sudo systemctl restart apache2 ``` #### 验证方法 使用`exiftool`检查分辨率: ```bash exiftool downloaded.png | grep Resolution # 正确输出:X Resolution: 300 | Y Resolution: 300 ``` #### 何时选择哪种方案 | 场景 | 推荐方案 | |------|----------| | 需保留所有元数据 | Imagick | | 服务器不支持Imagick | GD+手动注入 | | 批量处理大量图像 | Imagick | | 简单快速处理 | GD库 | 通过以上方法,您可以精确控制PNG文件的分辨率,避免被重置为默认的96 DPI。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值