我们如何在 AngularJS 中不使用幻数验证 SVG 图像

Posted

技术标签:

【中文标题】我们如何在 AngularJS 中不使用幻数验证 SVG 图像【英文标题】:How can we validate SVG Image without using magic number in AngularJS 【发布时间】:2020-11-05 17:47:58 【问题描述】:

我们目前正在使用幻数验证图像。由于 SVG 不支持幻数,那么在 angularJS 中验证 SVG 文件的好方法是什么?

这就是我们验证其他图像的方式 -

angular.module('fileMimeTypeServiceModule', [])
.constant('fileMimeTypeServiceConstants', 
    VALID_IMAGE_MIME_TYPE_CODES: ['FFD8FFDB', 'FFD8FFE0', 'FFD8FFE1', '474946383761', '424D', '49492A00', '4D4D002A', '89504E470D0A1A0A']
)
.factory('seFileReader', function() 
    var read = function(file, config) 
        var fileReader = new FileReader();

        config = config || ;
        fileReader.onloadend = config.onLoadEnd;
        fileReader.onerror = config.onError;

        fileReader.readAsArrayBuffer(file);
        return fileReader;
    ;

    return 
        read: read
    ;
)
.factory('fileMimeTypeService', function(fileMimeTypeServiceConstants, seFileReader, $q) 
    var _validateMimeTypeFromFile = function(loadedFile) 
        var fileAsBytes = (new Uint8Array(loadedFile)).subarray(0, 8);
        var header = fileAsBytes.reduce(function(header, byte) 
            var byteAsStr = byte.toString(16);
            if (byteAsStr.length === 1) 
                byteAsStr = '0' + byteAsStr;
            
            header += byteAsStr;
            return header;
        , '');

        return fileMimeTypeServiceConstants.VALID_IMAGE_MIME_TYPE_CODES.some(function(mimeTypeCode) 
            return header.toLowerCase().indexOf(mimeTypeCode.toLowerCase()) === 0; // validating here
        );
    ;

    var isFileMimeTypeValid = function(file) 
        var deferred = $q.defer();
        seFileReader.read(file, 
            onLoadEnd: function(e) 
                if (_validateMimeTypeFromFile(e.target.result)) 
                    deferred.resolve();
                 else 
                    deferred.reject();
                
            ,
            onError: function() 
                deferred.reject();
            
        );
        return deferred.promise;
    ;

    return 
        isFileMimeTypeValid: isFileMimeTypeValid
    ;
);

现在我也想验证 SVG 图像,我们如何在没有幻数的情况下验证它?

【问题讨论】:

【参考方案1】:

SVG 图像是 XML 文件。第一步,您可以测试 XML 幻数。之后,您可以将文件内容作为文本读取并使用DOMParser 对其进行解析。如果发生错误,这将告诉您文件无效。

此示例使用TextDecoder API 将数组缓冲区转换为字符串。这可能比使用单独的异步 FileReader.readAsText() 操作更具限制性。您应该检查浏览器的兼容性,看看这个解决方案是否足够好。

angular.module('fileMimeTypeServiceModule', [])
.constant('fileMimeTypeServiceConstants', 
    VALID_IMAGE_MIME_TYPE_CODES: [ 'ffd8ffdb', 'ffd8ffe0', 'ffd8ffe1', '474946383761', '424d', '49492a00', '4d4d002a', '89504e470d0a1a0a' ],
    XML_MIME_TYPE_CODE: '3c3f786d6c'
)
.factory('seFileReader', function() /*...*/)
.factory('fileMimeTypeService', function(fileMimeTypeServiceConstants, seFileReader, $q) 
    var _validateMimeTypeFromFile = function(loadedFile) 
        var u8arr = new Uint8Array(loadedFile);
        var fileAsBytes = (u8arr).subarray(0, 8);
        var header = fileAsBytes.reduce(function(header, byte) 
            var byteAsStr = byte.toString(16);
            if (byteAsStr.length === 1) 
                byteAsStr = '0' + byteAsStr;
            
            header += byteAsStr;
            return header;
        , '');

        if (header.toLowerCase().startsWith(fileMimeTypeServiceConstants.XML_MIME_TYPE_CODE) 
            try 
                var fileContentAsString = new TextDecoder('utf-8').decode(u8arr);
                var parser = new DOMParser();
                parser.parseFromString(fileContentAsString, 'image/svg+xml');
                return true;
             catch (e) 
                return false;
            
         else 
          return fileMimeTypeServiceConstants.VALID_IMAGE_MIME_TYPE_CODES.some(function(mimeTypeCode) 
              return header.toLowerCase().startsWith(mimeTypeCode); 
          );
        
    ;

    //...
);

显然,如果您希望测试非常大的文件,这可能是一个消耗内存的操作,因为 SVG 的完整 DOM 已构建(但未渲染)。我的期望是,除了一些异常用例(例如并行测试大量文件)之外,它仍然是最快、最可靠的解决方案。

【讨论】:

XML 并不总是需要以 在实践中,您可能是对的,XML 一致性大多没有经过测试。我正在解释来自spec rule 的“有效性”,它需要独立的 SVG 文件。如果您不关心这一点,那么该测试的唯一剩余原因是避免不必要地尝试将二进制文件作为文本加载,这意味着它并不重要。

以上是关于我们如何在 AngularJS 中不使用幻数验证 SVG 图像的主要内容,如果未能解决你的问题,请参考以下文章

我们如何使用 spring security Ldap 以 angularjs 作为客户端进行身份验证

AngularJS中使用的表单验证

AngularJs:如何对指令创建的动态元素应用表单验证

angularJS - 如何验证数字是否在字符串中

在 AngularJS 中不使用 JQuery 获取 HTML 元素高度

了解隐藏在状态栏中的幻数