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
}
?>