preload
Aug 27

In vielen PHP-Anwendungen findet man immer wieder mal die Funktion, eine Datei herunterzuladen, die nicht im Document-Root des Servers liegt. Hierzu wird dann ein kleines download-Skript erstellt, das in der Regel den gewünschten Dateinamen als Parameter erhält und dann die Datei direkt zum Browser ausgibt. Bequemerweise stellt PHP dafür die Funktion readfile zur Verfügung. Ein typischer Codeblock sieht dann ungefähr so aus:

if (isset($_GET["file"])) {
   $sFileName = $_GET["file"];
   // check for invalid file paths and preceed with file archive directory
   $sFile = getFullFileName($sSubDir);
   if (file_exists($sFile)) {
     header("Content-type: application/x-download");
     header("Content-Disposition: attachment; filename=$sFileName");
     header("Content-Transfer-Encoding: binary");
     header('Content-Length: ' . filesize($sFile));
     ob_clean();
     flush();
     readfile($sFile);
   }
}

Wichtig ist dabei die Verwendung von ob_clean() und flush() nach dem Senden der Header-Angaben. Ansonsten werden speziell Dateien mit Binärdaten nicht korrekt übermittelt und lassen sich dann beim Empfänger ggf. nicht öffnen.

Aug 14

Möchte man dynamisch eine Tabellenzeile per Javascript ausblenden, erreicht man dies durch die Zuweisung wie in folgendem Beispiel zum Verstecken der zweiten Zeile:

var oTR = document.getElementById(‘TableID’).rows[1];
oTR.style.display = ‘none’;

Möchte man die Zeile nun wieder anzeigen, erwartet ein korrekter Browser eigentlich das Setzen der Display-Eigenschaft auf “table-row”, also:

oTR.style.display = ‘table-row’;

Dies interpretiert der Internet Explorer allerdings nicht korrekt, er erwartet ein “display = ‘block’”, was wiederum in W3C-kompatiblen Browsern versagt. Die Lösung liegt in der Zuweisung eines Leerstrings an die Eigenschaft, also

oTR.style.display = ”;

Dies wird von (allen?) Browsern richtig verstanden.

Aug 07

Es ist schon mehrfach aufgetreten, dass Seiten, die mittels exec() Programme ausführen, urplötzlich hängen. Eine genauere Analyse ergab, dass dieses Problem auftritt, wenn der Server den ersten Request noch nicht abgearbeitet hat, jedoch der Benutzer im Browser schon wieder auf einen Link geklickt hat. Ruft der zweite Request auch exec() auf, hängt der Server. Es handelt sich dabei weder um ein Problem des Servers (bspw. Apache, IIS, Tomcat, usw.) noch um ein Problem des mit exec() ausgeführten Programms (bspw. GhostScript, ImageMagick, sonstige.com, usw.exe).

Das Problem liegt in diesem Fall bei PHP. Da die Session noch in Verwendung ist, während der nächste Request bereits versucht, einen zweiten Prozess mit der selben Session zu öffnen, hängt der Server, falls das ganze während der Ausführung von exec() stattfindet. Die Lösung dieses Problems ist es, die Session vor dem Aufruf von exec() zu schließen und sie direkt im Anschluss wieder zu starten:

<?php
  ...
  session_write_close();
  exec($sCommand);
  session_start();
  ...
?>

Durch das Schließen der Session kommt es nicht mehr zum Hängen des Servers. Das erneute Öffnen nach dem Aufruf von exec() garantiert, dass alle vor Beendigung des Skriptes erfolgenden Session-Zugriffe korrekt ablaufen.

Links zu diesem Problem:

Aug 05

Ein Datum kann, abhängig von der Maske, in der es angegeben werden muss, richtig sein, also bspw. 11.11.1998 oder 2004-04-05. Ein korrekt formatiertes Datum muss aber nicht zwangsweise auch existieren, wie bspw. 2009-02-31, also der 31. Februar 2009. Hierfür kann die PHP-Funktion checkdate($iMonth, $iDay, $iYear) verwendet werden, die ein gregorianisches Datum auf Gültigkeit prüft. Bevor die Funktion aufgerufen werden kann, muss die Datums-Zeichenkette in ihre einzelnen Teile zerlegt werden, also bspw. wie folgt:

<?php
  $iYear = intval(...);
  $iMonth = intval(...);
  $iDay = intval(...);
?>

Nun lässt sich mit checkdate einfach prüfen, ob das Datum wirklich gültig ist:

<?php
  $bDateIsValid = checkdate($iMonth, $iDay, $iYear);
?>

Zu beachten ist, dass checkdate laut Definition Integerwerte erwartet.