0%

业务需求

最近公司要搞个报名程序需要在不同网站上引用一段 Js 代码实现用户报名, 其中就涉及到需要图片上传的需求。
结果搞了好几天,感觉有必要记录一下以吸取经验教训!
兼容 IE7+ 可跨域上传图片(实际上 IE6 也是没有问题的…)

愉快踩坑步伐

考虑(其中部分使用过)过以下图片上传第三方组件:

最开始使用的是jquery-form上传图片,同域名 IE6+ 都没有问题,唯独跨域它就不行了(这里说的是 IE10以下, 若是不需要兼容 IE 这毒瘤一切 OK!),上传图片可以成功,但是responseText中一直返回body中的代码, 它有创建iframe且里面有我们想要的数据但是无法获取。
在找解决方案的过程中,看到了第二个项目jQuery-File-Upload 果然强大,Star 都2.6w+ 其中 这里 对使用跨域上传做了解释(个人理解: 必须在每个客户端创建一个文件用于跨域获取数据,同源策略所致: 无法获取iframe它域中的数据!)

因此我们有必要要尝试其他上传图片插件了:

第一步: 使用jquery-uploadify:

很快写完了实例, 第一个问题就出现了,刷新当前页面有多个 404 (Not Found) 问题, 原因是: 其配置项中有一个buttonImage参数没有配置(我们并不想配置), 此处就是uploadify的一个bug:
找到jquery.uploadify.js文件将下面代码:

1
this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url)

替换成:

1
2
3
if (this.settings.button_image_url != "") {
this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
}

客户端引用本地uploadify.swf没有问题,但若是引入别的域名的呢? 打开debug后提示如下:
SWF DEBUG: ExternalInterface reinitialized
即使是在服务器端根目录下创建crossdomain.xml文件,设置允许跨域也是一直提示上述信息并无法实现跨域上传

1
2
3
4
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

第二步: 使用SWFUpload:

我下载的是v2.2.0版本, 写完实例发现与uploadify相似, 但是它不需要额外引入jquery, 404 (Not Found) 问题解决同上。
其也提供swfupload.swfflash文件, 我先将其放入其他域名,测试一下上传图片,发现 ok, 完全是我想要的方案, 同时我发现了 这篇文章,
文章中还指导了如何修复此漏洞,当然我并没有时间去修复… 因为需要编译 swf 文件, 我了个xxoo…
不想点开看的,可以看下面我所引用的信息, 如何测试呢? 将以下路径替换成你要访问swf的url并放到浏览器中访问,若是提示 alert 则证明存在XSS和CSRF漏洞。

www.example.com/swfupload.swf?movieName=%22])}catch(e){if(!window.x){alert(1);window.x=1}}try{([%22

测试发现确实存在漏洞, 然而测试 uploadify 所引入的swf文件确没有弹框, 证明uploadify已修复了这个漏洞(难道是为了修复这个漏洞竟然不让其跨域上传图片了?)
机制的我将swfupload引用 swf 文件路径替换了uploadify中的 swf 文件路径,结果测试 ok, 原来都是 swf 文件在作怪, 接下来还是这个 swf 文件又坑了我…
目前来看, 所有问题都解决了(那个漏洞可以暂时一放, 先完成项目需求~ )
找了一个需要引入的报名页的网页放进去,测试发现选择完图片后没有反应了,没有反应了,没有反应了…

第三步: 使用 webuploader - 解决

查看引入页网页源代码发现它也引入了swfupload图片上传插件,这怎么搞? 领导说要兼容, 只能搞了…
方案:

  • swfupload.js中的SWFUpload更换名称, 无效…
  • swfupload.js中的SWFUploal闭源处理(即: 使用$(function(){codezm.swfupload = SWFUpload})(), 这样外部就不能使用SWFUpload对象了,只能使用 codezm.swfupload), 无效…

谷歌发现有人说要修改swfupload.js还要重新编译swfupload.swf文件才行, 我绝望了…
问题总是要解决的,万一实现了呢~
github 上搜索swfupload.swf,希望下载个不一样命名的 swfupload.swf, 下载后测试无效…

再尝试使用一款上传插件webuploader 百度开源, 因为看到其自己编译的Uploader.swf文件, 感觉有戏…
需要注意以下几点:

  • 此方式不能将pick绑定到
    1
    <input type="file" id="pick">
  • 此方式若是使用flash上传,并且将顶层设置为hidden:none来禁止用户再次上传将导致flash失效,需要重新加载一遍方法或者使用如下方式将其隐藏起来,但是如点击还可上传图片(可给出正确提示信息):
    1
    position: absolute; opacity: 0; filter:Alpha(opacity=0);
  • Chrome - Network面板明明已加载Uploader.swf文件还是无法使用,可能是Chrome
  • 重复上传同一个文件可设置如下属性:
    1
    2
    // 可重复上传
    duplicate :true,
  • 若判断达到上传限制取消图片上传
    1
    2
    3
    4
    5
    6
    uploader.on( 'fileQueued', function( file ) {
    if(uploader.isInProgress()) {
    alert("图片正在上传中");
    uploader.cancelFile( file );
    }
    }

其他技术点:

  • 虽然webuploaderbrowser方法检测浏览器, 但是万一不用它呢, 以下是我力荐的解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var isIE = function(ver){
    var b = document.createElement('b')
    b.innerHTML = '<!--[if IE ' + ver + ']><i></i><![endif]-->'
    return b.getElementsByTagName('i').length === 1
    }

    if(isIE(6)) {
    console.log('This is IE 6 browser.');
    }
  • 因为项目全程使用的Ajax提交数据,无奈IE又不支持遂引入 jQuery.XDomainRequest.js 而且POST时其只能通过二进制提交, 后端修改获取数据方式(PHP: file_get_contents(‘php://input’) 获取数据)

    When POSTing, the data will always be sent with a Content-Type of text/plain

本文主要收集我所使用过的 Alfred Workflows , 在此也推荐给大家并将持续更新, 也欢迎大家留言推荐实用的Workflows以便与众人共享
若没有也可向我提出你的想法,具体实现交给我。

阅读全文 »

记录开发环境配置 for php (警告: 开发模式而非生产模式).

主要记录我使用的环境配置中 php 需安装的插件及插件在 php.ini 中及其他 php 功能配置.
环境配置主要面向*unix系统.

阅读全文 »

docker-machine start docker-vm 后, docker-machine env docker-vm 提示如下信息:

1
Unknown Unable to query docker version: Get https://192.168.99.101:2376/v1.15/version: x509: certificate is valid for 192.168.99.103, not 192.168.99.101
阅读全文 »