Hallo zusammen,
ich hab mal paar Fragen, die mir keine Ruhe geben. Wäre nett, wenn ihr ein paar Kommentare einwerft.
Szenario:
ich hab meine DB Klasse:
und ich hab eine Kunde Klasse:
hier kommt das ausführende script:
was mich nun daran stört:
mein $DB Objekt muss instanziiert und vorhanden sein, um DB Queries abzusetzen. Es muss global sein, um es von überall nutzen zu können - wenn es nicht gloabl sein sollte, kann man $newDB = new NiceDB() aufrufen und man erhält die offene, in diesem Script bereits existierende Verbindungkennung. Brauche ich mehrere DB Verbindungen, um verschachtelte Queries anzusetzen, erstelle ich mir soviele neue wie ich brauche mit dem gesetzten newConnection param. ABER: Globale Objekte passen nicht so ganz in mein OOP Bild
Wenn ich nun aber jeder Klasse, die etwas in der DB schreiben oder lesen will, eine NiceDB Klasse einniste und sie im Konstruktor instanziiere, dann muss ich mich um die $DB verbindung nicht mehr kümmern, jedes Objekt, das die DB braucht wird es enthalten - ich muss mich nicht darum scheren, ob eine Verbindung gloabal offen ist oder nicht. Was mir dabei nicht gefällt ist, dass jedes Objekt zusätzlich Speicher und Ressourcen verbrät. Mehrere Verbindungen zur DB sind nicht mehr so einfach möglich - liese sich aber noch über den Kontruktor regeln.
Möchte man Ressourcen sparen, implementiert man die DB Klasse als Singleton, dann kann man die mehrfachen Verbindungen zur DB definitiv vergessen.
Was ist der beste Weg?
2. Frage:
Da ich normalerweise schreibfaul bin, erstelle ich für jede meiner Tabellen eine Klasse mit denselben Varnamen und -anzahl wie in der jeweiligen Tabelle. Damit spare ich mir ne Menge Schreibarbeit für die einfachen select / inserts / update statements, indem ich jeweils eine Standardfunktion (wie die insertRow im Bsp. oben) für _alle_ einfachen Queries benutze. Ändert sich eine Tabelle, mache ich dieselbe Änderung in der jeweligen Klasse und alle SQL-Queries werden kompatibel sein. Kombiniert man das mit PHPUnit tests, ist diese Methode die effizienteste in meinen Augen. Einwände?
Natürlich kommt man bei komplexeren Queries wie joins nicht drumherum, diese selber zu schreiben.
3. Frage: Sieht jmd in der insertRow Funktion eine Möglichkeit SQL zu injecten?
danke euch,
Cry
ich hab mal paar Fragen, die mir keine Ruhe geben. Wäre nett, wenn ihr ein paar Kommentare einwerft.
Szenario:
ich hab meine DB Klasse:
PHP-Code:
class NiceDB
{
//Connection info - könnte man auch über den konstruktor setzen...
var $DB_Host = "localhost";
var $DB_User = "root";
var $DB_Password ="";
var $DB_Database="dbtest";
var $DB_Connection;
//extra stuff
var $LogErrors = 1; // 0 do not log / log
var $Logfilename = "DB_errorLog.log";
/**
* creates DB Connection with default parameters
* @access public
* @param string $newConnection opens a new Con! No matter if there is already a Con open with these params
*/
function NiceDB($newConnection =0)
{
$this->DB_Connection=mysql_connect($this->DB_Host, $this->DB_User, $this->DB_Password, $newConnection) or die(mysql_error());
mysql_select_db($this->DB_Database, $this->DB_Connection) or die ("Datenbankverbindung zu $this->DB_Database kann nicht hergestellt werden!");
}
/**
* changes used Database
* @access public
* @param string $database Databasename
*/
function changeDatabase($database)
{
mysql_select_db($database, $this->DB_Connection) or die ("Datenbankverbindung zu $database kann nicht hergestellt werden!");
}
/**
* logger
* @access private
* @param string $entry eintrag, der geloggt werden soll
*/
function writeLog ($entry)
{
if ($this->LogErrors && $this->Logfilename)
{
$logfile = fopen($this->Logfilename, 'a');
fwrite($logfile,"\n[".date('m.d.y H:i:s')."]\n".$entry);
fclose($logfile);
}
}
/**
* insert a row into db
* @access public
* @param string $tablename Tabellenname
* @param object $object Ojekt, das eingefügt werden soll
* @param boolean $echo true -> soll sql-statement ausgegeben werden?
* @return 0 - if fails, PrimaryKeyValue if successful
*/
function insertRow ($tablename, $object, $echo=0)
{
$arr=get_object_vars($object);
if (!is_array($arr))
{
$this->writeLog("insertRow: Objekt enthält nichts! - Tablename:".$tablename);
return 0;
}
$columns="(";
$values="(";
$keys=array_keys($arr);
for ($i=0;$i<count($keys);$i++)
{
if ($i==count($keys)-1)
{
$columns.=$keys[$i].") values";
if ($object->$keys[$i]=="now()") //nicht sauber, aber nützlich
$values.=$object->$keys[$i].")";
else
$values.="\"".mysql_real_escape_string($object->$keys[$i])."\")";
}
else
{
$columns.=$keys[$i].", ";
if ($object->$keys[$i]=="now()") //nicht sauber, aber nützlich
$values.=$object->$keys[$i].", ";
else
$values.="\"".mysql_real_escape_string($object->$keys[$i])."\", ";
}
}
$stmt="insert into $tablename $columns $values";
if ($echo)
echo($stmt);
$res=mysql_query($stmt,$this->DB_Connection);
if(!$res)
{
$this->writeLog($stmt."\n".mysql_errno() . ": " . mysql_error());
return null;
}
else
{
$erg1=mysql_query('select LAST_INSERT_ID()',$this->DB_Connection);
if($erg1)
if ($res1=mysql_fetch_row($erg1))
if ($res1[0]>0)
return $res1[0];
else
return 1; // then this is non auto_increment - but insert was successful
}
}
//... usw.
}
PHP-Code:
class Kunde
{
var $cUserName;
var $cPassword;
var $cAnrede;
var $cTitel;
var $cName;
var $dDatetime;
//funktionen usw..
}
hier kommt das ausführende script:
PHP-Code:
require_once ("NiceDB.php");
require_once ("Kunde.php");
$DB = new NiceDB();
$Kunde = new Kunde();
$Kunde->cUserName="Crysus";
$Kunde->cPassword="pass";
$Kunde->cAnrede="H";
$Kunde->cTitel="Dr.";
$Kunde->cName="1\2\\3\\\4\\\\5\\\\\_1'_2''_3'''_4''''";
$Kunde->dDatetime="now()";
//insert in DB
$key = $DB->insertRow("test",$Kunde);
mein $DB Objekt muss instanziiert und vorhanden sein, um DB Queries abzusetzen. Es muss global sein, um es von überall nutzen zu können - wenn es nicht gloabl sein sollte, kann man $newDB = new NiceDB() aufrufen und man erhält die offene, in diesem Script bereits existierende Verbindungkennung. Brauche ich mehrere DB Verbindungen, um verschachtelte Queries anzusetzen, erstelle ich mir soviele neue wie ich brauche mit dem gesetzten newConnection param. ABER: Globale Objekte passen nicht so ganz in mein OOP Bild
Wenn ich nun aber jeder Klasse, die etwas in der DB schreiben oder lesen will, eine NiceDB Klasse einniste und sie im Konstruktor instanziiere, dann muss ich mich um die $DB verbindung nicht mehr kümmern, jedes Objekt, das die DB braucht wird es enthalten - ich muss mich nicht darum scheren, ob eine Verbindung gloabal offen ist oder nicht. Was mir dabei nicht gefällt ist, dass jedes Objekt zusätzlich Speicher und Ressourcen verbrät. Mehrere Verbindungen zur DB sind nicht mehr so einfach möglich - liese sich aber noch über den Kontruktor regeln.
Möchte man Ressourcen sparen, implementiert man die DB Klasse als Singleton, dann kann man die mehrfachen Verbindungen zur DB definitiv vergessen.
Was ist der beste Weg?
2. Frage:
Da ich normalerweise schreibfaul bin, erstelle ich für jede meiner Tabellen eine Klasse mit denselben Varnamen und -anzahl wie in der jeweiligen Tabelle. Damit spare ich mir ne Menge Schreibarbeit für die einfachen select / inserts / update statements, indem ich jeweils eine Standardfunktion (wie die insertRow im Bsp. oben) für _alle_ einfachen Queries benutze. Ändert sich eine Tabelle, mache ich dieselbe Änderung in der jeweligen Klasse und alle SQL-Queries werden kompatibel sein. Kombiniert man das mit PHPUnit tests, ist diese Methode die effizienteste in meinen Augen. Einwände?
Natürlich kommt man bei komplexeren Queries wie joins nicht drumherum, diese selber zu schreiben.
3. Frage: Sieht jmd in der insertRow Funktion eine Möglichkeit SQL zu injecten?
danke euch,
Cry
Kommentar