Tutorial: Anzeige des Upload-Status mit Ajax und PHP (PECL :: uploadprogress)

von Stefan Jutzi am Mittwoch, 29. März 2017

Lange Zeit galt es als unmöglich, den Status eines Uploads nur mit Hilfe von PHP zu ermitteln. Die PECL Erweiterung uploadprogress ermöglicht diese heiß ersehnte Möglichkeit.

Leider ist es ziemlich schwierig, eine Dokumentation zu finden. Daher möchte ich euch hier kurz erklären, wie man diese Erweiterung nutzen kann. Das Ergebnis sieht dann in etwa so aus:

Screenshot Upload Progress

Installation

Das Kernstück ist natürlich die Erweiterung. Diese kannst du unter http://pecl.php.net/package/uploadprogress herunterladen. Wenn du auf einem Linux-Server php5-dev installiert hast, kannst du die Erweiterung einfach mit folgendem Befehl installieren:

pecl install uploadprogress

Anschließend muss die Erweiterung noch in der php.ini aktiviert werden:

extension=uploadprogress.so

Falls du Windoofs nutzt oder Probleme bei der Installation hast, findest du unter http://freestylesystems.co.uk/blog/installng-pecl-uploadprogress-extension-drupal-filefield-module eine gute Installations-Anleitung.

Upload-Formular

Um die Datei identifizieren zu können, die gerade hochgeladen wird, muss diese eine ID bekommen. Diese wird in einem Hidden-Feld mit dem namen „UPLOAD_IDENTIFIER“ definiert. Dieses Hiddenfeld muss zwingend vor dem Upload-Feld kommen, sonst kann nicht darauf zugegriffen werden.

Außerdem benötigen wir ein leeres DIV, wo wir später die Progressbar einbinden.

<form enctype="multipart/form-data" action="" method="post">
    <input type="hidden" name="UPLOAD_IDENTIFIER" id="UPLOAD_IDENTIFIER" value="<?php echo $id; ?>" />
    Select file: <input name="thefile" type="file">
    <input type="submit" value="upload" onclick="setTimeout('updateProgress()', 1000);">
</form>

<div id="progress">
    <b>Dateiupload:</b> <span id="uploadFileName"></span><br />
    <div id='progressbarWrapper'>
        <div id='progressbar' style='width:0%;'> </div>
        <div id='progressbarInfo'>
            <span id="uploadedBytes"></span> / <span id="uploadTotalBytes"></span> <span id="uploadUnit"></span> (<span id="uploadPercent"></span> %)
        </div>
    </div>
    <b>Geschwindigkeit:</b> <span id="uploadSpeed"></span> kB/s<br />
    <b>Geschätzte Dauer: <span id="uploadTimeLeft"></span> Sekunden
</div>



Ermittlung des Fortschritts

Der Upload-Status wird durch ein kleines PHP-Script ermittelt. Diesem Script wird die ID des Uploads übermittelt. Mit Hilfe dieser ID kann man mit der Funktion uploadprogress_get_info($id) alle wichtigen Informationen zum laufenden Upload ermitteln. Rückgabewert ist ein Assoziatives Array mit Dateinamen, Gesamtgröße der Datei, bereits hochgeladene Menge, geschätzte Dauer und Durchschnittsgeschwindigkeit.


= (1024*1024)) {
	$unit = "MB";
	$total = $total / (1024*1024);
	$uploaded = $uploaded / (1024*1024);
} else {
	$unit = "kB";
	$total = $total / 1024;
	$uploaded = $uploaded / 1024;
}

$uploaded = number_format($uploaded, 1, ",", ".");
$total = number_format($total, 1, ",", ".");

echo '{"file":"'.$name.'","percent":'.$percent.',"uploaded":"'.$uploaded.'","total":"'.$total.'","unit":"'.$unit.'","speed":"'.$speed.'","left":"'.$time_left.'"}';
?>

Start der Statusermittlung durch ein Ajax-Request

Die Ermittlung des Upload-Fortschritts wird beim Start des Uploads (etwas zeitverzögert) durch ein Ajax-Request gestartet. Dazu erweitern wir den Absendebutton um den Event-Handler:

<input type="submit" value="senden" onclick="setTimeout("updateProgress()", 1000);">

Mein dazugehöriges Javascript sieht so aus:

<script type="text/javascript">
var xmlHttp = null;
var work = 0;
var stamp;
if (window.ActiveXObject)  {
        try {
                xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e) {
                try {
                        xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                }
        }
} else if (window.XMLHttpRequest) {
        try {
                xmlHttp = new XMLHttpRequest();
        } catch (e) {
        }
}

var uploadID = '';


function $(obj) {
	return document.getElementById(obj);
}

function updateProgress() {
	stamp = new Date() * getRandom();
	if (work == 0) {
		work = 1;
		xmlHttp.open('GET', './ajax.php?id=' + uploadID + "&" + stamp, true);
		xmlHttp.onreadystatechange = reloadProgress;
		xmlHttp.send(null);
	} else setTimeout("updateProgress()", 100);
}

function reloadProgress() {
	if (xmlHttp.readyState==4) {
		work = 0;
		text = xmlHttp.responseText;
		var upload = eval("("+text+")");
		if (upload["percent"] < 100) {
			$('progress').style.display="block";
			$('progressbar').style.width = upload["percent"] + "%";
			$('uploadFileName').innerHTML = upload["file"];
			$('uploadedBytes').innerHTML = upload["uploaded"];
			$('uploadTotalBytes').innerHTML = upload["total"];
			$('uploadUnit').innerHTML = upload["unit"];
			$('uploadPercent').innerHTML = upload["percent"];
			$('uploadSpeed').innerHTML = upload["speed"];
			$('uploadTimeLeft').innerHTML = upload["left"];

			setTimeout("updateProgress()", 1000);
		} else $('progress').style.display="none";
	}
}

function getRandom() {
        return parseInt(Math.random()*1000000)+1;
}

</script>

Download

Ein funktionierendes Beispiel gibt es natürlich auch zum Download. Du kannst dieses Beispiel und die darin enthaltenen Grafiken (von mir erstellt) gern verwenden. Natürlich wäre ich dir im Gegenzug für eine Verlinkung auf diesen Beitrag dankbar.

progress.zip (5,1 kB)

progress.tar.gz (4,4 kB)


Copyright © 2018 Stefan Jutzi Webdesign