Neben der teilweisen Adaptierung auf PHP5 wurden auch vorhandene Funktionen erweitert oder neue hinzugefügt. Das Ergebnis ist dabei eine im Vergleich zur vorherigen Version der DB-Klassen sicherere und einfacher zu verwendende DB-Abstraktion.
Im Folgenden möchte ich auf die Neuerungen eingehen.
query()
Die query() Funktion wurde flexibler und lässt sich optional mit verschiedenen Parametern aufrufen.
1. Variante
Während SQL-Statements immer noch wie gewohnt ausgeführt werden können
Code: Alles auswählen
// query(string $statement)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$db->query('SELECT * FROM `' . $cfg['tab']['art_lang'] . '` WHERE idart = ' . cSecurity::toInteger($idart) . ' AND idlang = ' . cSecurity::toInteger($idlang));
if ($db->nextRecord()) {
echo $db->f('title');
}
Kann man die Funktion auch mit mehreren Parametern aufrufen, wobei der erste Parameter die SQL-Anweisung in Form eines Formatierungsstrings ist und weitere Parameter die Werte, die mit den Formatierungs-Anweisungen in der SQL-Anweisung verarbeitet werden.
Code: Alles auswählen
// query(string $statement [, mixed $args [, mixed $... ]])
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$db->query('SELECT * FROM `%s` WHERE idart = %d AND idlang = %d', $cfg['tab']['art_lang'], $idart, $idlang);
if ($db->nextRecord()) {
echo $db->f('title');
}
* %s wird gegen $cfg['tab']['art_lang'] ersetzt
* Das erste %d wird gegen $idart ersetzt
* Das zweite %d wird gegen $idlang ersetzt
Bei dieser Version der Funktion muss man Strings nicht mehr manuell escapen und Werte, die vom Typ integer sein sollen nicht in ein solches umwandeln. Darum kümmert sich die dahinterliegende Funktionalität, die Verwendung von cSecurity::escapeDB() und cSecurity::toInteger() ist nicht mehr nötig, der Code wird weniger und lesbarer
3. Variante
Alternativ kann man query() auch mit 2 Parametern aufrufen, wobei der erste Parameter die SQL-Anweisung in Form eines Formatierungsstrings ist und der zweite Parameter eine indexbasierte Liste mit Werten, die mit den Formatierungs-Anweisungen in der SQL-Anweisung verarbeitet werden.
Code: Alles auswählen
// query(string $statement, array $values)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$values = array($cfg['tab']['art_lang'], $idart, $idlang);
$db = cRegistry::getDb();
$db->query('SELECT * FROM `%s` WHERE idart = %d AND idlang = %d', $values);
if ($db->nextRecord()) {
echo $db->f('title');
}
4. Variante
Letztendlich gibt es noch die Möglichkeit mit sogenannten "named Parametern" zu arbeiten. Dabei wird die Funktion auch mit 2 Parametern aufgerufen. Dabei ist der erste Parameter die SQL-Anweisung und verwendet zu ersetzende Platzhalter. Der zweite Parameter ist eine assoziative Liste mit Werten, die zu ersetzen sind.
Code: Alles auswählen
// query(string $statement, array $values)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$values = array(
'table_art_lang' => $cfg['tab']['art_lang'],
'idart' => (int) $idart,
'idlang' => (int) $idlang
);
$db->query('SELECT * FROM `:table_art_lang` WHERE idart = :idart AND idlang = :idlang', $values);
if ($db->nextRecord()) {
echo $db->f('title');
}
Die Platzhalter haben einen vorangestellten Doppelunkt ":" und sind ansonsten identisch mit den Schlüsseln im assoziativen Array.
Die Verwendung von "named Parametern" sollte nicht prepared Statements verwechselt werden. DB Treiber, die prepared Statements unterstützen, parsen die SQL-Anweisung einmal und verwenden die geparste Version für den mehrfachen Einsatz. Diese Version führt die Ersetzungen jedes Mal neu aus.
prepare()
Die neue Funktion prepare() ist im Grunde identisch mit der query(), bis auf 2 Punkte.
1. Während query() die Anweisung auch ausführt, liefert prepare() die aufbereitete Anweisung zurück.
2. prepare() kann man nicht mit einem Parameter, also nur mit der SQL-Anweisung, aufrufen.
Manchmal möchte man SQL-Anweisungen nicht direkt ausführen, z. B. vorher loggen. In solchen Fällen ist prepare() genau das Richtige.
1. Variante
Erster Parameter ist die SQL-Anweisung in Form eines Formatierungsstrings ist und weitere Parameter die Werte, die mit den Formatierungs-Anweisungen in der SQL-Anweisung verarbeitet werden.
Code: Alles auswählen
// string prepare(string $statement [, mixed $args [, mixed $... ]])
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = $db->prepare('SELECT * FROM `%s` WHERE idart = %d AND idlang = %d', $cfg['tab']['art_lang'], $idart, $idlang);
$db->query($sql);
if ($db->nextRecord()) {
echo $db->f('title');
}
Aufruf mit 2 Parametern, wobei der erste Parameter die SQL-Anweisung in Form eines Formatierungsstrings ist und der zweite Parameter eine indexbasierte Liste mit Werten, die mit den Formatierungs-Anweisungen in der SQL-Anweisung verarbeitet werden.
Code: Alles auswählen
// string prepare(string $statement, array $values)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$values = array($cfg['tab']['art_lang'], $idart, $idlang);
$sql = $db->prepare('SELECT * FROM `%s` WHERE idart = %d AND idlang = %d', $values);
$db->query($sql);
if ($db->nextRecord()) {
echo $db->f('title');
}
Aufruf mit 2 Parameters und als "named Parameter" Version. Der erste Parameter ist die SQL-Anweisung und verwendet zu ersetzende Platzhalter. Der zweite Parameter ist eine assoziative Liste mit Werten, die zu ersetzen sind.
Code: Alles auswählen
// string prepare(string $statement, array $values)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$values = array(
'table_art_lang' => $cfg['tab']['art_lang'],
'idart' => (int) $idart,
'idlang' => (int) $idlang
);
$sql = $db->prepare('SELECT * FROM `:table_art_lang` WHERE idart = :idart AND idlang = :idlang', $values);
$db->query($sql);
if ($db->nextRecord()) {
echo $db->f('title');
}
Die neue Funktion insert() kann verwendet werden, um einen Datensatz in einer gewünschten Tabelle anzulegen. Es kann als Alternative zum manuellen Erstellen einen INSERT-Statements verwendet werden.
Das manuelle Zusammenstellen eines INSERT-Statements sieht in der Regel folgendermaßen aus:
Code: Alles auswählen
$idcode = 123; // oder mit $db->nextid($cfg["tab"]["code"])
$idcatart = 12;
$idlang = 1;
$idclient = 1;
$code = "<html>... code n' fun ...</html>";
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = "INSERT INTO ".$cfg["tab"]["code"]." (idcode, idcatart, code, idlang, idclient)
VALUES (".cSecurity::toInteger($idcode).", ".cSecurity::toInteger($idcatart).",
'".cSecurity::escapeDB($code, $db)."', ".cSecurity::toInteger($idlang).",
".cSecurity::toInteger($idclient).")";
$db->query($sql);
Code: Alles auswählen
// bool insert(string $tablename, array $fields)
$idcatart = 12;
$idlang = 1;
$idclient = 1;
$code = "<html>... code n' fun ...</html>";
$fields = array(
'idcatart' => (int) $idcatart,
'idlang' => (int) $idlang,
'idclient' => (int) $idclient,
'code' => $code,
);
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$result = $db->insert($cfg['tab']['code'], $fields);
Dem Aufmerksamen Leser ist hier bestimmt aufgefallen, dass in diesem Beispiel die Id (idcode) fehlt. In CONTENIDO 4.9 wurde die Verwendung der Sequenz-Tabelle zum Verwalten der Ids der Tabellen entfernt. Mann muss nicht mehr mit $db->nextid() die nächste Id holen, darum kümmert sich nun die Datenbank (MySQL).
buildInsert()
Während insert() die Anweisung zusammenbaut und auch gleich ausführt, liefert buildInsert() die zusammengebaute Anweisung zurück. Man kann also das Statement vorher anderweitig verwenden, z. B. loggen.
Code: Alles auswählen
// string buildInsert(string $tablename, array $fields)
$idcatart = 12;
$idlang = 1;
$idclient = 1;
$code = "<html>... code n' fun ...</html>";
$fields = array(
'idcatart' => (int) $idcatart,
'idlang' => (int) $idlang,
'idclient' => (int) $idclient,
'code' => $code,
);
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = $db->buildInsert($cfg['tab']['code'], $fields);
$result = $db->query($sql);
Die neue Funktion update() ist zum Aktualisieren eines vorhandenen Datensatzes gedacht. Es kann als Alternative zum manuellen Erstellen einen UPDATE-Statements verwendet werden.
Das manuelle Zusammenstellen eines UPDATE-Statements sieht in der Regel folgendermaßen aus:
Code: Alles auswählen
$idcode = 123;
$code = "<html>... more code n' fun ...</html>";
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = "UPDATE ".$cfg["tab"]["code"]." SET code = '".cSecurity::escapeDB($code, $db)."'
WHERE idcode = " . cSecurity::toInteger($idcode);
$db->query($sql);
Code: Alles auswählen
// bool update(string $tablename, array $fields, array $where)
$idcode = 123;
$code = "<html>... more code n' fun ...</html>";
$fields = array(
'code' => $code,
);
$where = array(
'idcode' => (int) $idcode
);
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$result = $db->update($cfg['tab']['code'], $fields, $where);
Hat der dritte Parameter mehrere WHERE-Bedingungen, werden diese mit AND verknüpft.
buildUpdate()
Während update() die Anweisung zusammenbaut und auch gleich ausführt, liefert buildUpdate() die zusammengebaute Anweisung zurück.
Code: Alles auswählen
// string buildUpdate(string $tablename, array $fields, array $where)
$idcode = 123;
$code = "<html>... more code n' fun ...</html>";
$fields = array(
'code' => $code,
);
$where = array(
'idcode' => (int) $idcode
);
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = $db->buildUpdate($cfg['tab']['code'], $fields, $where);
$result = $db->query($sql);
toArray()
Dei neue Funktion toArray() liefert den aktuellen Datensatz, als Array zurück. Dabei ist es möglich den Datensatz als assoziatives und/oder indexiertes Array zurückzuliefern. Per default wird ein assoziatives Array zurückgeliefert.
Code: Alles auswählen
// string toArray(string $fetchmode)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = $db->prepare('SELECT * FROM `%s` WHERE idart = %d AND idlang = %d', $cfg['tab']['art_lang'], $idart, $idlang);
$db->query($sql);
if ($db->nextRecord()) {
$assocRs = $db->toArray(); // oder mit Parameter cDbDriverHandler::FETCH_ASSOC
echo "<pre>\$assocRs: " . print_r($assocRs, true) . "<pre>";
$indexedRs = $db->toArray(cDbDriverHandler::FETCH_NUMERIC);
echo "<pre>\$indexedRs: " . print_r($indexedRs, true) . "<pre>";
$bothdRs = $db->toArray(cDbDriverHandler::FETCH_BOTH);
echo "<pre>\$bothdRs: " . print_r($bothdRs, true) . "<pre>";
}
toObject()
Dei neue Funktion toObject() liefert den aktuellen Datensatz, als Objekt zurück das eine Instanz von stdClass ist (Standard Klasse in PHP). Die Eigenschaften des Objekts entsprechen den Feldnamen der Tabelle.
Code: Alles auswählen
// string toObject(string $fetchmode)
$idlang = 1;
$idart = 2;
$cfg = cRegistry::getConfig();
$db = cRegistry::getDb();
$sql = $db->prepare('SELECT * FROM `%s` WHERE idart = %d AND idlang = %d', $cfg['tab']['art_lang'], $idart, $idlang);
$db->query($sql);
if ($db->nextRecord()) {
$rs = $db->toObject();
echo "<pre>\$rs: " . print_r($rs, true) . "<pre>";
echo "<pre>idartlang: " . $rs->idartlang . "<pre>";
echo "<pre>title: " . $rs->title . "<pre>";
echo "<pre>author: " . $rs->author . "<pre>";
}
escape()
Mit der neuen Funktion escape() kann man Variablen vom Typ String bei Bedarf escapen. Diese Funktion ist eine Alternative zu cSecurity::escapeDB().
Code: Alles auswählen
// string escape(string $str)
$db = cRegistry::getDb();
$code = "<html>... more code n' fun ...</html>";
$escapedCode = $db->escape($code);
// Zuvor war dies folgendermaßen möglich
$db = cRegistry::getDb();
$code = "<html>... more code n' fun ...</html>";
$escapedCode = cSecurity::escapeDB($code, $db);
Das waren die wichtigsten Neuerungen in den Datenbank-Klassen cDb und Eltern-Klassen. Entwickler haben nun mehr Möglichkeiten, um SQL-Anweisungen zu generieren, zum Teil ist das Erstellen der SQL-Anweisungen einfacher sowie lesbarer geworden und der Sicherheitsaspekt wurde zum Teil in die DB-Adapter verlagert.