PHP 5 nach PHP 7: Umstellung von MySQL-Funktionen

Die angekündigte Umstellung der PHP-Version von 5 auf 7 auf den zentralen Webservern bringt für Autoren von PHP-Webanwendungen, die auf eine MySQL-Datenbank zugreifen, möglicherweise einiges an Programmierarbeit mit sich: Die alten MySQL-Funktionen, wie mysql_connect() oder mysql_query() funktionieren nicht mehr. Auch lange nicht mehr geänderte Datenbank-Passwörter werden nicht mehr akzeptiert. Wenn also Ihre Webseite(n) mit MySQL-Datenbankzugriff auf dem Testserver www-test.tu-chemnitz.de nicht mehr funktionieren, müssen Sie aktiv werden und finden hier im Folgenden hoffentlich Unterstützung.

Wir empfehlen, die alten mysql-Funktionen durch PHP Data Objects (PDO) zu ersetzen, da man hiermit weitgehend unabhängig von der Datenbank und mit prepared statements ohne großen Aufwand sicher programmieren kann. Unter www.php-einfach.de/mysql-tutorial/crashkurs-pdo finden Sie in einem Crashkurs einen Schnelleinstieg mit den wichtigsten Funktionen. PDO funktioniert auch schon mit PHP 5.4, so dass die Umstellung sofort passieren kann.

Das Datenbank-Passwort

Ich hoffe, dass es jedem Programmierer in den Fingern schmerzt, wenn er ein Passwort im Klartext in eine Datei schreibt:

<?php
$dbpass = 'mein-geheimes-passwort-au-weia!';

Das ist in etwa so, als wenn man den Wohnungsschlüssel unter den  Türvorleger legt – es ist unsicher, man tut es nicht 1). Wie geht es besser? Eine Lösung für den Wohnungsschlüssel haben wir nicht, aber für das Datenbank-Passwort schon: das sichere Geheimnis. Lesen Sie die Anweisungen auf dieser Webseite und folgen Sie den vier Schritten, so dass Sie kein Klartext-Passwort mehr in einer Datei ablegen müssen – und viel ruhiger schlafen können. Ihr Programmcode könnte dann z.B. so aussehen:

<?php
require_once('php/crypt.inc');
# Entschlüsseln des Geheimnisses
$dbpass = decrypt_token('Token1', '1ZMnl+lgmgVQuDrYWaerUw==');

Falls Sie eine Anwendung übernommen haben, in der Ihnen ein abgelegtes Datenbank-Passwort im Klartext entgegenspringt (was jedem Programmierer wiederum Augenschmerzen bereitet):

Diese beiden Schritte sind auch nötig, wenn Sie beim Verbinden zur Datenbank unter PHP 7 diese Fehlermeldung erhalten: „cannot connect to MySQL 4.1+ using the old insecure authentication“.

Umstellung der alten mysql-Funktionen zu PDO

Ihre Webseite mit MySQL-Abfragen geht nicht mehr auf dem Test-Server mit PHP 7? Schauen Sie der Fehler-Logdatei nach: Einsicht für Ihre IP-Adresse.
Finden Sie dort Meldungen wie  „PHP Fatal error: Uncaught Error: Call to undefined function mysql_connect()“ wissen Sie, dass Sie alte mysql-Funktionen ersetzen müssen. Im Folgenden einige Beispiele dazu. Achtung: Den Code unbedingt für Ihre Anwendung anpassen!

mysql_connect(), mysql_select_db() – Verbindung zur Datenbank öffnen

Altes Beispiel:

$db = mysql_connect($dbserver, $dblogin, $dbpass);
mysql_select_db($dbname, $db);

Ersetzen durch:

$db = new PDO('mysql:host=' . $dbserver . ';dbname=' . $dbname, $dblogin, $dbpass);

Wenn Sie sicher sein wollen, dass die Datenbank die Werte in UTF-8-Kodierung ausgibt und entgegen nimmt, schreiben Sie:

$db = new PDO('mysql:host=' . $dbserver . ';dbname=' . $dbname . ';charset=utf8', $dblogin, $dbpass);

Beispiel mit Abfangen eines Fehlers:

try {
    $db = new PDO('mysql:host=' . $dbserver . ';dbname=' . $dbname . ';charset=utf8', $dblogin, $dbpass);
} catch (PDOException $ex) {
    # Konkrete Fehlermeldung $ex->getMessage() nur auf Testserver ausgeben, nicht "in Produktion":
    die('Die Datenbank ist momentan nicht erreichbar. ' . 
        ($_SERVER['SERVER_NAME'] == 'www-test.tu-chemnitz.de' ? htmlspecialchars($ex->getMessage()) : ''));
}

Das erzeugte PDO-Objekt – im Beispiel $db – muss für weitere Funktionsaufrufe verwendet werden.

mysql_query() – Datenbank abfragen

Altes Beispiel:

$res = mysql_query("SELECT * FROM table WHERE id=$id");

Ersetzen durch:

#  prepared statement mit Platzhalter ? = Erhöhung der Sicherheit, da bei execute() eine Kodierung stattfindet
$res = $db->prepare('SELECT * FROM table WHERE id=?');
$res->execute(array($id)) 
    or die('Fehler in der Abfrage. ' . 
           ($_SERVER['SERVER_NAME'] == 'www-test.tu-chemnitz.de' ? htmlspecialchars($res->errorInfo()[2]) : ''));

Für Datenbank-Operationen, wie INSERT, UPDATE, REPLACE und DELETE mit Parametern sollten auch immer prepared statements verwendet werden, z. B.

$ins = $db->prepare('INSERT INTO table (name, vorname, alter) VALUES (?,?,?)');
$res = $ins->execute(array('Schneider', 'Helge', 63)) 
           or die('Fehler beim Einfügen.');

Nähere Erklärung und weitere Beispiele siehe: PHP-Beschreibung für execute()

Abfragen ohne Variablen können auch einfacher geschrieben werden:

foreach ($db->query('SELECT * FROM table') as $row) {      # Abfrage und Ausgabe aller Namen
    echo 'Name: ' . htmlspecialchars($row['name']);        # name ist Spaltenname
}

Siehe PHP-Beschreibung von query()

mysql_num_rows() – Anzahl der Ergebnisse

Altes Beispiel:

if (mysql_num_rows($res) > 0) {

Ersetzen durch:

if ($res->rowCount() > 0) { # Mindestens ein Ergebnis aus der Abfrage mit prepare/execute

mysql_fetch_row(), mysql_fetch_array(), mysql_fetch_assoc() … – Ergebnisse abrufen

Altes Beispiel:

while ($row = mysql_fetch_array($res)) {
    echo 'Name: ' . htmlspecialchars($row['name']);
}

Ersetzen durch:

while ($row = $res->fetch()) {
    echo 'Name: ' . htmlspecialchars($row['name']);
}

Weitere Funktionen

mysql_result() – Rufe einzelne Spalte einer Ergebniszeile ab

Altes Beispiel:

for ($i = 0; $i < mysql_num_rows($res); $i++) {
    $id =  mysql_result($res, $i, 'id');
    # …
}

Ersetzen durch:

while ($row = $res->fetch()) {
    $id = $row['id'];
    # …
}

Einzelnes Ergebnis abrufen

$res = $db->prepare('SELECT COUNT(*) FROM table WHERE feld like ?');
$res->execute(array('%' . $suchwort . '%')) or die('Fehler …');
$anzahl = $res->fetchColumn();    # holt ersten Wert des Ergebnisses

Sie haben noch kein Beispiel für Ihren alten MySQL-Code gefunden und keine Idee, wie Sie diesen umschreiben müssen? Dann wenden Sie sich bitte an uns: webmaster@tu-chemnitz.de

Datenschutz

Denken Sie daran: Wenn Sie personenbezogene Daten verarbeiten, müssen Sie unbedingt Aspekte des Datenschutzes beachten! Neben einer sorgfältigen Programmierung und kontinuierlichen Wartung der Software müssen Sie ein Verzeichnis von Verarbeitungstätigkeiten nach DSGVO erstellen und eigene Datenschutzhinweise veröffentlichen. Fragen Sie bei der Datenschutzbeauftragten der TU Chemnitz nach.

Alternativen

Zweifellos sind die Anforderungen an Webseiten und insb. an Webprogrammierung gestiegen: Funktional und sicher, mehrsprachig, barrierefrei, responsive und datenschutzkonform sollen Webseiten und -anwendungen sein. Berechtigterweise stellt sich die Frage, ob es zur Eigenprogrammierung nicht auch Alternativen gibt. Für sehr viele Aspekte der Organisation von Lehrveranstaltungen und des Universitätsalltages bietet die Lernplattform OPAL Lösungen, ohne selbst Programmcode erstellen zu müssen: Von Einschreibungen und Materialien-Download über Aufgabenverteilung und -abgabe, Selbsttests, Foren und Wikis bis hin zur Terminvergabe für mündliche Prüfungen oder Online-Prüfungen. Wir beraten Sie gern bei der Anpassung der Lernplattform für Ihre Zwecke: e-learning@tu-chemnitz.de


1)
Na gut, höchstens wenn man sich ein Haus mit der lieben Familie oder besten Freunden teilt – analoges gilt für den Webserver: Bei einem PROWeb-Server, den nur vertraute Kollegen mit administrieren, mag das gehen – auf www.tu-chemnitz.de nicht, den teilt man sich mit vielen unbekannten Autoren.

4 Antworten zu „PHP 5 nach PHP 7: Umstellung von MySQL-Funktionen“

  1. Md Abu Yusuf

    Hi
    is it possible to use mysql imporved version instead of PDO for PHP 7.2?

    1. Antje Schreiber

      Yes, it is possible but we advice you on preferring PDO.

  2. David Friel

    Hallo,

    ich habe in einem alten Script folgenden Befehl gefunden:

    mysql_free_result( $db_erg );

    Wenn ich diese Zeile auskommentiere, funktioniert weiterhin alles; allerdings bin ich mir nicht sicher, ob das eine sonderlich saubere Lösung ist. Gibt es einen entsprechenden Befehl für PDO, den ich dort einsetzen sollte?

    1. Frank Richter

      Hallo, eine richtig zufriedenstellende Antwort habe ich nicht gefunden. Am nächsten kommt:
      $db_erg->closeCursor();
      siehe https://stackoverflow.com/questions/12843886/when-should-i-use-closecursor-for-pdo-statements

Schreibe einen Kommentar