PHP Extention: Wann MySQLi statt MySQL benutzen?

Beim Starten eines Projektes oder bei Verwendung einer fertigen Webapplikation, welche/s auf PHP basiert, kommt man unweigerlich oftmals zu der Frage: Soll ich die MySQLi- oder MySQL-Bibliothek von PHP nutzen.

Die Frage lässt sich heute in 99,9% der Fälle mit MySQLi beantworten. Ausnahmen hierbei sollte es eigentlich nur sehr wenige geben. Eine Ausnahme könnte sein, dass man ein Module für eine Applikation schreibt, welche immer noch die MySQL-Erweiterung nutzt, nur dann stellt sich auch die Frage, ob diese Applikation noch genutzt werden sollte. Alternativ zu MySQLi lässt sich natürlich auch der Datenbankabstraktion-Layer PDO verwenden.
Wieso gerade MySQL nicht mehr verwendet werden soll, ist recht simple. MySQL wird nicht mehr wirklich gewartet, es werden nur noch die nötigsten Dinge erledigt (kritische Sicherheitsupdates), und ab PHP 6 wird es auch nicht mehr unterstützt werden, das heißt lieber jetzt umstellen, um später weniger Arbeit mit der Umstellung zu haben. Als Plus gibt es bei MySQLi zudem noch eine komplett Unterstützung von MySQL 4.1+.

Als kleine Übersicht nochmal die Tabelle von php.de zu diesen Thema ergänzt mit den bisherigen Informationen zu PHP 6:

Funktion MySQLi PDO MySQL
SSL-Verbindung
Eingeführt in PHP Version 5.0 5.0 3.0 und früher
In PHP 5.x verfügbar Ja Ja Ja
In PHP 6.0 verfügbar Ja Ja Nein
MySQL Entwicklungsstatus aktive Entwicklung aktive Entwicklung (as of PHP 5.3) nur Wartung
Empfehlung von MySQL für neue Projekte Ja – vorzugsweise Ja Nein
API Unterstützt Zeichensätze Ja Ja Nein
API Unterstützt serverseitige Prepared Statements Ja Ja Nein
API Unterstützt clientseitige Prepared Statements Nein Ja Nein
API Unterstützt Stored Procedures Ja Ja Nein
API Unterstützt Multiple Statements Ja weitestgehend Nein
Unterstützt alle MySQL 4.1+ Funktionen Ja weitestgehend Nein

Apache Sicherheit bei Verwendung von PHP

Sicherheit in Webanwendungen ist immer ein großes Thema, dazu gehört auch die sichere Einbindung des PHP-Modules in den Apache httpd Webserver. In diesen Artikel behandele ich kurz, wie PHP in den Apache eingebunden wird und nur von Dateien mit der Endung .php oder .php5 ausgeführt wird, und weshalb hier eine Sicherheitslücke lauern kann.

Wieder mal ist ein sogenanntes Future vom Apache Httpd Auslöser eines Exploits, diesmal bei WordPress.

Grundlegend kann man sich nun Fragen, liegt der Fehler nun beim Apache Httpd, bei WordPress oder beim Administrator des Apache Httpds? Nun, bei gesamter Betrachtung hat jeder etwas Schuld, aber das tut nichts zu Rolle. Interessanter ist es, wie ich als Administrator eines Apache Httpds nicht Opfer dieses Exploits geworden wäre, bzw. der Exploit keine Auswirkungen auf mein System hat.

Um zu verstehen, was hier passiert ist, eine kurze Erklärung des Exploits. Hier entsteht eine Lücke durch ein Future vom Apache Httpd, welche vom WordPress nicht abgefangen wurde. Dieses Future greift vornehmlich bei mehrfachen Dateiendung (bspw. archive.tar.gz oder image.php.jpg), es arbeitet den Dateinamen von rechts nach links ab, um einen diese einen entsprechenden Dateityp zu zuordnen. Wenn bei nun die für die Endung .jpg kein Dateityp im Apache httpd hinterlegt ist, nimmt er sich die nächste Stelle, was bei einer Datei mit den Namen image.php.jpg, die Endung .php wäre. Somit wird die Datei den Typ PHP zugeordnet und wird durch den PHP Parser geschickt und ausgeführt.

[…]
Files with Multiple Extensions

Files can have more than one extension, and the order of the extensions is normally irrelevant. For example, if the file welcome.html.fr maps onto content type text/html and language French then the file welcome.fr.html will map onto exactly the same information. If more than one extension is given that maps onto the same type of meta-information, then the one to the right will be used, except for languages and content encodings. For example, if .gif maps to the MIME-type image/gif and .html maps to the MIME-type text/html, then the file welcome.gif.html will be associated with the MIME-type text/html.

Languages and content encodings are treated accumulative, because one can assign more than one language or encoding to a particular resource. For example, the file welcome.html.en.de will be delivered with Content-Language: en, de and Content-Type: text/html.

Care should be taken when a file with multiple extensions gets associated with both a MIME-type and a handler. This will usually result in the request being handled by the module associated with the handler. For example, if the .imap extension is mapped to the handler imap-file (from mod_imagemap) and the .html extension is mapped to the MIME-type text/html, then the file world.imap.html will be associated with both the imap-file handler and text/html MIME-type. When it is processed, the imap-file handler will be used, and so it will be treated as a mod_imagemap imagemap file.

[…]

Quelle: http://httpd.apache.org/docs/2.2/mod/mod_mime.html

Also was sollte man als Administrator eines Apache Httpds machen?

Nun, erstmal sollte dafür gesorgt werden, dass Dateien nur durch den PHP Parser gelangen, wenn die Dateiendung auch wirklich den Abschluss der Datei bildet. Bei Debian Lenny kann dies wie folgt erreicht werden:

/etc/apache2/mods-enabled/php5.conf

<IfModule mod_php5.c>
  AddType text/plain .php .phtml .php3 .php4 .php5
  <FilesMatch "\.php5?$">
    AddType application/x-httpd-php .php .php5
    AddType application/x-httpd-php-source .phps
    SetHandler application/x-httpd-php
  </FilesMatch>
</IfModule>

Damit hätte man als Administrator eines Apache Httpds schon mal sorgfältiger gehandelt und der beschriebene Exploit wäre gar nicht möglich gewesen. Trotz allen müssen PHP-Anwendung, wie WordPress, umsichtig genug entwickelt werden, dass der Exploit gar nicht erst vorhanden ist.

Hinweis: Falls nun jemand meint, der SetHandler würde reichen, der irrt, zu mindestens bei Debian Lenny wird es nicht funktionieren, erst mit den oben gezeigten Beispiel arbeitet der Apache 2.2 zuverlässig, so wie es gewollt ist.

PHP: Dateinamen für Windows / CIFS

Ich weiß nicht, ob das nun der Weisheit letzter Rat ist, aber bei mir hat er mit Hilfe dieser kleinen Funktion sauber auf CIFS (SMB 1) geschrieben. Vielleicht hilft es ja den Einen oder Anderen etwas.

/**
 * tranform the filename inclusive path to the cifs filename charset
 *
 * @param string $filename;
 * @return string
 */
function cifs_file_charset ( $filename )
{
   if ( !is_string($filename) )
   {
      exit('wrong parameter for $filename');
   }

   /* first the lower bit encodings, otherwise the higher bit encoding will be
    * detected and the next step will return strange results or nothing
    * mb_convert_encoding without the three parameter will fail as well
    * Bug: If the real encoding of the string is utf-8, it detect the ISO-encoding first
    *   (PHP 5.3.0)
    */
   $encoding = mb_detect_encoding($filename, 'iso-8859-1, iso-8859-15, utf-8, auto', true);
   /* CP1252 seems to be the right file charset für CIFS (aka SMB 1) */
   $filename = mb_convert_encoding($filename, 'CP1252', $encoding);

   return $filename;
}