我在《Firefox Quantum 向左,Google Chrome 向右》中,曾经吐槽过在 Firefox 中使用 Galaxy 上传本地的 Excel 文件时,会出现 xlsx 无法识别异常的问题。今天,我们来聊一聊原因。
关于 Galaxy 生物信息平台,这里就不多说了,感兴趣的可以参考本专栏的前两篇文章。
对于数据上传,Galaxy 不仅可以支持 NCBI SRA、EBI SRA、UCSC main table browser 等数据库数据的无缝对接。
在本地文件的上传中,Galaxy 支持包括 ab1、arff、fasta、fastq、xlsx 在内 100 多种常见的格式数据上传。
对于不太熟悉命令行操作的科研工作者,Excel 是他们进行批量订单提交和处理最喜欢也是最熟悉的一个数据格式,因此,我们以 Galaxy 为基础开发一部分定制化工具中,有很大的一部分都是基于 excel 文件进行处理的工具。但随之而来的问题是,所有的这些工具在 Google Chrome 下可以运行良好,但是在 Firefox 下却出现了问题。
一开始,在办公环境下,我在内网环境部署的 Galaxy 和 https://usegalaxy.org/ 中分别对 xlsx 格式的文件进行上传测试,发现:
于是,下意识的,我开始怀疑,是不是 Firefox 会针对 Excel 的文件进行了特殊处理?还是 Galaxy 的 xlsx 文件识别存在 bug?针对前一个问题,我一开始并不知道如何去验证,但对于后一个问题,我开始了另外的尝试。
#!/bin/bash
mkdir ./cgi-bin/
cp upload.cgi ./cgi-bin/
chmod +x ./cgi-bin/upload.cgi
mkdir ./upload/
python -m http.server --cgi 8080
#!/usr/bin/python
# -*- coding: utf-8 -*-
import cgi, cgitb, os, sys
UPLOAD_DIR = './upload'
def save_uploaded_file():
print 'Content-Type: text/html; charset=UTF-8'
print
print '''
<html>
<head>
<title>Upload File</title>
</head>
<body>
'''
form = cgi.FieldStorage()
if not form.has_key('file'):
print '<h1>Not found parameter: file</h1>'
return
form_file = form['file']
if not form_file.file:
print '<h1>Not found parameter: file</h1>'
return
if not form_file.filename:
print '<h1>Not found parameter: file</h1>'
return
uploaded_file_path = os.path.join(UPLOAD_DIR, os.path.basename(form_file.filename))
with file(uploaded_file_path, 'wb') as fout:
while True:
chunk = form_file.file.read(100000)
if not chunk:
break
fout.write (chunk)
print '<h1>Completed file upload</h1>'
print '''
<hr>
<a href="../upload.html">Back to upload page</a>
</body>
</html>
'''
cgitb.enable()
save_uploaded_file()
<html>
<head>
<title>Upload File</title>
</head>
<body>
<h1>Upload File</h1>
<form action="cgi-bin/upload.cgi" method="POST" enctype="multipart/form-data">
File: <input name="file" type="file">
<input name="submit" type="submit">
</form>
</body>
</html>
通过这三个程序,就可以在 Linux 下启动一个简单文件上传小网站。网站效果如下面的截图所示。
通过 python cgi 上传完文件后,在使用 python 模块进行处理的时,发现通过 Firefox 上传的文件开始出现问题了:
In [1]: import pandas as pd
In [2]: pd.read_excel("upload/upload.xlsx")
---------------------------------------------------------------------------
XLRDError Traceback (most recent call last)
<ipython-input-8-9e85b7330a4e> in <module>
----> 1 pd.read_excel("upload/upload.xlsx")
......
XLRDError: Unsupported format, or corrupt file: Expected BOF record; found b'b\x14#e\xa9\x01W\x00'
于是,开始回去看 Galaxy 的源码,想要搞明白 Galaxy 对于 xlsx 文件上传到底是怎么进行识别的,终于在 packages/data/galaxy/datatypes/binary.py
中发现 Galaxy 正是使用了 python 的 zipfile
模块 :
于是,我也开始使用 zipfile
来对先前 python cgi 上传的文件进行测试:
In [9]: import zipfile
In [10]: zipfile.ZipFile("upload/upload.xlsx")
---------------------------------------------------------------------------
BadZipFile Traceback (most recent call last)
<ipython-input-10-3793f2363956> in <module>
----> 1 zipfile.ZipFile("upload/upload.xlsx")
......
BadZipFile: File is not a zip file
同样的操作,我在 Chrome 重复了一遍,但是却神奇的发现,不管是 panda
还是 zipfile
模块,竟然一切都表现正常!似乎,Firefox 的确有点不正常。
针对这个问题,我最开始向 Galaxy Project 团队咨询过,但一直没有从根本解决掉这个问题,他们建议考虑非 xlsx 格式数据的工具开发。
直到前几天,突发奇想在 Firefox 社区中重新提起这个事情,一个热心网友的回复才让我意识到了问题的所在,也就是哈希——文件完整性校验。
我把文件上传前的 MD5 和文件上传后的 MD5 重新进行了计算比较,这才发现:
很明显,我的原始 xlsx 文件是有问题的!!吐血中!!!但是在办公环境中,这个原始的 xlsx 文件不管是 Office 2016 还是 WPS 都能正常打开,正常编辑保存。唯一不同的是文件中多了一个锁的标志。
其实,这就是企业企业办公文档 Office Excel 软件加密的一种效果。
测试加密效果:被加密电脑重启后,打开 word 文档,新建文档并编辑保存,保存后的文件会显示“加锁”标志,如下图示,显示已成功加密。
实现效果:员工编辑后的文档自动加密,加密后的文档未经许可,私自通过 QQ,电子邮件,U盘等任何方式传输到公司以外,都将无法打开使用;不改变编辑操作习惯,在企业内部相互流通编辑,不受影响。彻底从源头保障数据的安全性。此外还可实现如需外发文件,可通过申请解密流程授权解密后方可外发;同时还可对其他软件进行加密,比如办公软件,设计软件,工程软件,编程软件,研发软件等。
最后,把未加密的 xlsx 文件进行重新测试,一切问题迎刃而解。
这是一个企业文档加密引发的填坑记录,从问题的发现,问题的思考,到解决的思路值得探讨记录一下。
Chrome 为什么能绕开部分企业文档加密的枷锁,还原文件,这是一个有待后面学习的问题,mark 一下,同时期待大家指点迷津。