I created an ajax/php uploader that I wanted to share as it may be usefull for others. It is a bit slow just using hex but it picks up on where it leaves off. It show progress and multiple files.
Code:
<?php
$MAXPOSTSIZE=50000;
$name="";
$mtime="";
$size="";
$blob="";
$start=0;
$end=$MAXPOSTSIZE;
if(sizeof($argv)==2)
{$arguments=explode("&",$argv[1]);
foreach($arguments as $argument)
{$key_value=explode("=",$argument);
if(sizeof($key_value!=1))
{$_REQUEST[$key_value[0]]=$key_value[1];
}
else
{$_REQUEST[$key_value[0]]="";
}}}
foreach($_REQUEST as $key=>$value)
{if($key=="name"){$name=$value;}
if($key=="mtime"){$mtime=$value;}
if($key=="size"){$size=$value;}
if($key=="mtime"){$mtime=$value;}
if($key=="start"){$start=$value;}
if($key=="end"){$end=$value;}
if($key=="blob"){$blob=$value;}
}
if($name!="")
{
$tempfile="/tmp/".$name."-".$mtime."-".$size.".tmp";
$constructfile="/tmp/".$name."-".$mtime."-".$size.".part";
$writeblob=false;
if(file_exists($tempfile))
{list($pstart,$pend)=explode(":",file_get_contents($tempfile));
}
else
{$pstart=0;
$pend=$MAXPOSTSIZE;
if($pend>$size){$pend=$size;}
}
if($pstart==$start&&$pend==$end)
{$writeblob=true;
}
else
{$start=$pstart;
$end=$pend;
}
if($writeblob)
{for($x=0;$x<strlen($blob);$x+=2)
{$byte=chr(intval($blob[$x].$blob[$x+1],16));
file_put_contents($constructfile,$byte,FILE_APPEND | LOCK_EX);
}
if($end==$size)
{unlink($tempfile);
rename($constructfile,"/tmp/".$name);
$start=$end;
}
else
{$start+=$MAXPOSTSIZE;
$end=$start+$MAXPOSTSIZE;
if($end>$size){$end=$size;}
file_put_contents($tempfile,$start.":".$end);
}}
header ("content-type: text/xml");
print "<data>\n";
print "<name>".$name."</name>\n";
print "<mtime>".$mtime."</mtime>\n";
print "<size>".$size."</size>\n";
print "<start>".$start."</start>\n";
print "<end>".$end."</end>\n";
print "</data>\n";
}
else
{
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
var files;
function pad(hexnum)
{if(hexnum.length<2){return "0"+hexnum;}
return hexnum
}
function toHex(str)
{var hex = '';
var myreplace='';
for(var i=0;i<str.length;i++)
{hex += pad(''+str.charCodeAt(i).toString(16));
}
return hex;
}
function readBlob(file,start,stop)
{var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt)
{if (evt.target.readyState == FileReader.DONE)
{// DONE == 2
var data="name="+file.name+"&mtime="+file.lastModifiedDate.valueOf()+"&size="+file.size+"&start="+start+"&end="+stop+"&blob="+toHex(evt.target.result);
ajax(next,"",data);
}};
var blob = file.slice(start, stop);
reader.readAsBinaryString(blob);
}
function start_upload(file)
{var data="name="+file.name+"&mtime="+file.lastModifiedDate.valueOf()+"&size="+file.size+"&start=0&end=0";
ajax(next,"",data);
}
function getfileindex(name)
{for (var i = 0 ; i< files.length; i++)
{if(files[i].name==name)
{return i;
}}
return -1;
}
function next(xmlhttp)
{var xmldata=xmlhttp.responseXML;
var start=xmldata.getElementsByTagName("start")[0].childNodes[0].nodeValue;
var end=xmldata.getElementsByTagName("end")[0].childNodes[0].nodeValue;
var file=getfileindex(xmldata.getElementsByTagName("name")[0].childNodes[0].nodeValue);
if(start!=end)
{document.getElementById("complete"+file).innerHTML=files[file].name+" "+end+" of "+files[file].size;
readBlob(files[file],start,end)
}
else
{//done
document.getElementById("complete"+file).innerHTML=files[file].name+" finnished";
}}
function ajax(afunction,url,data)
{var xmlhttp = false;
if(window.XMLHttpRequest)
{// Mozilla, Safari, Chrome,...
xmlhttp = new XMLHttpRequest();
// set type accordingly to anticipated content type
//xmlhttp.overrideMimeType('text/xml');
if (xmlhttp.overrideMimeType)
{xmlhttp.overrideMimeType('text/xml');
}}
else if(window.ActiveXObject)
{// IE
try
{xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{try
{xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
}}}
if(!xmlhttp){alert('Cannot create XMLHTTP instance');return false;}
xmlhttp.open('POST',url, false);
xmlhttp.onreadystatechange=function()
{if (xmlhttp.readyState==4)
{afunction(xmlhttp);
}};
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.send(data);
}
function start_uploading()
{files=document.getElementById("files").files;
var html="";
for(var i=0;i<files.length;i++)
{html+='<div id="complete'+i+'"></div>';
}
document.getElementById("complete").innerHTML=html;
for(var i=0;i<files.length;i++)
{start_upload(files[i]);
}}
</script>
</head>
<body>
<input type="file" id="files" name="files[]" multiple />
<button onclick="start_uploading()">start upload</button>
<div id="complete"></div>
</body>
</html>
<?php
}
?>
<?php
//initialize variables that should be overwritten with user input
$MAXPOSTSIZE=48000;
$name="";
$mtime="";
$size="";
$blob="";
$start=0;
$end=0;
//for testing from the commandline change a commandline into a request
//php phpfile.php "variable=value&variable2=value2"
if(isset($argv))
{if(sizeof($argv)==2)
{$arguments=explode("&",$argv[1]);
foreach($arguments as $argument)
{$key_value=explode("=",$argument);
if(sizeof($key_value!=1))
{$_REQUEST[$key_value[0]]=$key_value[1];
}
else
{$_REQUEST[$key_value[0]]="";
}}}}
//get variables
foreach($_REQUEST as $key=>$value)
{//Get the File Name
if($key=="name"){$name=$value;}
//Get an Modified Time From the Client
if($key=="mtime"){$mtime=$value;}
//Get the Postsize of bytes to send
if($key=="postsize"){$MAXPOSTSIZE=$value;}
//Get the filesize
if($key=="size"){$size=$value;}
//Get start of this blob
if($key=="start"){$start=$value;}
//Get end of this blob
if($key=="end"){$end=$value;}
//Get base64 encoded blob
if($key=="blob"){$blob=$value;}
}
//If there is a name use the server mode else use the client mode.
if($name!="")
{//Give a unique name based on clients filename size and last modified time.
$constructfile="upload/".$name."-".$mtime."-".$size.".part";
//get the expected start of blob
if(file_exists($constructfile)){$pstart=filesize($constructfile);}else{$pstart=0;}
//get the expected end of blob
$pend=$pstart+$MAXPOSTSIZE;
//if the expected end is greater then the file size set the expected end to the file size
if($pend>$size){$pend=$size;}
//if it is not the expected bits ignore it
if($pstart==$start&&$pend==$end)
{//decode the base64 blob and write it to the temp file
file_put_contents($constructfile,
base64_decode(str_replace(" ","+",$blob)),
FILE_APPEND | LOCK_EX);
if($end==$size)
{//file has been uploaded successfully make it the original file name
rename($constructfile,"upload/".$name);
//this tells the client it is done.
$start=$end;
}
else
{//ask for the next bit of data
$start+=$MAXPOSTSIZE;
$end=$start+$MAXPOSTSIZE;
if($end>$size){$end=$size;}
}}
else
{//return the expected bytes that the server wants
$start=$pstart;
$end=$pend;
}
header ("content-type: text/xml");
print "<data>\n";
print "<name>".$name."</name>\n";
print "<mtime>".$mtime."</mtime>\n";
print "<size>".$size."</size>\n";
print "<start>".$start."</start>\n";
print "<end>".$end."</end>\n";
print "</data>\n";
}
else
{// no name was given show the client side
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
var files;
var postsize;
//convert to base64
function toBase64(str)
{var base64 = '';
var char64 = function (number)
{var charset="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
charset+="abcdefghijklmnopqrstuvwxyz";
charset+="0123456789+/";
return charset[number];
}
for(var i=0;i<str.length;i+=3)
{var chr1,chr2,chr3,pad;
pad="";
chr1 = str.charCodeAt(i);
if(str.length>i+1){chr2=str.charCodeAt(i+1);}else{chr2=0;pad="==";}
if(str.length>i+2){chr3=str.charCodeAt(i+2);}else{chr3=0;pad="=";}
base64+=char64(chr1>>2);
base64+=char64(((chr1 & 3) << 4) | (chr2 >> 4))
if(pad.length!=2)
{base64+=char64(((chr2 & 15) << 2) | (chr3 >> 6));
if(pad.length!=1)
{base64+=char64(chr3 & 63);
}}
base64+=pad;
}
return base64;
}
function readBlob(file,start,stop)
{var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt)
{if (evt.target.readyState == FileReader.DONE)
{// DONE == 2
var data="&postsize="+postsize+"&name="+file.name+"&mtime=";
data+=file.lastModifiedDate.valueOf()+"&size="+file.size
data+="&start="+start+"&end="+stop+"&blob="+toBase64(evt.target.result);
//send this base64 encoded blob to the server
ajax(next,"",data);
}};
var blob = file.slice(start, stop);
reader.readAsBinaryString(blob);
}
//returns the index for the file with this name
function getfileindex(name)
{for (var i = 0 ; i< files.length; i++)
{if(files[i].name==name)
{return i;
}}
return -1;
}
//get the expected next bit of data for the server
function next(xmlhttp)
{var xmldata=xmlhttp.responseXML;
var start=xmldata.getElementsByTagName("start")[0].childNodes[0].nodeValue;
var end=xmldata.getElementsByTagName("end")[0].childNodes[0].nodeValue;
var filename=xmldata.getElementsByTagName("name")[0].childNodes[0].nodeValue;
var file=getfileindex(filename);
if(file!=-1)
{var element=document.getElementById("complete"+file);
var msg=filename+" ";
if(start!=end)
{msg+=end+" of "+files[file].size;
readBlob(files[file],start,end);
}
else
{//done
msg+="finnished";
}
element.innerHTML=msg;
}
else
{alert("file ["+filename+"] is no longer selected");
}}
function ajax(afunction,url,data)
{var xmlhttp = false;
if(window.XMLHttpRequest)
{// Mozilla, Safari, Chrome,...
xmlhttp = new XMLHttpRequest();
// set type accordingly to anticipated content type
//xmlhttp.overrideMimeType('text/xml');
if (xmlhttp.overrideMimeType)
{xmlhttp.overrideMimeType('text/xml');
}}
else if(window.ActiveXObject)
{// IE
try{xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");}
catch(e)
{try{xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");}
catch(e){}
}}
if(!xmlhttp){alert('Cannot create XMLHTTP instance');return false;}
// xmlhttp.open('GET',url+"?"+data, false);
xmlhttp.open('POST',url, false);
xmlhttp.onreadystatechange=function()
{if (xmlhttp.readyState==4)
{afunction(xmlhttp);
}};
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// xmlhttp.send("");
xmlhttp.send(data);
}
function start_uploading()
{//get file pointers to selected files
files=document.getElementById("files").files;
//get the size of chuncks to send to the server
postsize=parseInt(document.getElementById("POSTSIZE").value);
var html="";
//write a div for each of the files being uploaded to show each's progress
for(var i=0;i<files.length;i++)
{html+='<div id="complete'+i+'"></div>';
}
document.getElementById("complete").innerHTML=html;
for(var i=0;i<files.length;i++)
{var data="name="+files[i].name+"&mtime=";
data+=files[i].lastModifiedDate.valueOf()+"&size=";
data+=files[i].size+"&postsize="+postsize;
ajax(next,"",data);
}}
</script>
</head>
<body>
<input type="file" id="files" name="files[]" multiple />
<button onclick="start_uploading()">start upload</button>
POSTSIZE:<input id="POSTSIZE" value="<?php print $MAXPOSTSIZE; ?>">
<div id="complete"></div>
</body>
</html>
<?php } ?>
Last edited by jeffsadowski; 11-06-2012 at 10:32 PM.
Reason: left bits in that where no longer needed
Bookmarks