2

I want to upload a video file using PHP and show the progress of the upload via an Progress Bar. But this is more difficult like i thought and i tried to put the pieces ive found together but unfortunately i didnt found a working piece of code that has the needed php, ajax and html code all together, so ive tried to put different pieces together.

My Code functions nearly completely. The only thing is, that the current process of the file upload, which i've got in percent, is loaded by my javascript only AFTER the process has ended, and not from the beginning.

Here is my PHP Code:

 function file_get_size($file) {
    //open file
    $fh = fopen($file, "r");
    //declare some variables
    $size = "0";
    $char = "";
    //set file pointer to 0; I'm a little bit paranoid, you can remove this
    fseek($fh, 0, SEEK_SET);
    //set multiplicator to zero
    $count = 0;
    while (true) {
        //jump 1 MB forward in file
        fseek($fh, 1048576, SEEK_CUR);
        //check if we actually left the file
        if (($char = fgetc($fh)) !== false) {
            //if not, go on
            $count ++;
        } else {
            //else jump back where we were before leaving and exit loop
            fseek($fh, -1048576, SEEK_CUR);
            break;
        }
    }
    //we could make $count jumps, so the file is at least $count * 1.000001 MB large
    //1048577 because we jump 1 MB and fgetc goes 1 B forward too
    $size = bcmul("1048577", $count);
    //now count the last few bytes; they're always less than 1048576 so it's quite fast
    $fine = 0;
    while(false !== ($char = fgetc($fh))) {
        $fine ++;
    }
    //and add them
    $size = bcadd($size, $fine);
    fclose($fh);
    return $size;
}
$filesize = file_get_size('remote-file');

$remote = fopen('remote-file', 'r');
$local = fopen('local-file', 'w');

$read_bytes = 0;
while(!feof($remote)) {
  $buffer = fread($remote, 2048);
  fwrite($local, $buffer);

  $read_bytes += 2048;

  //Use $filesize as calculated earlier to get the progress percentage
  $progress = min(100, 100 * $read_bytes / $filesize);
  fwrite(fopen('files/upload/progress.txt', 'w'), $progress);

  //you'll need some way to send $progress to the browser.
  //maybe save it to a file and then let an Ajax call check it?
}
fclose($remote);
fclose($local);

This is my Javascript Code:

function main()
{
    var pathOfFileToRead = "files/upload/progress.txt";

    var contentsOfFileAsString = FileHelper.readStringFromFileAtPath
    (
        pathOfFileToRead
    );

    document.body.innerHTML = contentsOfFileAsString;
}

function FileHelper()
{}
{
    FileHelper.readStringFromFileAtPath = function(pathOfFileToReadFrom)
    {
        var request = new XMLHttpRequest();
        request.open("GET", pathOfFileToReadFrom, false);
        request.send(null);
        var returnValue = request.responseText;

        return returnValue;
    }
}

main();

function progressBarSim(al) {
  var bar = document.getElementById('bar-fill');
  var status = document.getElementById('status');
  status.innerHTML = al+"%";
  bar.value = al;
  al++;
var sim = setTimeout("progressBarSim("+al+")",1000);
if(al == 100){
 status.innerHTML = "100%";
 bar.value = 100;
 clearTimeout(sim);
 var finalMessage = document.getElementById('finalMessage');
 finalMessage.innerHTML = "Process is complete";
}
}
var amountLoaded = 0;
progressBarSim(amountLoaded);

The Progressbar does currently work over an Timer, because the main() function doesnt read the content of the "progress.txt" from the beginning but only at the end. so i would like to have some help to combine progressBarSim with main().

*Edit: * I have found a working piece of code: http://www.it-gecko.de/html5-file-upload-fortschrittanzeige-progressbar.html and am using that now.

hardking
  • 193
  • 2
  • 17
  • Have you really understand what ajax is? It looks like you don't, Ajax is used to call a php script and get the reponse from it without reloading the page in browser. So what you are using here isn't Ajax and it couldn't work, because the php will be executed first and entirely. So when the browser uses the main function it is logical that the file said it is finished. – MisterJ Feb 18 '14 at 14:28
  • your using also ffmpeg? – cocco Feb 18 '14 at 14:31
  • i am not using ffmpeg and dont have much experience with javascript and ajax, thats why i made this mistake. – hardking Feb 18 '14 at 15:02

1 Answers1

0

Here is a ajax function for modern browsers:

//url,callback,type,FormData,uploadFunc,downloadFunc
function ajax(a,b,e,d,f,g,c){
 c=new XMLHttpRequest;
 !f||(c.upload.onprogress=f);
 !g||(c.onprogress=g);
 c.onload=b;
 c.open(e||'get',a);
 c.send(d||null)
}

more about this function https://stackoverflow.com/a/18309057/2450730

here is the html

<form><input type="file" name="file"><input type="submit" value="GO"></form>
<canvas width="64" height="64"></canvas>
<canvas width="64" height="64"></canvas>
<pre></pre>

you can add more fields inside the form and you don't need to change anything in the javascript functions. it always sends the whole form.

this is the code to make this ajax function work

var canvas,pre;
window.onload=function(){
 canvas=document.getElementsByTagName('canvas');
 pre=document.getElementsByTagName('pre')[0];
 document.forms[0].onsubmit=function(e){
  e.preventDefault();
  ajax('upload.php',rdy,'post',new FormData(this),progressup,progressdown)
 }
}
function progressup(e){
 animate(e.loaded/e.total,canvas[0],'rgba(127,227,127,0.3)')
}
function progressdown(e){
 animate(e.loaded/e.total,canvas[1],'rgba(227,127,127,0.3)')
}
function rdy(e){
 pre.textContent=this.response;
}

this is the animation that moves the circular canvas progress bar

function animate(p,C,K){
var c=C.getContext("2d"),
x=C.width/2,
r=x-(x/4),
s=(-90/180)*Math.PI,
p=p||0,
e=(((p*360|0)-90)/180)*Math.PI;
c.clearRect(0,0,C.width,C.height);
c.fillStyle=K;
c.textAlign='center'; 
c.font='bold '+(x/2)+'px Arial';
c.fillText(p*100|0,x,x+(x/5));
c.beginPath();
c.arc(x,x,r,s,e);
c.lineWidth=x/2;
c.strokeStyle=K;
c.stroke();
}

you can extend this function with some nice bounce effect on initializzation or on progresschange.

http://jsfiddle.net/vL7Mp/2/

to test i would just simply use a upload.php file like that

<?php
print_r(array('file'=>$_FILE,'post'=>$_POST));
?>

test it with chrome first... then apply the necessary changes to use it with older browsers... anyway this code should work with all the newest browsers now.

i understand that this functions are not simple to understand so ...

if you have any questions just ask.

maybe there are some syntax error or something is missing... because i just copied the whole functions and applied some changes on the fly.

some other useful functions:

display a readable filesize:

https://stackoverflow.com/a/20463021/2450730

convert MS to time string or a time string to MS

function ms2TimeString(a){
 var ms=a%1e3>>0,s=a/1e3%60>>0,m=a/6e4%60>>0,h=a/36e5%24>>0;
 return (h<10?'0'+h:h)+':'+(m<10?'0'+m:m)+':'+(s<10?'0'+s:s)+'.'+(ms<100?(ms<10?'00'+ms:'0'+ms):ms);
}
function timeString2ms(a){
 var ms=0,b;
 a=a.split('.');
 !a[1]||(ms+=a[1]*1);
 a=a[0].split(':'),b=a.length;
 ms+=(b==3?a[0]*3600+a[1]*60+a[2]*1:b==2?a[0]*60+a[1]*1:s=a[0]*1)*1e3;
 return ms
}

A simple PAD LEFT function

function padL(a,b,c){//string,length=2,char=0
 return (new Array(b||2).join(c||0)+a).slice(-b);
}

ps.i'm also working on a conversion progress bar. if you are intrested i can show you my progress.

Community
  • 1
  • 1
cocco
  • 16,442
  • 7
  • 62
  • 77
  • okay, this code seem to work, but its difficult for me to understand the javascript code. i need to rewrite it because it seems to "print_r" the current file WITHOUT speciyfiyng this in the upload.php-file (i dont know why). you dont need to solve this i will have to find out for myself. the thing is i dont understand why it works in the form without having an 'action=""'-tag and i dont understand why it makes an "print_r". I also dont understand why i cant use `move_uploaded_file($_POST['file'], 'path/to/my/files');` – hardking Feb 18 '14 at 15:29
  • this is html5 new FormData .. that does not need any attributes inside the form.the print_r is just heere to show you whats uploading. and about php ... you have probably problems with the max_upload_size .. max_execution_time max_post_size... or some permissions. – cocco Feb 18 '14 at 15:52
  • Okay, thats fine ive tested it upon those values in the php.ini, but it seems to have a problem to execute it upon upload.php, no matter where i put the script or how i set the path, it doesnt call that file, so i cant use the POST- or FILE data... I have also tried it inside of a fresh project, where all files are in the same folder and it doesnt load the "upload.php code" for small files or big files, maybe yo've forgotten something to copy? (thanks beforehand, thats really great work!) – hardking Feb 18 '14 at 16:29