Gestern ist bei meiner Webshop-Entwicklung mal wieder ein Problem aufgetreten, an dass ich auf Anhieb nie gekommen wäre.
Es geht um einen Bilderupload in einem separaten Popup mit anschließendem Schließen des Popups.
Frech wie ich bin, habe ich den Aufruf des Submit-Buttons einfach über ein Javascript simuliert mit:

 document.forms[0].submit(); //erstes Form submitten
 window.opener.location.reload();  //refresh des aufrufenden Fensters
 window.close();

Problem dabei: Durch die langsame Netzwerkverbindung war das submit noch nicht fertig als das Fenster geschlossen wurde, so dass in manchen Fällen die Bilder nicht hochgeladen wurden.

Aufgrund dessen, habe ich erst einmal die beiden letzen Befehle ausgebaut.
Tja, dann lief zwar der Bilderupload, aber bei größeren Bildern (>60K) musste man schon so seine 2-3 Sekunden warten, bis das Bild dann endlich angezeigt wurde.
Da das eher unbefriedigend ist und ein Benutzer dann eher doppelt und dreifach klickt wenn nichts passiert, habe ich überlegt ein Ladefenster nach dem Web2.0-Gedanken einzublenden. Aber wie machen? Scriptaculous, Prototype und Modalbox für solch ein simples Fenster zu installieren, einzurichten, mich darin einzuarbeiten und es auszuprogrammieren war mir dann doch etwas zu aufwändig. Also habe ich ein wenig gegoogelt, einige meiner Kenntnisse aufgefrischt und entstanden ist dieses Tutorial:

Bevor wir anfangen sollten wir ein schickes Lade-Fenster entwerfen. Dazu einen Bild-Editor wie Gimp, Photoshop, Paint Shop Pro, Artweaver oder was auch immer öffnen. Damit das Fenster nicht zu groß wird, erstellen wir ein Bild mit 200 x 80 Pixeln. Das sollte eigentlich für unsere Zwecke reichen. Für die Erstellung des Bildes nutze ich Artweaver. Das ist kostenlos und kann sogar auf einem USB-Stick installiert und somit überall mitgenommen werden. Außerdem ist es für Photoshop-Kenner genauso zu bedienen, auch wenn viele Funktionen fehlen. Aber für unsere Zwecke reichts.
Wie schon gesagt, wir erstellen erst mal ein 200 x 80 großes Bild. Der Hintergrund ist egal

Über File->New bzw. Datei->Neu wird ein neues Bild angelegt:

Nun markieren wir mit dem Auswahl-Symbol: die ersten ca 20 Pixel auf der gesamten Breite. ( Bei mir sind es glaube ich 21 Pixel geworden, aber das ist irrelevant). Besonders gute weiche Bilder lassen sich durch Einstellen von Feather und dem eingeschalteten Anti-Aliasing erreichen.

Nun wählen wir das Verlauf-Symbol und die passenden Verlauf-Farben für Vorder- und Hintergrund. Da mein zu entwickelnder Webshop als Basisfarbe verschieden Grautöne besitzt, habe ich einen mittleren Grauton für die Hintergrund und einen etwas helleren Grauton als Vordergrund genutzt.
Den Verlauf von oben nach unten zeichnen und es dürfte sich ein Bild ähnlich wie dieses ergeben:

Nun mit Ctrl+Shift+I die Auswahl invertieren, die Farben heller machen und dann noch einmal den Verlauf von unten nach oben (oder auch von oben nach unten, wie es beliebt) durchführen.

Als Ergebnis erhält man dann einen Bildschirm, der zwar nicht nach Hightec aber immerhin auch nicht so schlimm aussieht:

 

Ggf. kann man den Bildschirm noch umrahmen, aber das können wir auch direkt in der Webseite machen.

Mit dem so vorbereiteten Bildschirm schauen wir erst mal unser Formular an. Das Formular wird in ein PHP-Script eingebettet, entweder mit einer Template-Engine oder in unserem simplen Fall direkt ausgegeben.
Wir speichern das Script als bildUpload.php ab und können es anschließend auch schon mal aufrufen.

<?php 
echo '<html>
 <head>
   <title>Test-Formular zum Bilder-Upload</title>
 </head>
 <body>
    <form action="bildUpload.php" method="POST" enctype="multipart/form-data" style="width: 500px; border: 1px solid black; height: 400px;">
        <p><img src="getImage.php" style="max-height: 300px; max-width: 3000px"></p> <!-- Das Bild wird dynamisch über PHP geladen -->
        <input type="file" id="uploadBild" name="uploadBild" accept="images/*" >
        <input type="submit" id="submitButton" name="submitButton" value="Bild hochladen" />
    </form>
 </body>
</html>';?>

Hm, natürlich fehlt die Verarbeitung und das Script getTestImage.php haben wir auch noch nicht geschrieben. Die
Darstellung des Bildes kommt später.
Fangen wir mal mit der Verarbeitung an. Für das Tutorial speichere ich das Bild erst mal nur in der Session ab. Prinzipiell sollte man Bilder aber lieber auf dem Dateisystem oder in der Datenbank speichern. Um die Logik einfach zu halten, mache ich es aber trotzdem:

Dazu legen wir als erstes eine Klasse an, in der unsere Bilddaten gespeichert werden kann.

<?php
     //wir legen mal eine Klasse an, die uns alle Bild-Informationen kompakt in einem Objekt speichert
   class Bild
   {
      /** Name des Bildes, den können wir dann beim Auslesen ggf. mitgeben*/
	  public $name;
	  
	  /** Content-Type des Bildes*/
	  public $contentType;
	  
	  /** Inhalt des Bildes als Binär-Stream */
	  public $content;
   }
?>

Dieses Klasse wird in der Datei: Bild.class.php abgespeichert.
Als nächstes wird unser Script zum Bilderupload soweit erweitert, dass sie die Files aufnimmt und in einer Session speichert. Die nachfolgenden Zeilen werden vor Ausgabe der HTML-Daten eingefügt:

require_once('Bild.class.php');
 
   //Als erstes prüfen wir mal, ob überhaupt ein Bild hochgeladen wurde und ob der Name des Bildes nicht leer ist
   if (isset($_FILES['uploadBild']['name']) && strlen($_FILES['uploadBild']['name'])>0)
   {
   	  //Nun legen wir ein Bild als Objekt an
   	  $bild = new Bild();
	  //Der Content-Type des Bildes wird gesetzt
   	  $bild->contentType = $_FILES['uploadBild']['type'];
	  //Der Name des Bildes wird gesetzt
   	  $bild->name = $_FILES['uploadBild']['name'];
   	  
	  //Der Content des Bildes wird aus der Temporären Datei gelesen, die der Upload per HTML anlegt. Weiterhin gibt der Upload auch die Größe des Files mit, so dass wir 
	  //ohne umständliche weitere Befehle den Inhalt direkt in einen String lesen können.
	  $bild->content = fread(fopen($_FILES['uploadBild']['tmp_name'], "r"), $_FILES['uploadBild']['size']);
	  
	  //Für Testzwecke packen wir das gelesene Bild einfach  in die Session, normalerweise speichert man das aber in ein File oder in die Datenbank
	  session_start();
	  $_SESSION['uploadBild'] = $bild;
   }

So sieht die Verarbeitung aus. Als erstes wird die von uns angelegte Klasse geladen und wir schauen im $_FILES-Array nach, ob dort Dateien mitgeschickt wurden. Ist dies der Fall, werden die Informationen des Files ausgelesen und in Klassen-Member-Variablen gespeichert.

Anschließend wird eine Session gestartet (oder wiederaufgenommen) und das Bild mit Hilfe des Objektes in der Session abgelegt.

Nun kommen wir zur Implementierung des getImage-Scriptes:

<?php
  //Laden der Bild-Klasse, soweit nicht bereits geschehen
  require_once('Bild.class.php');
  
  //Session starten, um an das hochgeladene Bild zu kommen
  session_start();
  //Wenn ein Bild gesetzt wurde, wird das Bild ausgegeben
  if (isset($_SESSION['uploadBild']))
  {
      //Der Header-Eintrag sagt dem Browser, um was für ein Bild es sich handelt, somit kann er es dann auch anzeigen
     header('Content-Type: '.$_SESSION['uploadBild']->contentType);
     //Die Ausgabe des eigentlichen Inhalts
     print($_SESSION['uploadBild']->content);
  }
?>

Bitte beachtet, dass ihr Bilder, die in die Datenbank geladen werden sollen ggf. mit base_64_encode gespeichert und nach dem Laden mit base_64_decode wieder zurückgewandelt werden müssen.

Last but not least erstellen wir eine HTML-Seite, die unser Formular als Popup aufrufen soll.

<html>
  <head><title>Test-Popup</title></head>
  <body>
    <p><img src="getImage.php" style="max-height: 500px; max-width: 500px" /></p>
    <a href="#" onclick="window.open('bildUpload.php','test','width=550 height=300,scrollbars=no,location=no,directories=no,status=no,menubar=no,toolbar=no,resizable=yes');" >Hier klicken</a>
  </body>
</html>

Zur Veranschaulichung der reload-Funktionalität wird das Bild auch hier hinterlegt.

Schön und gut, nun haben wir erst einmal die Grundlagen geschafft. Wie schließen wir aber unser Popup NACH dem Upload und wie binden wir unser Wartefenster ein?

Um das Wartefenster einzublenden machen wir ein wenig von CSS und Javascript Gebrauch.
Als erstes definieren wir zwei Stylesheet-Klassen, eine “loadingInvisible” für das Wartefenster, wenn es nicht aktiv ist und eine Klasse für ein aktives Fenster.
Das ist total simpel und wird einfach in den Header des HTML-Teils geschrieben:

<style type="text/css">
.loadingInvisible
{
   display: none;
}
.loading
{
     background: url("loadingBackground.png") no-repeat bottom right;
     color: white;
     font-size: medium;
     font-weight: bolder;
     display: block;
     z-index: 1;
     position: absolute;
     left: 180px;
     top: 200px;
     width: 200px;
     height: 80px;
     text-align: center;
     margin: auto;   
}
</style>

Der Trick bei der loading-Klasse ist der z-index. Ich habe lange gebraucht, um die Eigenschaft z-index zu verstehen, aber mit Hilfe von absoluter Positionierung, kann man diese Eigenschaft nutzen, um überlagernde Fenster darzustellen.

Als nächstes müssen wir noch unser div-Tag einbetten. An welcher Stelle im HTML-Code das kommt ist prinzipiell egal, packen wir es am besten ans Ende.

 <div class="loadingInvisible" id="loading">
  <p>Bitte warten</p>
  <p align="center"><img src="ajax-loader.gif" /></p>
 </div>

Ich habe noch das übliche ajax-Loader-Image in den Bildschirm gepackt, dann wirkt das ganze noch etwas besser.

Was noch fehlt ist das Zusammenspiel und das Refresh der Master-Seite und das Schließen des Popups. Aber immer schön nacheinander.

Um die Seite anzuzeigen, wird der Submit-Button zu einem “normalen” Button umgewandelt und ein Javascript in beim Klick aufgerufen.

Das javascript wird im Header definiert und sieht folgendermaßen aus:

 <script type="text/javascript">
  function showLoading()
  {
        document.getElementById("loading").className="loading";
       	//Firefox & Co
	if (window.innerWidth)
	{
	    document.getElementById("loading").style.left = new Number(window.innerWidth / 2 -100).toString()+"px";
        document.getElementById("loading").style.top = new Number(window.innerHeight / 2 - 40).toString()+"px";
	}
	//IE
        else
	{
		document.getElementById("loading").style.left = new Number(document.body.offsetWidth / 2 - 100).toString()+"px";
		document.getElementById("loading").style.top = new Number(document.body.offsetHeight / 2 - 100).toString()+"px";
	}
    return true;
 
  }
  function submitBilderUpload()
  {
      showLoading();
      document.forms[0].submit();
  }
</script>

Die erste Funktion setzt die Klasse des loading-Div-Tags auf loading, dadurch wird das Fenster inkl. einem Ladesymbol angezeigt. Die nachfolgenden Zeilen in der showLoading-Funktion sorgen dafür, dass das Fenster mittig im Popup angezeigt wird. Hierbei ist zu beachten, dass Microsoft IE und die anderen Browser mal wieder voneinander abweichen, da in Firefox & Co die Eigenschaften innerWidth und innerHeight definiert sind, währenddessen diese Eigenschaft im Internet Explorer nicht existiert. Dafür wird dann offsetWidth und offsetHeight genutzt.
Das zweite Script zeigt erst das Ladefenster an und submittet dann das Formular. Ist das Formular submittet, verschwindet der Ladebalken automatisch, da die Seite neu aufgebaut wird.

Nun muss noch der Submit-Button ersetzt werden durch:

<input type="button" id="submitButton" name="submitButton" value="Bild hochladen" onclick="submitBilderUpload()"/>

Wird nun auf den Button geklickt, wird nicht sofort submittet, sondern der Submit erfolgt über die Javascript-Methode.

So, das wärs doch fast. Noch das selbst erstellte Bild und das ajax-Loader-Gif  in das Verzeichnis packen und dann….

… stimmt, das Geheimnis des Schließens ist noch zu lüften. Eigentlich ist das ganz einfach. Lösung bietet wiederum Javascript und PHP.

Beim Schreiben des HTML-Codes stellt ihr einfach eine Bedingung mit ein, unter der ein bestimmter Code-Teil eingefügt wird.

Das sieht folgendermaßen aus:

echo '<html>.... usw </div>';
if isset($_FILES['uploadBild']) {echo '<script type="text/javascript"> window.opener.location.reload(); window.close(); </script>';}
echo '</body></html>';

Im Endeffekt wird das Schließen beim Neuladen des Fensters gemacht und zwar genau dann, wenn ein neues Bild hochgeladen wurde.

Viel Spaß beim Ausprobieren und verfeinern.
Hier dann noch mein Beispielcode im gesamten:

Download Beispielcode

Schreibe einen Kommentar

Artikel, die Dir auch gefallen könnten

Remote-Desktop unter Manjaro

Hallo da draußen, Leute die mich etwas besser kennen, wissen, dass ich ein großer Fan von Manjaro Linux bin. Ich nutze das schon seit etlichen

mehr...

Linux und Active Directory

Hallo Welt da draußen, heute bin ich mal wieder fast verzweifelt. Ein bisschen habe ich mich an meine Zeiten als Angestellter mit dem Projekt der

mehr...