[mySql] Abfrage ob Element in der Datenbank vorhanden ist

[mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 16:15:49 von Thorn Thaler

Hallo NG,

bin gerade dabei mir etwas Php+MySql beizubringen, bin also auf diesem
Gebiet noch ein ziemlicher Frischling (daher mein wahrscheinlich
triviale Frage).
Nach dem Studium der FAQ (die übrigens sehr hilfreich gerade für
Einsteiger ist) habe ich was über die absolute Notwendigkeit
Skript-Parameter (egal ob aus GET, POST oder COOKIE) zu validieren
gelesen. So weit so gut. Jetzt habe ich hier ein Skript, dass ein
gewisses Element aus einer DB löscht, was zu löschen ist, erhält das
Skript in diesem Fall über GET. Naja, und um zu prüfen ob es ein güliger
Wert ist, muss ich wohl oder übel schauen, ob er in der DB überhaupt
vorhanden ist: ich mache das so:

$tmp = "SELECT x FROM y WHERE z=\"" . $_GET["what"] . "\"";
if (mysql_num_rows(mysql_query($tmp)) == 1) {
$tmp = "DELETE FROM y WHERE z=\"" . $_GET["what"] . "\"";
mysql_query($tmp);
}

Das "==1" ergibt sich daraus, dass nach dem Primärschlüssel gesucht (und
gelöscht) wird, daher kann es ja nur entweder ==0 oder ==1 geben.

Meine Frage dazu ist das eine "saubere" Lösung, oder ein Workarraund?
Ich lege nämlich auf sauberen Programmierstil i.A. viel Wert.

Mit bestem Dank für Eure Anregungen,

Thorn

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 17:16:35 von Stephan Schulze

Thorn Thaler schrieb:
> Nach dem Studium der FAQ (die übrigens sehr hilfreich gerade für
> Einsteiger ist) habe ich was über die absolute Notwendigkeit
> Skript-Parameter (egal ob aus GET, POST oder COOKIE) zu validieren
> gelesen.

Validierung heißt in diesem Fall nicht, dass Du die Übergabe ungeprüft
in einem SQL-Query schmeisst, sondern, dass Du die Daten in der Übergabe
validierst.
Sowas wie "verbotene Zeichen", unerlaubte Inhalte, zu lange Inhalte usw.
usf.
Siehe auch Teil zu sauberem Programmierstil.

>
> $tmp = "SELECT x FROM y WHERE z=\"" . $_GET["what"] . "\"";
> if (mysql_num_rows(mysql_query($tmp)) == 1) {
> $tmp = "DELETE FROM y WHERE z=\"" . $_GET["what"] . "\"";
> mysql_query($tmp);
> }
>
> Das "==1" ergibt sich daraus, dass nach dem Primärschlüssel gesucht (und
> gelöscht) wird, daher kann es ja nur entweder ==0 oder ==1 geben.

Generell brauchst Du um ein Element aus der Datenbank zu löschen nicht
erst zu überprüfen ob dieses Element drin ist.
Ein einfaches
$tmp = "DELETE FROM y WHERE z=\"" . $_GET["what"] . "\""; mysql_query($tmp);

sollte reichen.

>
> Meine Frage dazu ist das eine "saubere" Lösung, oder ein Workarraund?
> Ich lege nämlich auf sauberen Programmierstil i.A. viel Wert.

Eine saubere Lösung ist das in keinem Fall. Du verwendest die Werte aus
der GET Übergabe ungeprüft, mysql_escape_string($_GET['what']) solltest
Du mindestens machen (kannst Du auch mal hier gucken, da hat einer nen
kurzen Artikel über SQL-Injektion gemacht:
http://www.thegeek.de/blog/index.php?type=archiv&post=200502 #prispevek60).

Und wenn ich mir Deine Variablenbezeichner und Spaltennamen angucke,
dann kriege ich ehrlich gesagt, das kalte Grausen ;-)

Du tust Dir und allen anderen die Deinen Code lesen müssen einen
Gefallen, wenn Du aussagekräftige Variablennamen verwendest. Das Gleiche
gilt natürlich auch für die Spaltennamen in der Datenbank.
Aber vielleicht hast Du die ja auch nur für das Beispiel so gewählt ;-)

Viele Grüße

Stephan

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 18:02:19 von Thorn Thaler

Stephan Schulze schrieb:

> Validierung heißt in diesem Fall nicht, dass Du die Übergabe ungeprüft
> in einem SQL-Query schmeisst, sondern, dass Du die Daten in der Übergabe
> validierst.
> Sowas wie "verbotene Zeichen", unerlaubte Inhalte, zu lange Inhalte usw.
> usf.
> Siehe auch Teil zu sauberem Programmierstil.

Aha, also mal angenommen der erwartete Input sollte ein sql Datum sein,
also z.B. 2005-12-1, in welcher Form kann ich das vernünftig überprüfen
regexp? Wenn ja, werd ich da mal die FAQ konsultieren.

> Generell brauchst Du um ein Element aus der Datenbank zu löschen nicht
> erst zu überprüfen ob dieses Element drin ist.

War mir klar, ich hab das mit der Validierung nur falsch verstanden.

> Eine saubere Lösung ist das in keinem Fall. Du verwendest die Werte aus
> der GET Übergabe ungeprüft, mysql_escape_string($_GET['what']) solltest
> Du mindestens machen (kannst Du auch mal hier gucken, da hat einer nen
> kurzen Artikel über SQL-Injektion gemacht:
> http://www.thegeek.de/blog/index.php?type=archiv&post=200502 #prispevek60).

Ist es also im Sinne der Validierung ausreichend, die Form zu
überprüfen, und sonderzeichen ggf. zu maskieren? Hab ich das jetzt
richtig verstanden?

> Und wenn ich mir Deine Variablenbezeichner und Spaltennamen angucke,
> dann kriege ich ehrlich gesagt, das kalte Grausen ;-)
>
> Du tust Dir und allen anderen die Deinen Code lesen müssen einen
> Gefallen, wenn Du aussagekräftige Variablennamen verwendest. Das Gleiche
> gilt natürlich auch für die Spaltennamen in der Datenbank.
> Aber vielleicht hast Du die ja auch nur für das Beispiel so gewählt ;-)

Jupp, auf alle Fälle, wenn ich wirklich so benamsen würde, würde mir
wahrscheinlich selber schlecht werden ;) War also _kein_ copy und paste
sondern nur schnelles (faules) Hingeschreibse. Sorry.

Danke auf alle Fälle mal für die ersten Tipps auf meiner PHP - Odyssee.

LG thorn

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 18:24:11 von Stephan Schulze

Thorn Thaler schrieb:

> Aha, also mal angenommen der erwartete Input sollte ein sql Datum sein,
> also z.B. 2005-12-1, in welcher Form kann ich das vernünftig überprüfen
> regexp? Wenn ja, werd ich da mal die FAQ konsultieren.

Du könntest zum Beispiel ein
$array_mysql_date = explode("-", $string_date) machen und dann für jedes
Element des Arrays überprüfen ob es a) eine Zahl ist b)ein gültige(r/s)
Jahr/Monat/Tag ist c) ob das Datum insgesamt korrekt ist (checkdate) und
d) ob das Array genau drei Elemente enthält.

Muss nicht unbedingt in der Reihenfolge sein ;-)

>
> Ist es also im Sinne der Validierung ausreichend, die Form zu
> überprüfen, und sonderzeichen ggf. zu maskieren? Hab ich das jetzt
> richtig verstanden?
Prinzipiell schon, Du solltest aber natürlich auch im Hinterkopf
behalten, dass auch für Dich und Dein System valide Eingaben Gefahren
für den Benutzer bergen können. Als Stichwort sei hier
Cross-Site-Scripting genannt.
Zum Weiterlesen kannst Du vielleicht mal bei
http://blog.bitflux.ch/wiki/XSS_Prevention
schauen.

> Jupp, auf alle Fälle, wenn ich wirklich so benamsen würde, würde mir
> wahrscheinlich selber schlecht werden ;) War also _kein_ copy und paste
> sondern nur schnelles (faules) Hingeschreibse. Sorry.
Das beruhigt mich ;-)

Viele Grüße

Stephan Schulze

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 19:00:45 von Niels Braczek

Stephan Schulze schrieb:
> Thorn Thaler schrieb:

> Ein einfaches
> $tmp = "DELETE FROM y WHERE z=\"" . $_GET["what"] . "\"";
> mysql_query($tmp);
> sollte reichen.

Zu einem sauberen Stil gehören auch Lesbarkeit, sprechende
Variablennamen und Fehlerbehandlung.

$what = $_GET['what'];
/* ggf. Prüfungen! */
$sql = sprintf("DELETE FROM y WHERE z='%s'",
mysql_real_escape_string($what));
$result = mysql_query($sql) or die ($sql.'
'.mysql_error());

>> Meine Frage dazu ist das eine "saubere" Lösung, oder ein Workarraund?
>> Ich lege nämlich auf sauberen Programmierstil i.A. viel Wert.
>
> Eine saubere Lösung ist das in keinem Fall. Du verwendest die Werte aus
> der GET Übergabe ungeprüft, mysql_escape_string($_GET['what']) solltest
^^^^^^^^^^^^^^^^^^^
mysql_escape_string() ist veraltet. Verwende (empfehle) statt dessen
mysql_real_escape_string().

> Und wenn ich mir Deine Variablenbezeichner und Spaltennamen angucke,
> dann kriege ich ehrlich gesagt, das kalte Grausen ;-)

ACK.

> Du tust Dir und allen anderen die Deinen Code lesen müssen einen
> Gefallen, wenn Du aussagekräftige Variablennamen verwendest. Das Gleiche
> gilt natürlich auch für die Spaltennamen in der Datenbank.

ACK.

MfG
Niels

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 19:23:31 von Thorn Thaler

Stephan Schulze schrieb:


> Du könntest zum Beispiel ein
> $array_mysql_date = explode("-", $string_date) machen und dann für jedes
> Element des Arrays überprüfen ob es a) eine Zahl ist b)ein gültige(r/s)
> Jahr/Monat/Tag ist c) ob das Datum insgesamt korrekt ist (checkdate) und
> d) ob das Array genau drei Elemente enthält.

(a) und (d) ok. Aber sind (b) und (c) notwendig? Ich meine, so wie ich
das jetzt verstanden habe, gehts bei der Validierung vor allem auch
darum, dass man keine "bösen" SQL - Tags mitschicken kann, die - weil
nicht überprüft - die Datenbank korumpieren? Weil der Normalfall ist
der, dass ich einen link mit einem gültigen DAtum habe, und der brave
und geünschte USer klickt drauf und die Daten verschwinden im Nivana.
Ein direkter Aufruf ist nicht gewünscht, weil es aber böse Menschen gibt
und die es trotzdem machen, muss ich zusehen, dass zumindest nicht mehr
angerichtet wird(als das löschen des Termins, aber das muss anders
geschützt werden (php file im geschützten Bereich des servers und
..htaccess)). Dies mache ich durch Validierung der Daten. Oder habe ich
da noch immer Verständnisprobleme?

BTW: habs jetzt mal mit regexps probiert steh da aber irgendwie an:

echo $_GET["what"] . "
"; //liefert z.B. 2005-09-07
if (preg_match("/^d{4}-\d{2}-\d{2}$/", $_GET["what"])) {

müsste eigentlich gehen, aber er springt nicht ins if. Was mach ich falsch?


> Prinzipiell schon, Du solltest aber natürlich auch im Hinterkopf
> behalten, dass auch für Dich und Dein System valide Eingaben Gefahren
> für den Benutzer bergen können. Als Stichwort sei hier
> Cross-Site-Scripting genannt.
> Zum Weiterlesen kannst Du vielleicht mal bei
> http://blog.bitflux.ch/wiki/XSS_Prevention
> schauen.

Ok, danke. Schaut recht interessant aus.

>> Jupp, auf alle Fälle, wenn ich wirklich so benamsen würde, würde mir
>> wahrscheinlich selber schlecht werden ;) War also _kein_ copy und
>> paste sondern nur schnelles (faules) Hingeschreibse. Sorry.
>
> Das beruhigt mich ;-)

Glaub mir, mich noch mehr ;)

Thorn

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 19:34:42 von Thorn Thaler

Thorn Thaler schrieb:


> BTW: habs jetzt mal mit regexps probiert steh da aber irgendwie an:
>
> echo $_GET["what"] . "
"; //liefert z.B. 2005-09-07
> if (preg_match("/^d{4}-\d{2}-\d{2}$/", $_GET["what"])) {
>
> müsste eigentlich gehen, aber er springt nicht ins if. Was mach ich falsch?

Ok, fehler gefunden (beschämt wegschau). Hab das in einem test-File
getestet (dort hats gefunzt) und habs dann aber nicht kopiert sondern
nur abgeschrieben, und dann hab ich wohl den einen slash vergessen. ;)

LG thorn

Re: [mySql] Abfrage ob Element in der Datenbank vorhanden ist

am 25.02.2005 19:38:33 von Stephan Schulze

Thorn Thaler schrieb:
> Stephan Schulze schrieb:
>
>
>> Du könntest zum Beispiel ein
>> $array_mysql_date = explode("-", $string_date) machen und dann für
>> jedes Element des Arrays überprüfen ob es a) eine Zahl ist b)ein
>> gültige(r/s) Jahr/Monat/Tag ist c) ob das Datum insgesamt korrekt ist
>> (checkdate) und d) ob das Array genau drei Elemente enthält.
>
>
> (a) und (d) ok. Aber sind (b) und (c) notwendig? Ich meine, so wie ich
> das jetzt verstanden habe, gehts bei der Validierung vor allem auch
> darum, dass man keine "bösen" SQL - Tags mitschicken kann, die - weil
> nicht überprüft - die Datenbank korumpieren?
Wenn Du tatsächlich nur ein syntaktisch korrektes Datum haben willst,
dann reichen a) und d) aus. Allerdings würden dann auch
if (preg_match("#^[0-9]{4}-[0-9]{2}-[0-9]{2}$#", $_GET["what"]))
den Zweck erfüllen.


> BTW: habs jetzt mal mit regexps probiert steh da aber irgendwie an:
>
> echo $_GET["what"] . "
"; //liefert z.B. 2005-09-07
> if (preg_match("/^d{4}-\d{2}-\d{2}$/", $_GET["what"])) {
ich habs mit dem regulären Ausdruck oben probiert, der funktioniert in
jedem Fall, kann Dir zum Ausprobieren komplexer Ausdrücke aber den
RegexCoach sehr ans Herz legen. Den gibt es hier:
http://www.weitz.de/regex-coach/
>
> müsste eigentlich gehen, aber er springt nicht ins if. Was mach ich falsch?
Dein Ausdruck muss
^\d{4}-\d{2}-\d{2}$ lauten, Du hast das erste d nicht escaped...

Siehe hier:http://de.php.net/manual/de/reference.pcre.pattern.synt ax.php

Viele Grüße

Stephan Schulze