Bahnhofstraße 22, 52134 Herzogenrath Montag - Freitag: 8:00 - 16:30 kontakt@milnersoftware.de 0176 66798849

Aktuelles · Tipps · · 5 Min. Lesezeit

„Call to undefined function mysql_connect()“ – Ursache und Lösung

Nach einem PHP-Update meldet die Website „Call to undefined function mysql_connect()“? So stellen Sie alten Code auf mysqli oder PDO um – sicher, mit Prepared Statements.

Kleines Team arbeitet gemeinsam an Laptops an einem Holztisch

Kurz gesagt: Die Funktion mysql_connect() und alle anderen mysql_*-Funktionen wurden mit PHP 7.0 entfernt. Läuft Ihr Server mit PHP 7 oder 8, gibt es sie schlicht nicht mehr – daher der Fehler. Zurück zu PHP 5 ist keine Lösung. Der Code muss auf mysqli oder PDO umgestellt werden, am besten gleich mit Prepared Statements.

Meistens kommt der Fehler ohne Vorwarnung: Der Hoster hat die PHP-Version umgestellt, und eine Website oder ein internes Tool, das jahrelang lief, zeigt nur noch eine weiße Seite oder einen „500 Internal Server Error“. Im Fehlerprotokoll steht dann:

PHP Fatal error: Uncaught Error: Call to undefined function mysql_connect()
in /var/www/html/includes/db.php:5

Das betrifft fast immer Code, der vor vielen Jahren geschrieben wurde: selbst programmierte Kundenportale, ältere Shop-Systeme, Buchungsformulare oder Verwaltungstools.

Warum gibt es mysql_connect() nicht mehr?

Die alte MySQL-Erweiterung stammt aus der Anfangszeit von PHP. Sie unterstützt keine Prepared Statements, keine objektorientierte Nutzung und viele neuere MySQL-Funktionen nicht. Seit PHP 5.5 war sie als veraltet markiert, mit PHP 7.0 wurde sie ganz entfernt. Seitdem gibt es zwei Nachfolger, die beide fest zu PHP gehören:

  • mysqli – speziell für MySQL und MariaDB, nutzbar prozedural oder objektorientiert.
  • PDO – eine einheitliche Schnittstelle für verschiedene Datenbanken, mit klarer Fehlerbehandlung.

Beide funktionieren gut. Für kleine Umstellungen nehme ich oft mysqli, weil die Struktur dem alten Code ähnlicher ist. Für alles, was länger gepflegt werden soll, bevorzuge ich PDO.

Vorher: typischer alter Code

$link = mysql_connect('localhost', 'benutzer', 'passwort');
mysql_select_db('shop', $link);

$id = $_GET['id'];
$result = mysql_query("SELECT name, preis FROM produkte WHERE id = $id");

while ($row = mysql_fetch_assoc($result)) {
    echo $row['name'];
}

Dieser Code hat zwei Probleme. Das erste ist offensichtlich: Er läuft unter PHP 7 und 8 nicht mehr. Das zweite ist gefährlicher und war schon immer da – dazu gleich mehr.

Nachher: mit mysqli und Prepared Statement

$db = new mysqli('localhost', 'benutzer', 'passwort', 'shop');
$db->set_charset('utf8mb4');

$id = (int) ($_GET['id'] ?? 0);

$stmt = $db->prepare('SELECT name, preis FROM produkte WHERE id = ?');
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();

while ($row = $result->fetch_assoc()) {
    echo htmlspecialchars($row['name']);
}

Das Fragezeichen ist ein Platzhalter. Der Wert wird getrennt von der SQL-Abfrage an die Datenbank geschickt und kann deren Aufbau nicht verändern. Das 'i' in bind_param steht für Integer, 's' wäre ein Text. Für get_result() muss der Treiber mysqlnd installiert sein, was bei üblichen Hosting-Paketen der Fall ist.

Nachher: mit PDO

$pdo = new PDO(
    'mysql:host=localhost;dbname=shop;charset=utf8mb4',
    'benutzer',
    'passwort',
    [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]
);

$stmt = $pdo->prepare('SELECT name, preis FROM produkte WHERE id = :id');
$stmt->execute(['id' => (int) ($_GET['id'] ?? 0)]);

foreach ($stmt as $row) {
    echo htmlspecialchars($row['name']);
}

Benannte Platzhalter wie :id machen längere Abfragen gut lesbar. Durch ERRMODE_EXCEPTION bricht der Code bei einem Datenbankfehler mit einer klaren Meldung ab, statt still weiterzulaufen.

Die wichtigsten Entsprechungen

  • mysql_query() → $db->query() bzw. $db->prepare() / $pdo->prepare()
  • mysql_fetch_assoc() → $result->fetch_assoc() / $stmt->fetch()
  • mysql_num_rows() → $result->num_rows (bei PDO besser per COUNT(*) abfragen)
  • mysql_insert_id() → $db->insert_id / $pdo->lastInsertId()
  • mysql_real_escape_string() → entfällt, stattdessen Prepared Statements
  • mysql_error() → Exceptions bzw. $db->error

Das eigentliche Risiko: SQL-Injection im alten Code

Zurück zum alten Beispiel. Die Zeile WHERE id = $id übernimmt den Wert aus der Adresszeile ungeprüft in die Abfrage. Ruft jemand die Seite mit ?id=1 OR 1=1 auf, liefert die Datenbank alle Datensätze. Mit etwas mehr Aufwand lassen sich so auch andere Tabellen auslesen – etwa Kundendaten oder Passwort-Hashes.

Viele alte Projekte nutzen mysql_real_escape_string() und gelten deshalb als „abgesichert“. Das stimmt nur teilweise. Die Funktion schützt nur Werte, die in Anführungszeichen stehen. Bei Zahlen ohne Anführungszeichen, wie im Beispiel oben, hilft sie gar nicht. Und es reicht eine einzige vergessene Stelle.

Deshalb rate ich davon ab, bei der Umstellung nur die Funktionsnamen auszutauschen. Wenn Sie den Code ohnehin anfassen müssen, setzen Sie gleich Prepared Statements ein. Der Mehraufwand ist gering, der Gewinn an Sicherheit groß.

Ein Punkt, an dem Prepared Statements nicht helfen: Tabellen- und Spaltennamen, zum Beispiel in ORDER BY. Die lassen sich nicht als Platzhalter übergeben. Hier prüfen Sie den Wert gegen eine feste Liste erlaubter Spalten.

Typische Fehler bei der Umstellung

  • Suchen und Ersetzen von mysql_ zu mysqli_: Das klappt nicht. Bei vielen mysqli-Funktionen steht die Verbindung als erster Parameter, also mysqli_query($link, $sql) statt mysql_query($sql, $link). Außerdem nutzt mysqli keine „zuletzt geöffnete Verbindung“ mehr automatisch.
  • Zeichensatz vergessen: Ohne set_charset('utf8mb4') bzw. charset=utf8mb4 erscheinen Umlaute plötzlich als Fragezeichen oder kaputte Zeichen.
  • Verbindung in Funktionen: Alter Code verlässt sich oft darauf, dass mysql_query() ohne Verbindungsparameter funktioniert. Mit mysqli und PDO muss die Verbindung in jede Funktion übergeben werden.
  • Kompatibilitäts-Schichten als Dauerlösung: Es gibt Bibliotheken, die die alten mysql_*-Funktionen mit mysqli nachbauen. Als Notlösung für ein paar Tage kann das helfen. Die Sicherheitslücken bleiben damit aber genau so, wie sie waren.
  • Nur die Startseite testen: Datenbankabfragen verteilen sich oft über Dutzende Dateien. Testen Sie Formulare, Login, Suche, Export und Admin-Bereich.

So gehen Sie vor

  1. Sichern Sie Dateien und Datenbank vollständig.
  2. Suchen Sie alle Stellen: grep -rn "mysql_" --include=*.php . zeigt jede betroffene Zeile.
  3. Legen Sie eine Testkopie mit der neuen PHP-Version an.
  4. Bauen Sie eine zentrale Datenbankverbindung (eine Datei, ein Objekt) und stellen Sie die Abfragen Datei für Datei um.
  5. Prüfen Sie das Fehlerprotokoll nach jedem Schritt und testen Sie alle Funktionen.
  6. Erst dann spielen Sie die Änderungen live ein.

Wann Sie Hilfe brauchen

Ein Skript mit fünf Abfragen stellen Sie mit dieser Anleitung an einem Nachmittag um. Bei einer gewachsenen Anwendung mit Hunderten Abfragen, verstreuter Logik und ohne Dokumentation sieht das anders aus. Dazu kommt: Wo noch mysql_* steckt, finden sich oft weitere Funktionen, die in neueren PHP-Versionen fehlen, etwa each() oder create_function(), die mit PHP 8.0 entfernt wurden.

In solchen Fällen schaue ich mir den Code zuerst an und sage Ihnen, ob sich eine Umstellung lohnt oder ob Teile neu gebaut werden sollten. Wie ich dabei vorgehe, steht unter Altsystem modernisieren. Geht es vor allem darum, die Anwendung auf eine aktuelle PHP-Version zu bringen, finden Sie Ablauf und Preise unter PHP-Update (ab 690 €).

Geschrieben von Przemysław Milner

Weitere Beiträge

Przemysław Milner Tipps

WordPress ist nicht schlecht – nur schlecht gebaut

Langsam, unsicher, ständig kaputt? Meist liegt das nicht an WordPress, sondern an Pagebuildern, Plugin-Chaos und Multipurpose-Themes. Was ein eigenes Theme anders macht.

Weiterlesen

Przemysław Milner Tipps

WordPress gehackt? So erkennen Sie es

Fremde Seiten bei Google, Weiterleitungen nur auf dem Handy, unbekannte Admins: Diese sechs Anzeichen zeigen, ob Ihre WordPress-Seite gehackt wurde – und was Sie sofort tun sollten.

Weiterlesen