Übergabe von Checkbox-Werten in die Select-Abfrage
Murli
- php
Hallo,
ich hoffe ich stelle meine Frage so, dass man sie auch versteht ... ;-)
Mein Konstrukt funktioniert mit MySQL und Php, allerdings bin ich noch relativ frisch dabei.
Ich habe eine Nachrichtenübersicht und davor Checkboxen, sieht so aus (Schema)
[ ] Überschrift Nachricht 1 >Link zum weiterlesen
[ ] Überschrift Nachricht 2 >Link zum weiterlesen
[ ] Überschrift Nachricht 3 >Link zum weiterlesen
Bisher ist es so, dass man die Nachrichten einzeln anklicken muss. Ich möchte jedoch, dass man auch alle drei Nachrichten (oder nur 2) per Checkbox auswählen kann und dann die allesamt auf einer Seite kommen.
Die Sache mit der Übergabe der Checkbox-Häkchen funktioniert. Also wenn ich einen Haken setze, wird die ID der Nachricht übergeben. Bisher habe ich das nur probiert und die IDs werden in der Datei ausgabe.php untereinander ausgegegeben, also z.B.
9987
9988
9989
Meine Überlegung bzw. mein Ansatz ist der, dass die einzelnen Nachrichten bisher immer per ID angezeigt werden, also
"select * from $table WHERE id='xxx' Order By date DESC");
Mein Problem bzw. meine Frage ist jetzt, wie ich die per Checkbox ausgewählten IDs in meine Abfrage bekomme, sodass diese z.B. so aussieht ...
"select * from $table WHERE id='9987' or id ='9988' Order By date DESC");
Ich hoffe, ich habe mein Problem vernünftig dargestellt. Wenn es andere Ansätze gibt, die ich nicht erkenne oder wenn ich noch weitere Infos posten soll, dann bitte ich um eine Rückmeldung. Über Hilfe würde ich mich sehr freuen, denn an dieser Stelle hier hänge ich und komme nicht weiter.
Vielen Dank!
Hi,
Mein Problem bzw. meine Frage ist jetzt, wie ich die per Checkbox ausgewählten IDs in meine Abfrage bekomme, sodass diese z.B. so aussieht ...
"select * from $table WHERE id='9987' or id ='9988' Order By date DESC");
Lasse dir die Werte als Array übergeben (eckige Klammern an den Namen hängen, name="xyz[]"), und generiere daraus eine komma-separierte Liste, die du im IN()-Operator einsetzen kannst.
Und informiere dich über SQL Injection, und was du dagegen zu tun hast.
MfG ChrisB
--
Light travels faster than sound - that's why most people appear bright until you hear them speak.
Lasse dir die Werte als Array übergeben (eckige Klammern an den Namen hängen, name="xyz[]"), und generiere daraus eine komma-separierte Liste, die du im IN()-Operator einsetzen kannst.
Danke für die schnelle Antwort. Gibt es dazu vielleicht ein Tutorial, einen (Beispiel-)Codeschnipsel oder etwas ähnliches (Links?). Die Beschreibung ist für mich wie eine Anleitung in serbokroatisch ...
Hello,
Lasse dir die Werte als Array übergeben (eckige Klammern an den Namen hängen, name="xyz[]"), und generiere daraus eine komma-separierte Liste, die du im IN()-Operator einsetzen kannst.
Danke für die schnelle Antwort. Gibt es dazu vielleicht ein Tutorial, einen (Beispiel-)Codeschnipsel oder etwas ähnliches (Links?). Die Beschreibung ist für mich wie eine Anleitung in serbokroatisch ...
Dann lass es uns übersetzen:
Wie sieht das Formular aus?
<form action="<?php echo $_SERVER['SCRIPT_NAME']; ?>" method="post" enctype="multipart/form-data">
<p><input type="checkbox" name="ctrl[record][]" value="1234"> 1234</p>
<p><input type="checkbox" name="ctrl[record][]" value="2345"> 2345</p>
<p><input type="checkbox" name="ctrl[record][]" value="2222"> 2222</p>
<p><input type="checkbox" name="ctrl[record][]" value="1313"> 1313</p>
<p><input type="checkbox" name="ctrl[record][]" value="4711"> 4711</p>
<p><input type="submit" name="btn[show]" value="anzeigen"></p>
</form>
In der PHP-Datei steht dann ungefähr:
if (isset($_POST['btn']['show']))
{
if (isset($_POST['ctrl']['record']) and is_array($_POST['ctrl']['record']))
{
$_liste = array_map('intval', $_POST['ctrl']['record']);
$liststr = "('" . implode(",'", $_liste) . "')";
}
## Aufruf des SHOW-Statements
}
und das Statement kennst Du schon.
Nun hoffe ich, dass kein Tippfejhler drin ist.
Lass Dir an geeigneten Stellen einfach zur Kotrolle mal ausgegen, was in den Variablen drin steht. dann sollte es am schnellstens klar werden, was da passiert.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
$liststr = "('" . implode(",'", $_liste) . "')";
Noch zwei Sätze dazu, warum ich mich hier für die Häkchen entschieden habe, obwohl es sich um zahlen handelt. Das hat nichts mit Doppelparanoia zu tun, sondern mit Bequemlichkeit.
Wenn Du abfragst
select id, zahl from zahl where id in (1,3,7,8,11);
ist das für MySQL auch OK. Aber wenn die Liste leer ist, also dadurch dann
select id, zahl from zahl where id in ();
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds
to your MySQL server for the right syntax to use near ')' at line 1
gibt es eine hässliche Fehlermeldung, weil die Liste leer ist.
Wenn Du nun aber
select id, zahl from zahl where id in ('');
abfragst, sit MySQL damit zufrieden, da die Liste nicht leer ist, sondern einen Leerstring enthält.
Das ergibt dann einfach ein leeres Resultset
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
...zuerst einmal vielen Dank für die umfangreiche Hilfe. Da mein Ansatz natürlich nicht identisch war, musste ich mich erst einmal hineindenken, jetzt funktioniert es aber grundsätzlich, allerdings nur dann, wenn ich einen Haken mache. Wenn ich zwei Haken in den Checkboxen setze, kommt die Fehlermeldung
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 '9940')) AND untertext_nr=474 Order By date DESC' at line 1You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '9940')) AND untertext_nr=475 Order By date DESC' at line 1You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '9940')) AND untertext_nr=476 Order By date DESC' at line 1
So sieht die Zeile aus ...
$result = mysql_query("select * from $table WHERE untertext='2' AND id IN ($liststr) AND untertext_nr=$idd[$m] Order By date DESC");
Könnt Ihr mir bitte noch mal helfen?
Vielen Dank!
Hello,
$result = mysql_query("select * from $table WHERE untertext='2' AND id IN ($liststr) AND untertext_nr=$idd[$m] Order By date DESC");
Wenn Du den $liststr so aufbauen lassen hast, wie ich es gepostet hate, dann steht er bereits in Klammern. Das geht für mich auch aus der Fehlermeldung hervor.
Bau das SQL-Query mal separat auf.
$sql = "select \* from $table ".
"WHERE untertext='2' ".
"AND id IN $liststr ".
"AND untertext\_nr={$idd[$m]} ".
"Order By date DESC";
und lasse ihn die anzeigen, bevor Du ihn an die Query-Funktion übergibst.
echo "<p>$sql</p>";
$result = mysql\_query ($sql, $connection);
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg

--
Nur selber lernen macht schlau
<http://bergpost.annerschbarrich.de>
Danke, ich glaube ich weiß, wo das Problem liegt.
Es gibt in dem Script noch mal eine separate Abfrage, d.h. es werden alle Beiträge noch mal nach einer gesonderten ID durchsucht. Aufgrund dessen durchsucht er alle untertext_nr, die einer ID zugeordnet sind (immer 8 Stück). So kommt es zu der Ausgabe ...
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=474 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=475 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=476 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=477 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=478 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=479 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=480 Order By date DESC
select * from news WHERE untertext='2' AND id IN (9944,9940) AND untertext_nr=481 Order By date DESC
Wie kann ich das denn beschränken? Ich dachte, das ginge mit LIMIT, das war aber natürlich falsch gedacht. Stehe auf dem Schlauch!
... ich glaub ich hab's, muss noch mal testen
Hallo,
also, es funktioniert jetzt soweit, vielen Dank noch mal!
Es gibt allerdings 2 Fußnoten bzw. Fragen, die ich noch habe und über deren Beantwortung ich mich freuen würde:
a) In der $liststr-Zeile mit den ''' gab es einen Fehler. Ich habe die '' jetzt entfernt und jetzt läuft es. Das Problem war, dass die Ausgabe so aussah:
(9980','9999',...)
also das ' vor der ersten Zahl gefehlt hat und so eine Fehlermeldung produiziert wurde.
b) Ist es Möglichkeit, eine "Auskunft" zu geben, wenn keine Checkbox ausgewählt wurde? Also ...
if { checkbox wurde nicht angeklickt
echo 'bitte wählen sie eine aus';
}
c) Ist in Deinem Beispiel schon eine Absicherung gegen diese Injektion drin und wenn nein, gibt es einen empfehlenswerten Link bzw. ein Beispiel zur Anwendung?
Das wars. Vielen Dank noch mal und ein schönes Rest-Wochenende!
Sascha
Hello,
a) In der $liststr-Zeile mit den ''' gab es einen Fehler. Ich habe die '' jetzt entfernt und jetzt läuft es. Das Problem war, dass die Ausgabe so aussah:
(9980','9999',...)
also das ' vor der ersten Zahl gefehlt hat und so eine Fehlermeldung produiziert wurde.
b) Ist es Möglichkeit, eine "Auskunft" zu geben, wenn keine Checkbox ausgewählt wurde? Also ...
Ich hatte als Code-Schnipsel vorgeschlagen:
Den ergänze ich un einfach durch einen else-Zweig
if (isset($_POST['btn']['show']))
{
if (isset($_POST['ctrl']['record']) and is_array($_POST['ctrl']['record']))
{
$_liste = array_map('intval', $_POST['ctrl']['record']);
$liststr = "('" . implode(",'", $_liste) . "')";
## Aufruf des SHOW-Statements, wenn es sich nur auf die Checkboxen bezieht
}
else
{
## Keine Checkboxen gewählt
$_output['errors'][] = 'Sie haben keine Option ausgewählt';
}
## Aufruf des Show-Statements, wenn es außedr den Checkboxnen auch noch andere
## andere Daten bereitstellen muss
}
Zur Frage mit der in()-Funktion
+--- den hatte ich vergessen
|
v
$liststr = "('" . implode("','", $_liste) . "')";
^ ^ ^
| | |
Die anderen Stringbegrenzer hatte ich drin im Mustercode.
Sorry, den einen hatte ich vergessen.
Du hast ihn beim Nachbauen dafür an einer anderen Stelle unterschlagen ;-))
Ich würde die Stringbegrenzer aus den schon erwähnten Gründen setzen lassen und außerdem ist die Funktion dann auch schnell umgebaut, um nach echten Stringinhalten (in einer anderen Spalte) zu suchen. Da muss dann nur das intval() gegen ein mysql_real_escape_string() ausgetauscht werden.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
...noch mal vielen Dank!
Ein Problem gibt es noch, wenn keine Berichte angeklickt werden. Dann erscheint folgende Meldung:
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 'AND untertext_nr=474 Order By date DESC' at line usw.
Wo kann da der fehler liegen?
Danke!
Hello,
Ein Problem gibt es noch, wenn keine Berichte angeklickt werden. Dann erscheint folgende Meldung:
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 'AND untertext_nr=474 Order By date DESC' at line usw.
Wo kann da der fehler liegen?
Es wäre hilfreich, das gesamte durch PHP zusammengebaute SQL-Statement zu haben.
Lass Dir das mal zur Kontrolle ausgeben.
$sql = "select $fieldlist from $table WHERE id in $liststr ... "
echo $sql;
$res = mysql_query($sql, $con);
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Danke! Das kommt dabei raus:
select * from news WHERE untertext='2' AND id IN AND untertext_nr=474 Order By date DESC
muss da noch irgendwie eine Klammer hinter id IN? Nur noch mal zur Verdeutlichung, so sehen die wesentlichen Zeilen aus ...
$liststr = "('" . implode("','", $_liste) . "')";
...
$result = mysql_query("select * from $table WHERE untertext='2' AND id IN $liststr AND untertext_nr={$idd[$m]} Order By date DESC");
Hello,
select * from news WHERE untertext='2' AND id IN AND untertext_nr=474 Order By date DESC
muss da noch irgendwie eine Klammer hinter id IN? Nur noch mal zur Verdeutlichung, so sehen die wesentlichen Zeilen aus ...
$liststr = "('" . implode("','", $_liste) . "')";
...
$result = mysql_query("select * from $table WHERE untertext='2' AND id IN $liststr AND untertext_nr={$idd[$m]} Order By date DESC");
Das kann nicht sein, denn dann müsste das Statement lauten
select * from news WHERE untertext='2' AND id IN ('') AND untertext_nr=474 Order By date DESC
und das müsste dann funktionieren, also vermutlich ein leeres Resultset ergeben.
Da hast Du ein anderes Statement für "$liststr = ..." benutzt, als Du oben gepostet hast.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi,
nee, das sind die beiden Zeilen ...
$sql = "select * from $table WHERE untertext='2' AND id IN $liststr AND untertext_nr={$idd[$m]} Order By date DESC";
$liststr = "('" . implode("','", $_liste) . "')";
Hello,
nee, das sind die beiden Zeilen ...
$sql = "select * from $table WHERE untertext='2' AND id IN $liststr AND untertext_nr={$idd[$m]} Order By date DESC";
$liststr = "('" . implode("','", $_liste) . "')";
Wo wird denn in deinem Gesamtkunstwerk $liststr erzeugt?
Hast Du error_reporting(E_ALL) oben in Deinem Script drinstehen zum Debuggen?
Vermutlich wird Dein $liststr gar nicht genereriert, wenn keine Treffer vorhanden sind. Dann kann er später auch nicht ins SQL-Statement eingesetzt werden.
Da ist ggf. ein kleiner Designfehler in meinem Vorschlag.
Wenn das Statement auch mit leerem $liststr aufgerufen werden können soll, musst Du den vorher entweder mit
$liststr = "('')";
setzen oder besser die Sequenzen in der Bedingung ändern:
$liststr = '';
if (isset($_POST['btn']['show']))
{
if (isset($_POST['ctrl']['record']) and is_array($_POST['ctrl']['record']))
{
$_liste = array_map('intval', $_POST['ctrl']['record']);
$liststr = "AND id IN ('" . implode(",'", $_liste) . "')";
}
else
{
## Keine Checkboxen gewählt
$_output['errors'][] = 'Sie haben keine Option ausgewählt';
}
## Aufruf des Show-Statements, wenn es außer den Checkboxen auch noch
## andere Daten bereitstellen muss
$sql = "select * from $table".
" WHERE untertext='2' $liststr ".
" AND untertext_nr={$idd[$m]} Order By date DESC";
# ...
}
Bitte nur als Anregeung nehmen :-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
"select * from $table WHERE id='9987' or id ='9988' Order By date DESC");
Ich fange bei Statement vorne an:
Select \*
sollte man im Produktiveinsatz nicht mehr schreiben, wenn man nicht alle Spaltenwerte benötigt, sondern nur eine geringe Auswahl daraus. Dann sollte man die Spaltennamen gezielt angeben.
Die Möglichkeit, die gewünschten Datensätze mit 'or' einzusammeln ist grundsätzlich richtig.
Die übergebenen IDs sollte man auf jeden Fall gegen gefakte Werte abprüfen, also sicherstellen, dass auch wirklich nur (natürliche) Zahlen übermittelt werden und keine wilden Strings (-> SQL Injection).
Das kann man z.B. mittels der PHP-Funktion intval() richtogstellen. Im Zweifelsfalle wird dann eben
intval('böser böser SQL-String') zu 0
und 0 sollte bei vernünftiger ID-Wahl für die Tabelle einen ungültigen Index bedeuten.
Es gibt außerdem bei MySQL die Funktion in()
select $spalten from $table where id in ($idliste);
$idliste sollte dann eine durch Komma getrennte Liste von IDs sein.
Wenn Du die Checkboxen zu einem Checkboxarray zusammenfasst, kannst du dieses automatisch verarbeitetn lassen.
Die Funktionen array\_map(), intval() und implode() helfen Dir dabei.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg

--
Nur selber lernen macht schlau
<http://bergpost.annerschbarrich.de>