php 上传html文件_php结合html5 实现大文件上传的方法

工作中,经常碰到大文件上传的需求,如上传大的用户包、CDK列表等。常规的解决方案是采用form表单+iframe方式提交给php处理,如下面的代码:

html代码:

action="CRobFloor.php?a=Upload" method="POST"

id="frmImportCDK">

请选择CDK文件

上传

php代码:

if (is_uploaded_file($_FILES["sCDKFile"]["tmp_name"])) {

switch ($_FILES["sCDKFile"]["error"]) {

case UPLOAD_ERR_OK:

break;

case UPLOAD_ERR_NO_FILE:

$this->OutputScript('No file sent.');

case UPLOAD_ERR_INI_SIZE:

case UPLOAD_ERR_FORM_SIZE:

$this->OutputScript('Exceeded filesize limit.');

default:

$this->OutputScript('Unknown errors. Code:' . $_FILES["sCDKFile"]["error"]);

}

//上传文件的类型

$stype = $_FILES["sCDKFile"]["type"];

//如果文件符合要求并且上传过程中没有错误

if ($stype != "text/plain" && $stype != "application/csv") {

$this->OutputScript("请选择上传txt,csv格式的文件,不支持格式{$stype}");

}

上面方案存在一个致命的问题,没发处理大文件的上传。主要受到来自下面几个方面的限制:

PHP的脚本时长的限制

长时间上传,网络中断的问题

PHP脚本执行时内存大小等的限制

apache服务器链接数限制

与之相关的php配置项如下:

;;;;;;;;;;;;;;;;

; File Uploads ;

;;;;;;;;;;;;;;;;

file_uploads = On

upload_max_filesize = 8m //允许上传文件大小的最大值

max_file_uploads = 20 //单请求最多允许上传文件数量

post_max_size = 8M //post数据大小限制

;;;;;;;;;;;;;;;;;;

; Resource Limits ;

;;;;;;;;;;;;;;;;;;;

max_execution_time = 30 ;每个PHP页面运行的最大时间值(秒),默认30秒

max_input_time = 60 ;每个PHP页面接收数据所需的最大时间,默认60秒

memory_limit = 128m ;每个PHP页面所吃掉的最大内存,默认8M

从上面的配置看到,如果调大upload_max_filesize = 128m,设上传网速为 500KB,则30s只够上传15M以内大小的文件,时间长了脚本将中断执行,如果继续调整max_execution_time等设置,将 如果中间网络中断,上传文件还是失败。

并且上述方案还有下面几个问题:

不支持显示上传进度

不支持断点续传、如果网络中断后需要整体重传

我们希望能够找到一个在web上能够解决上面两个问题的方案。

HTML5之前的解决方案

一般有三种方法:

RIA技术(Flex Silverlight等),该方案需要浏览器支持Flash,最常用的是使用SWFupload实现。

插件技术(ActiveX,applet等),要装下载安装插件、比较麻烦。而且ActiveX插件不具有跨浏览器的特性,只能在IE浏览器上使用。

CS解决方案:开发单独的客户端和服务器程序,使用UDP/TCP长链接通讯上传。缺点:需要单独开发Client,发布更新困难、

html5的解决方案

相关对象和API

File - 独立文件;提供只读信息,例如名称、文件大小、mimetype 和对文件句柄的引用。

FileList - File 对象的类数组序列(考虑 或者从桌面拖动目录或文件)。

Blob - 可将文件分割为字节范围。

FileReader:文件读写对象,包括四个异步读取文件的选项:

FileReader.readAsBinaryString(Blob|File) - result 属性将包含二进制字符串形式的 file/blob 数据。每个字节均由一个 [0..255] 范围内的整数表示。

FileReader.readAsText(Blob|File, opt_encoding) - result 属性将包含文本字符串形式的 file/blob 数据。该字符串在默认情况下采用“UTF-8”编码。使用可选编码参数可指定其他格式。

FileReader.readAsDataURL(Blob|File) - result 属性将包含编码为数据网址的 file/blob 数据。

FileReader.readAsArrayBuffer(Blob|File) - result 属性将包含 ArrayBuffer 对象形式的 file/blob 数据。

HTML5文件处理API能够支持文件拖拽、上传进度显示、支持文件分块读取等特性。有了文件分块读取的特性,就可以实现将文件分块上传,然后在服务器段合并文件。如下面的demo:

#progress_bar {

margin: 10px 0;

padding: 3px;

border: 1px solid #000;

font-size: 14px;

clear: both;

opacity: 0;

-moz-transition: opacity 1s linear;

-o-transition: opacity 1s linear;

-webkit-transition: opacity 1s linear;

}

#progress_bar.loading {

opacity: 1.0;

}

#progress_bar .percent {

background-color: #99ccff;

height: auto;

width: 0;

}

0%

//todo流程:

//0. 读取文件长度

//1. 初始化显示信息

//1. 读取数据

//2. 发送给后台

//3. 接收返回值、更新收到的数据

var uploadData = function (data, size, beg, end, callback) {

$.post("testUpload.php",

{

"size": size,

"data": data,

"beg": beg,

"end": end

}).done(function (result) {

if (result.indexOf("Success") != -1) {

callback();

} else {

console.log("Error:\n" + data);

alert("文件块上传失败,请重新上传文件!");

}

});

};

var handleFileSelect = function (evt) {

var reader;

var progress = document.querySelector('.percent');

progress.style.width = '0%';

progress.textContent = '0%';

var files = document.getElementById('files').files;

if (!files.length) {

alert('请选择文件');

return;

}

var file = files[0];

var length = 1024 * 1024; //1M

var hadRead = 0;

var start = 0;

var stop = 0;

readBob = function (start, stop) {

console.log("Read:[" + start + ':' + stop + ']');

if (file.webkitSlice) {

var blob = file.webkitSlice(start, stop);

} else if (file.mozSlice) {

var blob = file.mozSlice(start, stop);

} else {

var blob = file.slice(start, stop);

}

reader.readAsDataURL(blob);

}

reader = new FileReader();

reader.onerror = function (evt) {

console.debug(evt.target.error.message);

switch (evt.target.error.code) {

case evt.target.error.NOT_FOUND_ERR:

alert('File Not Found!');

break;

case evt.target.error.NOT_READABLE_ERR:

alert('File is not readable');

break;

case evt.target.error.ABORT_ERR:

console.debug("errorHandler ABORT_ERROR");

break; // noop

default:

alert('An error occurred reading this file.');

}

;

};

reader.onabort = function (e) {

console.debug(e.target.error.message);

//alert('File read cancelled');

};

reader.onloadstart = function (e) {

document.getElementById('progress_bar').className = 'loading';

};

reader.onload = function (e) {

if (reader.readyState == FileReader.DONE) { // DONE == 2

var callback = function () {

hadRead = stop;

progress.style.width = Math.round(hadRead / file.size * 100) + '%';

progress.textContent = Math.round(hadRead / file.size * 100) + '%';

if (hadRead >= file.size) {

return;

}

stop = (hadRead + length) > file.size ? (file.size) : (hadRead + length);

start = hadRead;

readBob(start, stop);

}

uploadData(reader.result, file.size, start, stop, callback);

//setTimeout(callback, 1000);

}

}

stop = (hadRead + length) > file.size ? (file.size) : (hadRead + length);

readBob(start, stop);

}

// Check for the various File API support.

if (window.File && window.FileReader && window.FileList && window.Blob) {

document.getElementById('files').addEventListener('change', handleFileSelect, false);

} else {

alert('您的浏览器不支持HTML5 API,请使用最新版本的chrome或者firefox浏览器');

}

//php

//TODO:

//1. 合并同一个文件、

//2. 判断是否文件结束

//3. 多用户并发情况下,不能互相干扰

session_start();

$data = $_POST["data"];

if(substr($data, 0, 37) == "data:application/octet-stream;base64,"){

$data = substr($data, 37);

}

$data = base64_decode($data);

$size = $_POST["size"];

$end = $_POST["end"];

$beg = $_POST["beg"];

if($beg == 0){

$filename = tempnam("/tmp", "FOO");

$_SESSION["filename"] = $filename;

}else{

$filename = $_SESSION["filename"];

}

// Let's make sure the file exists and is writable first.

if (!$handle = fopen($filename, 'a')) {

echo "Cannot open file ($filename)";

exit;

}

// Write $somecontent to our opened file.

if (fwrite($handle, $data) === FALSE) {

echo "Cannot write to file ($filename)";

exit;

}

fclose($handle);

if($size == $end){

unset($_SESSION["filename"]);

chmod($filename, 0755);

$newName = "Date".date("YmdHis", time()).".jpg";

rename($filename, $newName);

echo $newName;

}

echo "Success";

exit(0);

One more thing

大文件上传在后端还要考虑如何支持接入服务器集群部署,把数据传递给后端的文件处理服务器。

结束语:

感谢html5!积极拥抱新技术,这是快速提高生产力的最有效手段!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值