<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-67  評(píng)論-522  文章-0  trackbacks-0
        大象根據(jù)研究與實(shí)際項(xiàng)目經(jīng)驗(yàn),向大家介紹一個(gè)關(guān)于文件類型驗(yàn)證的解決辦法。不清楚的朋友可以了解下,知道的不喜勿噴。
        對(duì)于文件上傳,相信大家都不會(huì)陌生,我們都知道,文件在上傳到服務(wù)器的過(guò)程中,都是以流的形式傳輸?shù)模诤笈_(tái)處理文件上傳的代碼中,獲得這個(gè)流,然后讀取數(shù)據(jù)流將之保存到上傳文件的臨時(shí)目錄中,如果有使用到MongoDB,再將這個(gè)文件存儲(chǔ)到文件系統(tǒng)中。
        大部分的文件上傳都是通過(guò)HTML的上傳組件完成的,而業(yè)務(wù)需求往往是有類型要求的,比如只允許上傳jpggifpng類型的圖片,或者是只允許上傳Office文檔等等,雖然可以用JavaScript對(duì)上傳文件做一些類型驗(yàn)證之類的控制,但還是不能完全做到過(guò)慮。這時(shí),就需要在后臺(tái),用代碼來(lái)進(jìn)一步完成這個(gè)驗(yàn)證工作。
        到底通過(guò)什么方式可以做到正確驗(yàn)證呢?答案就是通過(guò)文件的頭部信息,通過(guò)大量測(cè)試,大象發(fā)現(xiàn)每種類型的文件,他們最開(kāi)始的一段信息都是一樣的,比如Office97~03,它的頭四位16進(jìn)制信息就是d0 cf 11 e0,而Office2007則是50 4b 03 04PDF25 50 44 46,大家可以多用這樣的文件分別測(cè)試一下,看看前四位16進(jìn)制信息是不是都是一樣的。當(dāng)然這其中也有個(gè)別情況,比如jpg類型的圖片,它的前四位16進(jìn)制信息就有兩種一個(gè)是ff d8 ff e0,另一個(gè)是ff d8 ff e1,區(qū)別是最后一位。知道了這些,我們就有一個(gè)方向了。
        可能有同學(xué)有疑問(wèn)了,為什么只取前四位,不是六位或八位呢?這是因?yàn)椋笙蟾鶕?jù)反復(fù)測(cè)試發(fā)現(xiàn),從第五位開(kāi)始到第八位,同一種類型的文件,在這幾位里面很有一些存在區(qū)別,像圖片以及pdf,這種現(xiàn)象很多,為了避免同一類型的文件,因?yàn)檫@一些小的不同,要定義N多檢測(cè)頭信息,這樣做似乎沒(méi)有必要,因此大象才建議取前四位作為類型檢測(cè)的依據(jù)。
        不過(guò)說(shuō)了這么多,還是沒(méi)講怎么做,這顯然不是大象的風(fēng)格,大象一般都從實(shí)際出發(fā),用代碼來(lái)說(shuō)話。

    package com.bolo.util;

    public class FileValidateUtil {

        public static boolean validateType(byte[] b, String customTypes) {

           if (b != null) {

               int size = b.length;

               String hex = null;

               StringBuilder contentType = new StringBuilder();

               for (int i = 0; i < size; i++) {

                  hex = Integer.toHexString(b[i] & 0xFF);

                  if (hex.length() == 1) {

                      hex = "0" + hex;

                  }

                  contentType.append(hex);

                  if (i > 2)

                      break;

               }

               if (customTypes.indexOf(contentType.toString()) > -1) {

                  return Boolean.TRUE;

               }

           }

           return Boolean.FALSE;

        }

    }
        上面這段代碼就是用來(lái)對(duì)文件類型作驗(yàn)證的方法,第一個(gè)參數(shù)是文件的字節(jié)數(shù)組,第二個(gè)就是定義的可通過(guò)類型。代碼很簡(jiǎn)單,主要是注意中間的一處,將字節(jié)數(shù)組的前四位轉(zhuǎn)換成16進(jìn)制字符串,并且轉(zhuǎn)換的時(shí)候,要先和0xFF做一次與運(yùn)算。這是因?yàn)椋麄€(gè)文件流的字節(jié)數(shù)組中,有很多是負(fù)數(shù),進(jìn)行了與運(yùn)算后,可以將前面的符號(hào)位都去掉,這樣轉(zhuǎn)換成的16進(jìn)制字符串最多保留兩位,如果是正數(shù)又小于10,那么轉(zhuǎn)換后只有一位,需要在前面補(bǔ)0,這樣做的目的是方便比較,取完前四位這個(gè)循環(huán)就可以終止了。
        下面我們準(zhǔn)備些文件來(lái)測(cè)試一下這段代碼有沒(méi)有問(wèn)題。

    package com.bolo.util;

    import java.io.IOException;

    import junit.framework.Assert;

    import org.apache.commons.io.FileUtils;

    import org.junit.Test;

    import org.springframework.util.ResourceUtils;

    import com.bolo.util.FileValidateUtil;

    public class FileValidateUtilTest {

        /**

         * 文件頭部信息,十六進(jìn)制信息,取前4

         * 50 4b 03 04 office 2007+

         * d0 cf 11 e0 office 97~03

         * 25 50 44 46 pdf

         * ff d8 ff e0 jpg,部分pngjpg頭文件前4位一樣

         * ff d8 ff e1 jpg,一種不同的jpg頭文件

         * 89 50 4e 47 png

         */

        private static final String FILE_TYPE = "504b0304 d0cf11e0 25504446 ffd8ffe0 ffd8ffe1 89504e47";

        @Test

        public void jpgTest(){

            validateType("file/1.jpg");

        }

        @Test

        public void docTest(){

           validateType("file/2.doc");

        }

        @Test

        public void docxTest(){

            validateType("file/3.docx");

        }

        @Test

        public void pdfTest(){

            validateType("file/4.pdf");

        }

        @Test

        public void exeTest(){

            validateType("file/5.png");

        }

        private void validateType(String path){

            try {

                Assert.assertTrue(FileValidateUtil.validateType(FileUtils

                   .readFileToByteArray(ResourceUtils.getFile("classpath:" + path)), FILE_TYPE));

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }
        從測(cè)試代碼可以看到文件類型,只有第五個(gè)不是正確文件,是我將一個(gè)exe文件通過(guò)改后綴為png。這個(gè)測(cè)試類,用到了commons-ioFileUtils,需要在pom中加入這個(gè)依賴,而ResourceUtilsorg.springframework.util包中,它屬于spring-core.jar,大象這個(gè)測(cè)試類是放在之前ssm3工程test里面,要想正常運(yùn)行測(cè)試,要在test/resources目錄下建個(gè)file文件夾存放測(cè)試文件,最后編譯之后file及其測(cè)試文件都會(huì)在test-classes下面,所以文件查找是以classpath:開(kāi)頭。
         OK,運(yùn)行測(cè)試,結(jié)果就是前四個(gè)成功,最后一個(gè)失敗,這達(dá)到了我們的預(yù)期,只允許FILE_TYPE里面定義的文件類型通過(guò)測(cè)試。大家可以自己動(dòng)手試驗(yàn)一下。
        本文為菠蘿大象原創(chuàng),如要轉(zhuǎn)載請(qǐng)注明出處。http://bolo.blogjava.net/ 
    posted on 2012-05-01 11:37 菠蘿大象 閱讀(6352) 評(píng)論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 亚洲日韩精品国产3区| 日韩va亚洲va欧洲va国产| 亚洲深深色噜噜狠狠网站| 亚洲av片一区二区三区| 亚洲va精品中文字幕| 亚洲中文无码永久免费| 亚洲AV无码乱码麻豆精品国产| 99久久久国产精品免费无卡顿| 亚洲免费二区三区| 日韩精品成人无码专区免费| 亚洲校园春色另类激情| 天天天欲色欲色WWW免费| 亚洲人成国产精品无码| 人妻巨大乳hd免费看| 亚洲色精品aⅴ一区区三区| 国产色无码精品视频免费| 亚洲情a成黄在线观看动漫尤物| 亚洲13又紧又嫩又水多| 免费无码不卡视频在线观看| 亚洲高清一区二区三区电影| 免费一级毛片不卡不收费| 亚洲伊人色一综合网| 成人黄软件网18免费下载成人黄18免费视频 | 91免费资源网站入口| 91亚洲性爱在线视频| 蜜桃精品免费久久久久影院| 春意影院午夜爽爽爽免费| 亚洲an天堂an在线观看| 国产人在线成免费视频| 美女免费精品高清毛片在线视| 在线播放亚洲第一字幕| 免费观看国产网址你懂的| 亚洲AV无码成人精品区狼人影院 | 久久久久久国产精品免费免费男同| 久久亚洲私人国产精品vA| 精品国产精品久久一区免费式| 国产99精品一区二区三区免费| 亚洲春色另类小说| 亚洲av无码不卡私人影院| 99免费观看视频| 精品一区二区三区免费毛片|