Erster Eintrag in eine MySQL-Datenbank mit PHP

  1. Die Verbindung zur Datenbank herstellen
  2. Der Aufbau einer Datenbank-Tabelle
  3. Die Datenbank-Tabelle anlegen
  1. Die Daten einfügen, auslesen und bearbeiten
  2. MySQL-Fehlermeldungen anzeigen
  3. Die Daten über ein Formular sicher eintragen
  1. Die Daten über ein Formular bearbeiten
  2. Die Daten sortiert und begrenzt ausgeben
  3. Hinweise zu den MySQL-Anweisungen
  1. Die Daten schnell durchsuchen
  2. Die Ausführung auf dem Webserver
  3. Was fehlt hier noch?

4. Die Daten einfügen, auslesen und bearbeiten

Die Datenbank-Tabelle muss nun mit Daten gefüttert werden, diese Daten stammen meist aus Formularen die Benutzer ausfüllen. Nach dem ausfüllen des Formulars werden diese Daten per PHP an die Datenbank-Tabelle gesendet und eingetragen, hierfür benötigen Sie die MySQL-INSERT-Anweisung, die Sie gleich kennen lernen werden.

Es gibt im wesentlichen vier MySQL-Anweisungen:

  1. INSERT - Datensatz einfügen
  2. SELECT - Datensatz auslesen
  3. UPDATE - Datensatz überschreiben
  4. DELETE - Datensatz löschen

Jede dieser Anfragen (im engl. als query bezeichnet) wird über die Datenbanksprache SQL (engl. Structured Query Language = Strukturierte Abfragesprache) ausgeführt.

Nachfolgend gehe ich immer auf den weiter unten gezeigten Quelltext ein, wenn jemand meine Erklärung dazu nicht gleich versteht macht das nichts, entweder noch einmal lesen oder den Quelltext studieren der recht einfach gehalten ist.

INSERT - Datensatz einfügen

Die PHP-Funktion exec() führt eine Anweisung aus und gibt die Anzahl der betroffenen Datensätze zurück und sollte für INSERT, UPDATE und DELETE-Anweisungen genutzt werden.

Mit INSERT INTO fügen Sie einen neuen Datensatz ein, gefolgt von dem Namen der Tabelle `nachrichten` und den Spalten `titel`, `autor`, `nachricht`, `datum`. Mit VALUES fügen Sie dann den eigentlichen Inhalt in die Tabelle ein. Bitte beachten Sie die Reihenfolge der Spalten (dies ist eine häufige Fehlerquelle) und hinter dem letzten Wert darf kein Komma mehr stehen, sonst wird die Anweisung nicht ausgeführt.

1
2
3
4
5
6
7
8
9
10
11
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensatz einfügen.
if ($db->exec("INSERT INTO `nachrichten`
              (`titel`, `autor`, `nachricht`, `datum`)
       VALUES ('Hallo Welt!', 'Werner', 'Viel Text ...', '2018-11-21')")) {
 echo 
'<p>Die Nachricht wurde eingetragen.</p>';
}
?>

Zu kompliziert, hier folgt eine wesentlich übersichtlichere Anweisung die ich immer bevorzuge. Mit SET, dem Namen der Spalte einem Gleichheitszeichen und dem Inhalt der Spalte, wird ein Datensatz eingetragen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensatz einfügen.
if ($db->exec("INSERT INTO `nachrichten`
               SET
                `titel`     = 'Hallo Welt!',
                `autor`     = 'Werner',
                `nachricht` = 'Viel Text ...',
                `datum`     = '2018-11-21'")) {
 echo 
'<p>Die Nachricht wurde eingetragen.</p>';
}
?>

Die Daten die eingetragen werden, sollten hierbei vom PHP-Programm selbst kommen und nicht vom Benutzer über ein Formular „manipuliert” sein. Siehe » Die Daten über ein Formular sicher eintragen weiter unten auf dieser Seite.

Es müssen bei allen Feldern (außer der ID), die in der Datenbank-Tabelle sind und die nicht in dem INSERT angesprochen werden von vorne herein Vorgabewerte angegeben werden.

SELECT - Datensatz (Datensätze) auslesen

Mit der PHP-Funktion query() kann man Daten aus der DB-Tabelle auslesen. Mit SELECT `titel`, `name`, `nachricht`, `datum`   in der MySQL-Anweisung, wählen Sie die gewünschten Spalten der Tabelle zum lesen aus, gefolgt von FROM und dem Namen der Tabelle `nachrichten`.

Die PHP-Funktion fetchAll() gibt der Variable $nachrichten ein Array mit allen Folgesätzen zurück. Mit einer foreach()-Schleife werden die Datensätze dann über $var['Spalten_Name'] ausgegeben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensätze auslesen.
$select $db->query("SELECT `titel`, `autor`, `nachricht`, `datum`
                      FROM `nachrichten`");
$nachrichten $select->fetchAll();

// Ausgabe über eine Foreach-Schleife.
foreach ($nachrichten as $nachricht) {
 echo 
'<p>$nachricht["titel"] . '<br>.
  
$nachricht["autor"] . '<br>.
  
$nachricht["nachricht"] . '<br>.
  
$nachricht["datum"] . '</p>';
}
?>

Das folgende Beispiel zeigt das auslesen wenn der Parameter PDO::FETCH_OBJ (Klassen-interne Konstante) bei fetchAll() hinzugefügt wird, es wird dann ein Objekt mit allen Datensätzen zurück gegeben. Die Ausgabe erfolgt dann über einer foreach()-Schleife mit $var->Spalten_Name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensätze auslesen.
$select $db->query("SELECT `titel`, `autor`, `nachricht`, `datum`
                      FROM `nachrichten`");
$nachrichten $select->fetchAll(PDO::FETCH_OBJ);

// Ausgabe über eine Foreach-Schleife.
foreach ($nachrichten as $nachricht) {
 echo 
'<p>$nachricht->titel '<br>.
  
$nachricht->autor '<br>.
  
$nachricht->nachricht '<br>.
  
$nachricht->datum '</p>';
}
?>

Nur einen Datensatz auslesen

Manchmal benötigt man nur einen bestimmten Datensatz aus einer DB-Tabelle, deshalb ist da eine foreach()-Schleife unnötig.

Mit der Spalte `id` in der Tabelle, hat jeder Datensatz eine eindeutige Identifikationsnummer, diese kann man nun dazu benutzen einen bestimmten Datensatz auszulesen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Einen Datensatz auslesen.
$select $db->query("SELECT `titel`, `nachricht`
                      FROM `nachrichten`
                      WHERE `id` = 7");

// $select->fetch() holt die betreffende Zeile aus dem Ergebnis der Anfrage.
$datensatz $select->fetch();

// Mit $select->rowCount() überprüfen ob ein Datensatz zurückgegeben wurde.
if ($select->rowCount() == 1) {

 
// Ausgabe
 
echo '<p>$datensatz["titel"] . ' - ' $datensatz["nachricht"] . '</p>';
}
?>

Mit WHERE weisen Sie an welcher Datensatz ausgelesen werden soll. In diesem Beispiel wird `id` = '7' , also der Datensatz mit dem Identifikationsnummer 7 ausgelesen.

$datensatz = $select->fetch() holt die betreffende Zeile aus dem Ergebnis der Anfrage. Und $select->rowCount() enthält die Anzahl der zurückgegeben Datensätze.

Filter

Mit der WHERE-Klausel (Bedingung) können Sie die Auswahl der Daten bei einem SELECT filtern. Angenommen Sie möchten nur die Nachrichten anzeigen die in der Spalte `kategorie` den Eintrag 'Software' haben, dann lautet die MySQL-Anweisung wie folgt:

1
2
3
4
5
6
<?php
// Datensätze auslesen.
$select $db->query("SELECT `titel`, `autor`, `nachricht`, `datum`
                      FROM `nachrichten`
                      WHERE `kategorie` = 'Software'");
?>

Limitierung

Die Anzahl der Nachrichten können Sie mit der LIMIT-Anweisung limitieren (begrenzen). Dazu fügen Sie nach LIMIT den Wert ein ab welchem Datensatz die Nachrichten ausgelesen werden (5), nach dem Komma folgt dann die Anzahl der Nachrichten (10) die ausgelesen werden sollen, also: LIMIT 5,10.

1
2
3
4
5
6
<?php
// Datensätze auslesen.
$select $db->query("SELECT `titel`, `autor`, `nachricht`, `datum`
                      FROM `nachrichten`
                      LIMIT 5,10");
?>

Mit der Anweisung LIMIT 12 (ohne einem zweiten Wert) wird das auslesen auf 12 Datensätze limitiert.

Wie die LIMIT-Anweisung und dessen Werte nun dazu benutzt werden um eine Seiten-Navigation (Pagination) zu erstellen, erfahren Sie auf der nächsten Seite unter » Die Daten sortiert und begrenzt ausgeben

UPDATE - Datensatz überschreiben

Mit UPDATE überschreiben Sie einen Datensatz, gefolgt von dem Namen der Tabelle `nachrichten` und SET dahinter geben Sie die Spalte an, die Sie überschreiben möchten und dessen Inhalt. Mit WHERE weisen Sie an welcher Datensatz geändert werden soll. In diesem Beispiel wird `id` = '17' , also der Datensatz mit der Identifikationsnummer (ID) 17 geändert.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensatz überschreiben.
if ($db->exec("UPDATE `nachrichten`
                SET 
                  `titel` = 'Hallo Welt die zweite!',
                  `nachricht` = 'Viel mehr Text ...'
                WHERE
                  `id` = '17'")) {
 echo 
'<p>Die Nachricht wurde überschrieben.</p>';
}
?>

Achtung: Wenn keine WHERE-Klausel (Bedingung) angegeben wird, so werden alle Datensätze überschrieben!

DELETE - Datensatz löschen

Mit DELETE FROM löschen Sie einen Datensatz, gefolgt von dem Namen der Tabelle `nachrichten` und WHERE weisen Sie an welchen Datensatz Sie löschen möchten. In diesem Beispiel wird `id` = '35' , also der Datensatz mit der Identifikationsnummer 35 gelöscht.

1
2
3
4
5
6
7
8
9
10
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensatz löschen.
if ($db->exec("DELETE FROM `nachrichten`
                WHERE `id` = '35'")) {
 echo 
'<p>Die Nachricht wurde gelöscht.</p>';
}
?>

Achtung: Wenn keine WHERE-Klausel angegeben wird, werden alle Datensätze der Tabelle ohne Nachfrage gelöscht!

Beachten Sie, dass es bei einer Datenbank keinen „Rückgängig-Button” gibt, wie Sie ihn vielleicht von Word oder Excel gewohnt sind. Eine DB-Tabelle stellt einen elementaren Datenspeicher dar, INSERT / UPDATE / DELETE verändern diesen Speicher direkt. Und was Sie eingefügt, geändert oder gelöscht haben, ist unwiderruflich eingefügt, geändert oder gelöscht.

Nicht jeder Datensatz muss gleich gelöscht werden, fügen Sie eine Tabellenspalte hinzu die den Datensatz auf "inaktiv" setzt, so kann dieser leicht zurück geholt werden.

5. MySQL-Fehlermeldungen anzeigen

Nicht nur PHP kann Fehler enthalten sondern auch die MySQL-Anweisung. Um nun nicht wild zu raten wo der Fehler in der MySQL-Anweisung versteckt ist, bauen wir ein if(){} else{}-Statement ein das den Fehler abfängt und dann mit $db->errorInfo() eine detaillierte Fehlermeldung ausgibt.

Das folgende Script enthält einen Fehler  9  in der MySQL-Anweisung, es wurde ein Komma am Ende der Zeile vergessen!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// Verbindung zur Datenbank aufbauen.
include "verbinden.php";

// Datensatz überschreiben.
// Zeile 9 enthält einen Fehler, es wurde ein Komma vergessen!
if ($db->exec("UPDATE `nachrichten`
               SET 
                 `titel` = 'Hallo Welt die zweite!'
                 `nachricht` = 'Viel mehr Text ...'
               WHERE
                 `id` = '17'")) {
 
// Bei einer erfolgreichen Änderung (UPDATE) wird 'true' zurück gegeben.
 
echo '<p>Die Nachricht wurde überschrieben.</p>';
}
else {
 
// Andernfalls wird (bei 'false') eine SQL-Fehlermeldung ausgegeben.
 
print_r($db->errorInfo());
}
?>

Es wird folgende MySQL-Fehlermeldung ausgegeben:

Array ( [0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the right syntax
to use near '`nachricht` = 'Viel mehr Text ...' WHERE ' at line 4 )

Die Zahl 42000 ist der SQLSTATE-Fehlercode, die Zahl 1064 ist der Fehlercode der aktuellen Fehlermeldung. Die Fehlermeldung weist uns noch freundlich darauf hin das man einen Fehler in der MySQL-Syntax hat und man in das Handbuch (MySQL-Referenzhandbuch) für die richtige Syntax schauen sollte.

Wichtig ist, was weiter unten steht: near '`nachricht` = 'Viel mehr Text ...' WHERE ', zeigt die fehlerhafte Syntax an und at line 4 die entsprechende Zeile wo der Fehler dem MySQL-Parser aufgefallen ist (wobei der eigentliche Fehler meist eine Zeile höher liegt).

Für Schreibfaule geht das auch einfacher mit dem or die()-Statement.

1
2
3
4
5
6
7
8
<?php
$db
->exec("UPDATE `nachrichten`
           SET
             `titel` = 'Hallo Welt die zweite!'
             `nachricht` = 'Viel mehr Text ...'
           WHERE
                     `id` = '17'") or die($db->errorInfo()[2]);
?>

Man sollte schon beim schreiben der MySQL-Anweisung darauf achten diese in mehrere Zeilen aufzuteilen und Einrückungen (Leerzeichen, Tabulatoren) einsetzen. Die Anweisung lässt sich schnell auf eventuelle Fehler überprüfen und es wird bei einer Fehlermeldung die betreffende Zeile mit ausgegeben, siehe » Quelltext mit Format.

Beachten Sie das Fehlermeldungen zur Fehlersuche nur bei der Entwicklung ausgegeben werden sollten und nicht im fertigem Script.

6. Die Daten über ein Formular sicher eintragen

Sicheres Programmieren – Traue niemals den Eingaben des Benutzers! Hier folgt ein Beispiel wie Daten sicher in die Datenbank-Tabelle über ein Formular eingetragen werden können.

Bisher war es immer ein großes Problem wenn Eingaben über ein Formular gemacht wurden, häufig kam es zu SQL-Injektionen. Die DB-Tabelle konnte über ein Formular kompromittiert werden, Passwörter und anderes konnten ausgelesen und die Tabelle konnte schlimmstenfalls komplett gelöscht werden.

Nachfolgend sehen Sie zwei Beispiele wie man es nicht machen sollte:

<?php
// Fehler! - Die POST-Variablen stehen direkt im SQL-Code.
$insert $db->exec("INSERT INTO `nachrichten`
                      SET
                       `titel`     = $_POST['titel'],
                       `autor`     = $_POST['autor'],
                       `nachricht` = $_POST['nachricht'],
                       `kategorie` = $_POST['kategorie'],
                       `anzeige` = $_POST['anzeige'],
                       `datum` = NOW()");

// Fehler! - Die GET-Variablen stehen direkt im SQL-Code.
$insert $db->exec("DELETE FROM `nachrichten` WHERE `id` = $_GET['id']");
?>

Die POST-Variablen oder GET-Variablen wurden im Script direkt in den SQL-Code eingefügt.

Mit den „Prepared Statements” (zu deutsch: vorbereitete Anweisung) ist dies nun vorbei, die Daten die über POST/GET gesendet wurden, werden über Platzhalter (:titel :autor :nachricht :kategorie :anzeige) in den SQL-Code eingeführt.

<?php
 $insert 
$db->prepare("INSERT INTO `nachrichten`
                         SET
                          `titel`     = :titel,
                          `autor`     = :autor,
                          `nachricht` = :nachricht,
                          `kategorie` = :kategorie,
                          `anzeige` = :anzeige,
                          `datum` = NOW()");

 
$insert->bindValue(':titel'$_POST["titel"]);
 
$insert->bindValue(':autor'$_POST["autor"]);
 
$insert->bindValue(':nachricht'$_POST["nachricht"]);
 
$insert->bindValue(':kategorie'$_POST["kategorie"]);
 
$insert->bindValue(':anzeige'$anzeige);
// ...
?>

Die Platzhalter werden mit $insert->bindValue() durch den Inhalt der POST-Variablen ersetzt und maskiert. Später zeige ich, wie sich die Platzhalter (einfacher) über ein Array einfügen lassen.

Es sollten nicht nur die Eingaben von Textfeldern/Textbereichen durch Platzhalter ersetzt werden, sondern auch von Auswahllisten, Checkboxen, Radiobuttons usw. da diese auch manipuliert sein können.

Mit den Platzhaltern lassen sich keine Spaltennamen in der DB-Tabelle ersetzen, sondern nur Parameter-Werte.

Sämtliche potentiell gefährlichen Anweisungen in Platzhaltern werden automatisch maskiert und sind somit ungefährlich. Daher sollten Sie immer „Prepared Statements” einsetzen, anstatt PHP-Variablen in Ihre MySQL-Anweisung einzubauen. So ist Ihre Web-Anwendung von dieser Seite aus nicht angreifbar und der Aufwand für diesen erheblichen Gewinn an Sicherheit ist minimal.

Dieses Bildschirmfoto zeigt das Formular zum eintragen einer Nachricht an.

Quelltext „eintragen.phpKopierenAusblendenZeilen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<!DOCTYPE html>
<html lang="de">
 <head>
  <meta charset="UTF-8"> 
  <title>Nachricht eintragen</title>

  <style>
  body {
   font-family: Verdana, Arial, Sans-Serif;
   background-color: Whitesmoke;
  }

  a:link, a:visited {
   color: Royalblue;
   text-decoration: None;
  }
  </style>


 </head>
<body>

<nav>
 <a href="auslesen.php">Nachrichten</a> |
 <u>Eintragen</u> |
 <a href="bearbeiten.php">Bearbeiten</a> |
 <a href="suchen.php">Suchen</a>
</nav>

<form action="eintragen.php" method="post">

 <p>
  <label>Titel: 
   <input type="text" name="titel" size="45" maxlength="80" required="required" autofocus="autofocus">
  </label>
 </p>

 <p>
  <label>Autor: 
   <input type="text" name="autor" size="25" maxlength="30" required="required">
  </label>
 </p>

 <p>
  <label>Kategorie: 
   <select name="kategorie" size="1" required="required">
    <option>Aktuell</option>
    <option>Hardware</option>
    <option>Software</option>
   </select>
  </label>
 </p>

 <p>
  <label>Nachricht:<br>
  <textarea rows="10" cols="40" name="nachricht" required="required"></textarea>
  </label>
 </p>

 <p>
  <label>
  <input type="checkbox" name="anzeige"> Nachricht anzeigen
  </label>
 </p>

 <p>
  <input type="submit" value="Absenden">
 </p>

</form>

<?php
// Wurde das Formular abgesendet?
if ("POST" == $_SERVER["REQUEST_METHOD"]) {

 
// Die Formulareingaben müssen hier überprüft werden,
 // siehe: https://werner-zenk.de/tipps/php_mit_sicherheit.php

 // Verbindung zur Datenbank aufbauen.
 // Die Verbindung sollte erst aufgebaut werden, wenn diese benötigt wird.
 
include "verbinden.php";

 
// Der Variable $anzeige einen Wert zuweisen, entweder 1 oder 0.
 // Je nachdem ob die Checkbox gesetzt (ausgewählt) wurde.
 
$anzeige = isset($_POST["anzeige"]) ? 0;

 
// Nachricht eintragen
 // prepare() (prepare = aufbereiten) bereitet die Anweisung für die Ausführung vor.
 // Die Platzhalter werden hier anstatt den POST-Variablen eingesetzt.
 
$insert $db->prepare("INSERT INTO `nachrichten`
                                 SET
                                  `titel`     = :titel,
                                  `autor`     = :autor,
                                  `nachricht` = :nachricht,
                                  `kategorie` = :kategorie,
                                  `anzeige` = :anzeige,
                                  `datum` = NOW()");

 
// Die Platzhalter werden mit $insert->bindValue() durch den
 // Inhalt der POST-Variablen ersetzt und maskiert.
 
$insert->bindValue(':titel'$_POST["titel"]);
 
$insert->bindValue(':autor'$_POST["autor"]);
 
$insert->bindValue(':nachricht'$_POST["nachricht"]);
 
$insert->bindValue(':kategorie'$_POST["kategorie"]);
 
$insert->bindValue(':anzeige'$anzeige);

 
// $insert->execute() führt die vorbereitete Anweisung aus.
 // Bei einem erfolgreichen Eintrag wird 'true' zurück gegeben.
 
if ($insert->execute()) {
  echo 
'<p>&#9655; Die Nachricht wurde eingetragen.</p>';

  
// Um die gerade eingetragene Nachricht bearbeiten zu können, benötigen
  // wir die ID des zuletzt eingetragenen Datensatzes: lastInsertId()
  
$id $db->lastInsertId();

  
// Nun hängen wir an den Dateinamen (bearbeiten.php) die ID dran
  
echo '<p><a href="bearbeiten.php?id=' $id '">Nachricht bearbeiten</a></p>';

 }
 else {
  
// Andernfalls (bei 'false') wird eine SQL-Fehlermeldung ausgegeben.
  
print_r($insert->errorInfo());
 }
}
?>

</body>
</html>

Um das Script hier möglichst einfach zu halten, werden die Formulareingaben des Benutzers nicht validiert (überprüft), Zeile 75. Dies müssen Sie selbst einbauen wenn Sie das Script im produktiven Einsatz verwenden wollen. Siehe: PHP mit Sicherheit

Nachdem die ersten Einträge in der Tabelle stehen, schaut diese ungefähr so aus:

id titel autor nachricht kategorie anzeige datum
1 Hallo Welt! Werner Viel Text ... Aktuell 1 2018-11-19
2 Lorem Ipsum Blindtextchen Weit hinter den … Aktuell 0 2018-11-20
3 Testtext Testi Testext um den Text … Software 1 2018-11-21

So, nun müssen fleißig weitere Daten eingetragen werden, damit auch welche ausgegeben werden können

Die Daten über ein Formular bearbeiten

Der Zugriff auf die Datenbank