问题
java后台接收一张jpg格式图片,发现其在windows下可以正常打开并显示图片内容,但在Ubuntu下打开却提示Error interpreting JPEG image file (Not a JPEG file: starts with 0x89 0x50)
。如下图所示:
提示该文件不是JPEG图像文件,文件开头两个字节分别是0x89、0x50。
解决办法
通过维基百科List_of_file_signatures了解到,这两个字节开头的文件签名应该是png文件格式,将文件后缀名修改为png,再打开文件就可以正常显示。
为此在后台接口增加判断文件签名的逻辑,防止前端提交的后缀名并不是文件的真正格式(不仅限于图片)。
对于特意伪造文件头信息的恶意文件,下列逻辑无法起到甄别作用。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class filetools
{
public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();
static
{
getAllFileType();
}
private static void getAllFileType()
{
FILE_TYPE_MAP.put("jpg(JFIF)", "^FFD8FFE000104A4649460001"); // jpg JFIF file format
FILE_TYPE_MAP.put("jpg(Exif)", "^FFD8FFE1.{4}457869660000"); // jpg Exif file format
FILE_TYPE_MAP.put("jpeg", "^FFD8FFEE"); // jpeg
FILE_TYPE_MAP.put("png", "^89504E470D0A1A0A"); // PNG (png)
FILE_TYPE_MAP.put("bmp", "^424D"); // Windows Bitmap (bmp)
FILE_TYPE_MAP.put("mp4", "^000000206674797069736F6D"); // ISO Base Media file (MPEG-4)
}
public final static String getFileByFile(File file)
{
String filetyp = null;
byte[] fileheader = new byte[15]; // 只读取前面15个字节,依据实际需要读取一定的字节判断即可
try
{
InputStream is = new FileInputStream(file);
is.read(fileheader);
filetyp = getFileTypeByStream(fileheader);
is.close();
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return filetyp;
}
public final static String getFileTypeByStream(byte[] b)
{
String filetypeHex = String.valueOf(getFileHexString(b));
Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
while (entryiterator.hasNext())
{
Entry<String, String> entry = entryiterator.next();
String fileTypeHexValue = entry.getValue();
Pattern p = Pattern.compile(fileTypeHexValue);
Matcher m = p.matcher(filetypeHex.toUpperCase());
if (m.find()) // 只判断是否匹配成功一个
{
if (0 == m.start()) // 判断是否开头匹配
return entry.getKey();
}
}
return "unknow type";
}
public final static String getFileHexString(byte[] b)
{
StringBuilder stringBuilder = new StringBuilder();
if (b == null || b.length <= 0)
{
return null;
}
for (int i = 0; i < b.length; i++)
{
int v = b[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2)
{
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public static void main(String[] args)
{
File f = new File("/home/alderaan/111.jpg");
if (f.exists())
{
String filetype = getFileByFile(f);
System.out.println(filetype);
} else
{
System.out.println(f.getPath() + " not found!");
}
}
}