www.webdeveloper.com
Results 1 to 2 of 2

Thread: Interesting ajax/php uploader

  1. #1
    Join Date
    Jul 2012
    Posts
    9

    Interesting ajax/php uploader

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

  2. #2
    Join Date
    Jul 2012
    Posts
    9
    Simplified with more comments.
    Code:
    <?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 11:32 PM. Reason: left bits in that where no longer needed

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles