Ulf Wendel

Warum ich ext/mysql mag…

Es gibt drei Extensions mit deren Hilfe ein PHP-Skript auf einen MySQL Server zugreifen kann: ext/mysql, ext/mysqli und PDO_MYSQL. Alle drei sind geeignet, um die Entwicklungsgeschichte von PHP und MySQL Revue passieren zu lassen, alle drei sind geeignet, um Kopfschütteln oder Staunen hervorzurufen. Heute: Grundlagen des Verbindungsaufbaus mit ext/mysql – wie verbinde ich PHP mit MySQL?

Was wird folgendes Kommando ausgeben?

time MYSQL_TCP_PORT=3307 sapi/cli/php -r '$link = mysql_connect("127.0.0.1", "root", "root"); mysql_query("SELECT SLEEP(10)"); var_dump($link);' 

Um zu beantworten was passieren wird, ist es notwendig das Betriebssystem, die verwendete Client Bibliothek und mindestens eine PHP-Konfigurationsdirektive zu kennen. Das Betriebssystem ergibt sich aus dem Beispiel: es ist ein Unix. Die verwendete Client Bibliothek ist MySQL Client Library (libmysql). Es ist ein Standardbuild, genauso wie PHP und MySQL unverändert aus der Tüte gefallen sind. Es wurden keine PHP-Konfigurationsdirektiven gesetzt und die Standardeinstellungen von PHP 5.3 werden benutzt.

Das Betriebssystem und die PHP-Konfigurationsdirektive mysql.default_port entscheidet darüber ob das Setzen der Umgebungsvariablen MYSQL_TCP_PORT einen Einfluß auf ext/mysql hat. Unter Windows oder Netware wird die Umgebungsvariable nicht ausgewertet. Im Beispiel wird ein Unix verwendet. Auf diesem System wird die Umgebungsvariable einen etwaigen “mysql” Eintrag aus der TCP-Sektion in /etc/services überstimmen, sofern kein Wert für mysql.default_port gesetzt ist, welches die Standardeinstellung ist. Ist das dokumentiert? Ja, in der php.ini-production findet sich eine Notiz. Dort wird auch die Bedeutung des Compile-Flags MYSQL_PORT erklärt.

Da als Hostname die IP-Adresse “127.0.0.1” angegeben ist und der Port 3307 benutzt wird gemäß der Umgebungsvariable MYSQL_TCP_PORT, baut die MySQL Client Library (libmysql) eine TCP/IP Verbindung auf. Die Verbindung schlägt fehl, weil es sich beim MySQL Server um eine Standardinstallation handelt, die auf Port 3306 horcht. Der Fehler führt zu einer PHP Warnung die, je nach Wert der PHP-Direktive error_reporting, leicht übersehen werden kann: Warning: mysql_connect(): Lost connection to MySQL server at 'reading initial communication packet', system error: 111 in Command line code on line 1.

Anschließend macht PHP unbeirrt weiter und der Aufruf von mysql_query() baut implizit eine neue Verbindung auf, weil – wie bei ext/mysql üblich und möglich – kein Handle angegeben wurde. Ja, das ist dokumentiert. Die Verbindung wird zum Host = NULL auf Port 3307 aufgebaut. Host = NULL findet Anwendung, weil kein Wert für die PHP-Konfigurationsdirektive mysql.default_host gesetzt ist. Eine leere Hostangabe bewirkt unter Unix in der MySQL Client Bibliothek einen Fallback auf localhost und Unix Domain Sockets. Auf Windows würde etwas anderes passieren.

Mit der Hostangabe localhost und mit dem Standardwert einer leeren PHP-Konfigurationsdirektive mysql.default_socket wird das Socket /tmp/mysql.sock verwendet. Aber auch nur, wenn es sich um einen Standardbuild von PHP handelt, PHP_MYSQL_UNIX_SOCK_ADDR nicht beim Kompilieren definiert wurde und es sich auch um einen Standardbuild der MySQL Client Library handelt. Ist das dokumentiert? Sicher, ich habe es doch hiermit gerade dokumentiert!

Schlußendlich gelingt es SELECT SLEEP(10) über einer Unix Domain Socket Verbindung an MySQL zu senden und das Skript wird nach etwa 10 Sekunden beendet. var_dump($link) gibt false aus, da der Verbindungsaufbau fehlgeschlagen ist. Hier noch einmal das korrekte und fehlerfreie Ergebnis im Ãœberblick:

time MYSQL_TCP_PORT=3307 sapi/cli/php -r '$link = mysql_connect("127.0.0.1", "root", "root"); mysql_query("SELECT SLEEP(10)"); var_dump($link);'          

Warning: mysql_connect(): Lost connection to MySQL server at 'reading initial communication packet', system error: 111 in Command line code on line 1
bool(false)

real    0m10.024s
user    0m0.008s
sys     0m0.004s

Alles gaaanz easy…. Und bloß nicht ext/mysqli verwenden. Das baut nicht implizit Verbindungen auf, unterbindet die Verwendung von Umgebungsvariablen, verhindert das Bauen von optimierten und angepassten Binaries mit verbesserten Standardeinstellungen, verlangt bei jedem Kommando die Angabe eines Verbindungshandle und unterstützt neben irrelevanten Dingen wie Prepared Statements auch noch performanzkritische C API Funktionen wie mysql_warning_count().

Comments are closed.