自定义文件类型

之前公司的项目需要自定义一种文件类型,但是由于存储的是普通文本文件,文件上传后用php的finfo判断文件类型的时候还是会被识别为txt类型,今天看到了,在linux下可以通过修改/etc/magic 文件来实现自定义文件类型,通过man magic可以查看到详细的自定义文件格式的帮助信息。问题来了,windows下怎么实现呢,貌似finfo扩展使用的是自己的magic库,也就是说我们如果能够修改的话,即使是windows下这种方式依然是可行的。

finfo_open()

<?php
$fo = finfo_open('FILEINFO_MIME_TYPE')
$type = finfo_file($fo, 'test');

通过上面简单的代码,我们就可以获取到文件的mime信息,但是只能获取到finfo扩展定义的, 如果我们想自己定义呢?仔细阅读finfo_open() 我们可以看到,第二个参数是让指定magic_file, 这又是什么呢?

magic_file

包含了多种文件特征签名的文件。

通过阅读维基百科文档关于文件格式的内容 我们可以发现,文件格式的识别,一共有3种方式

  • 通过文件的扩展名, .exe , .txt , .rmvb , windows 操作系统采用的方式。

  • 特征签名, unix 类及其派生类操作系统

    特征签名是通过在文件的特定位置,一般是前几个字节,放置一些描述该文件的信息,来进行识别。例如Gif 图片通过前六个字节来进行识别GIF87a, GIF89a

  • 元数据

    将文件格式信息存放到磁盘特定的位置。

    采用这种方式,元数据与文件本身份开存放。此法的缺点是可移植性差。因为不同的文件系统之间元数据可能需要转换。

自定义文件类型

通过上面的介绍,我们应该知道计算机是怎么识别不同类型的文件了,现在我们就是要自己创建一个属于自己的文件类型。通过查看php的源码我们应该能够看到,php内置的magic库使用的是来自Fossies 软件源中 file 这个软件,下载解压之后,我们能够在magic/Magdir/ 下面发现很多文件,这些文件中就定义了很多种文件的特征签名。 我们可以根据man magic 中介绍的规则定义自己的类型。

0       search/1/c      =akg                  akg file
!:mime  text/akg
//最简单的一种定义方式,适合普通文件文件
  • 普通文本类

    如果我们自定义的文件类型是,普通文本文件,类似脚本文件这种,自然是很好定义的,只需要在文件头部,写一些特定的字符就行了。

  • 二进制类

    如果我们定义的文件并不想被普通文本编辑器打开,那么我们可以使用php的一对函数来写入,他们的功能是负责将数据转换成二进制,并解码二进制文件,他们是 pack 和 unpack

    可以参考这篇文章 pack()&unpack() &ord()

自定义magic_file的使用方式

我们有两种方式使用,自定义的magic文件。

  • 环境变量,Linux 下我们可以通过简单的使用export MAGIC='/path/to/magic_file' 来定义环境变量,但是重启之后会失效,也可以通过在/etc/profile 中永久定义。windows 下就不用说了吧。
  • 指定文件路径,这种方式的话,我们只能指定一个文件了,所以我们有必要把所有的特征签名整合到一个文件中去,然后finfo_open('FILEINFO_MIME_TYPE', '/path/to/magic_file')