Sql Dynamisch aufbauen, aber sicher

Liebe/-r Experte/-in,
ich möchte euch noch mal mit einer Frage belästigen. :wink:

erstmal zum Szenario:
Ich habe eine Datenbank ua mit der Tabelle Beiträge.
Über Filter wähle ich das anzuzeigende Quartal und die anzuzeigenden Jahre. (checkboxen). Über eine verwaltungsvariable lege ich fest wie weit die Jahre zurückgehen können sollen.

$sql_quittungen=sprintf("select beiträge.* from beitraege where
(
quarter(quittungen.datum)=%s)or
quarter(quittungen.datum)=%s)or
quarter(quittungen.datum)=%s)or
quarter(quittungen.datum)=%s)
}
and
(
Date_Format(quittungen.datum,’%%Y’) = %s)or
Date_Format(quittungen.datum,’%%Y’) = %s)or
Date_Format(quittungen.datum,’%%Y’) = %s)or
Date_Format(quittungen.datum,’%%Y’) = %s)
)
and
(
mysql_real_escape_string($array_quartal[0]),
mysql_real_escape_string($array_quartal[1]),
mysql_real_escape_string($array_quartal[2]),
mysql_real_escape_string($array_jahre[0]),
mysql_real_escape_string($array_jahre[1]),
));

Soll heissen:
Wenn checkbox quartal 1 gesetzt ist, zeige mir alle Beiträge aus dem ersten Quartal.
Wenn checkbox quartal 2 gesetzt ist, zeige mir alle Beiträge aus dem zweiten Quartal.
Wenn checkbox 2012 gesetzt ist gesetzt ist, zeige mir alle Beiträge aus 2012 und dem Quartal xy.
usw.

Also habe ich derzeit die Anzahl der auswählbaren Jahre auf 4 festgelegt. Also ab 2009 bis 2012 kann alles ausgewählt werden. Im Array $jahreanzahl_array sind die Werte 999 oder Jahreszahl.

Nun möchte ich die Anzahl der zurückreichenden Jahre dynamisch machen. Also sowas wie eine Konfigurationsvariable $jahrezurueck.
=> $jahrezurueck =5. Dann kann der User die letzten 4 jahre + das aktuelle auswählen. Bei $jahrezurueck=3 nur die letzten 2 Jahre + das aktuelle Jahr. usw.

Eine Idee ist das Ganze mit einer for-schleife zu machen und dann die sql-Abfrage via string Operationen zusammen zu bauen. (Quartal wegen der Übersichtlichkeit weggelassen). Die forschleife geht von 0 bis count(jahrezurueck_array).

$sql_teil1= „select * from beitrage where „;
$sql_string_tei2=““;
for($d=0;$d

Das sind reine strings und funktioniert. Alternativ habe ich probiert nur die gesetzten Variablen in ein Array zu packen und dies dann zu durchlaufen.

Die Abfrage ist nur ein string. Funktioniert.
Nun zur Frage:
Aber wie kriege ich das mit dem mysql_real_escape_string und den Platzhaltern hin?
Oder ist der Denkansatz falsch?

Also das sowas rauskommt:
(gesetzt ist 1., 2. und 3. Quartal
2011 und 2012 und 2009
$array_jahre=array(2012,2009);
$array_quartal = array(1,2,3):wink:


and
(
quarter(quittungen.datum)=%s)or
quarter(quittungen.datum)=%s)or
quarter(quittungen.datum)=%s)
}
and
Date_Format(quittungen.datum,’%%Y’) = %s)or
Date_Format(quittungen.datum,’%%Y’) = %s))
group by kategorie_id having sum(wert)!=‚NULL‘",
mysql_real_escape_string($array_quartal[0]),
mysql_real_escape_string($array_quartal[1]),
mysql_real_escape_string($array_quartal[2]),
mysql_real_escape_string($array_jahre[0]),
mysql_real_escape_string($array_jahre[1]),
);

Eine Überlegung geht gegen implode und „or“-Verknüpfung.
Aber echo „mysql_real_escape_string“; funktioniert so leider nicht. :wink:

also

du brauchst foreach.
vorher durch die arrays durch und es passt.
dann arraygrösse bestimmen, zb 5
deine query ist dann:
„select bla from bl where quartal in (“.substr(str_repeat("%s,",$anz),-1).")"

dann mit sprintf aufbauen, fertig. sprintf n8mmt den array als 2. argument.

so sollt das klappen.

ups… foreach mit dem mysql_real_escape_string wie hier:

In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.

Hi,
das war ja schnell. Danke erstmal!
habe ich es richtig verstanden, dass
$value = mysql_real_escape_string($value);

innerhalb der foreach Schleife die Ausgaben verkettet?

Denn dann müsste ich für die Jahre noch eine verschachtelte foreach reinbasteln, damit

mysql_real_escape_string($array_quartal[0]),
mysql_real_escape_string($array_quartal[1]),
mysql_real_escape_string($array_quartal[2]),
mysql_real_escape_string($array_jahre[0]),
mysql_real_escape_string($array_jahre[1])

das dabei rauskommt. (Bei drei gewählten Quartalen und 2 gesetzten Jahren.)

PS
Ich habe es nun mal eingesetzt.Und der value hat nun den Wert der gesetzten Quartale (1,2,3)
Sind dass denn schon die escapten Werte?

Weil dann müsste ich nur die for-schleifen für den stringpart mit in das foreach packen, oder bin ich wieder auf der falschen fährte?

for($p=0;$p

Liebe/-r Experte/-in,
ich möchte euch noch mal mit einer Frage belästigen. :wink:

snip/
Moin Oliver,

mir fe_lt da was. Was soll ‚%s‘ sein? Wie wird dieser Wert gefüllt? Wie ist Deine Datenstruktur (create table-Befehl für ‚Quittungen‘)?

Willst Du im „Optimalfall“ z. B. das 1. Quartal von 2009, das 2. von 2010 und das dritte von 2011, sowie komplett 2008 abdecken können? Oder reichen Dir zusammenhängende Zeiträume aus?

Will fragen: Wo kommst Du her, wo willst Du hin?

Ich frage darum, weil z.B. ein Tuner auch Rückfragen hast, wenn Du mit dem Auto in die Werkstatt fährst und ihm sagst: „Schneller machen!“. Er wird Dich fragen, wie viel Du ausgeben willst, um „wieviel“ er „schneller“ werden soll, ob Dir Mehrverbrauch egal ist, solange er adäquat ist [Du willst nicht 15 Liter mehr verbrauchen für 5 km/h mehr Endgeschwindigkeit], ob Du Rennen fahren willst [ScheiX auf die STVZO, gib mir die Rennordnung!] oder weiterhin eine Strassenzulassung benötigst, etc.

Darum, nur darum frage ich.

Hallo,

du versuchst in deiner Schleife das gesetzte Jahr per MySQL mit einer IF-Anweisung abzufragen. Der Gedanke mit der Schleife ist gut, aber besser wäre es, die IF-Amweisung in PHP zu machen, dann kannst du auch mysql_real_escape_string() einsetzen. Und es kommt nur das in den String, was reingehört.

$sql_teil1= „select * from beitrage where „;
$sql_string_tei2=““;
for($d=0;$d

Ach so, ich hatte vergessen mysql_real_escape_string einzusetzen:

$sql_teil1= „select * from beitrage where „;
$sql_string_tei2=““;
for($d=0;$d

hi,
(jetzt bin ich am PC, das andre war am handy getippt)

Also:
zuerst deine Arrays „cleanen“:

foreach ($array_quartal as &$value) {
$value = mysql_real_escape_string($value);
}
foreach ($array_jahre as &$value) {
$value = mysql_real_escape_string($value);
}
-> Jetzt sind alle Werte escapt. Alternativ könntest du auch einfach mit 1 multiplizieren :smile:

jetzt SQL bauen:
$sql= „SELECT beiträge.* FROM beitraege WHERE „;
$sqlqu=„quarter(quittungen.datum) in (“.substr(str_repeat(“%s,“,count($array_quartal),-1).")";

$sqlyr=" AND year(quittungen.datum) in (".substr(str_repeat("%s,",count($array_year),-1).")"

Wie das geht:
count($array_quartal) gibt die Anzahl der gewählten Quartale zurück. Nehmen wir an 3: Quartal 1,2,4
Es ergibt sich (der ersetzte Teil in # #

substr(str_repeat("%s,",count($array_quartal),-1)
wird zu
substr(str_repeat("%s,",#3#),-1)
-> %s,%s,%s,

Das kannst Du mit sprintf ersetzen, indem dudann einfach:

weiter: Das Substr schneidet das letzte , weg
->
%s,%s,%s

Dadurch ergibt sich am Ende:
„quarter(quittungen.datum) in (“.substr(str_repeat("%s,",count($array_quartal),-1).")".
wird zu
"quarter(quittungen.datum) in (%s,%s,%s)

Dasselbe fürs Jahr und voila =>

$sql.=sprintf($sqlqu,@array_quartal).sprintf($sqlyr,@array_jahre);

den Code hab ich nicht getestet nur getippt, sollt aber klappen.

Hallo,

leider kann ich dir bei dem Thema nicht helfen. Ich hoffe, dass du Hilfe von einem anderen Experten bekommst.

LG
Manfred

Trotzdem danke für die Rückmeldung!

Hi Alex,
also ich habe nun noch etwas rumprobiertb und auch Deine Anregung zumindest erstmal gedanklich übernommen, die Arrays nicht ab zufragen, sondern wirklich nur mit den gesetzten Werten zu füllen. Also nicht ein Array mit 5 jahren und davon 2 auf 999 (=nicht gesetzt), sondern dann nur 3 Werte im Array.

Hm, was macht der Parrt:

##$sql_string_tei2.=(($jahreanzahl_array[$d]!=999)?9)? " Date_Format(beitra##

Insbesondere das „?“

Da kriege ich beim lesen einen Knoten im Hirn…
Da wird doch eine Funktion wie ein String behandelt, oder?
Gruß
Oliver

Hi,
nee ich habe oben zwei leisten mit checkboxen.
Quartale und Jahre.

also gebe mir das 2. und 4. Quartal von 2008, 2009 und 2011 raus, zum Beispiel.

Vergess quitttungen, nenn das Beitraege. Das %s ist ein Platzhalter, gehört zu sprint f und wird durch die escapten Werte aus mysql_real_escape_string ersetzt.

Gruß
Oliver

Hi,
ich dachte, ich könnte programmieren,… Nun sitzt ich hier und habe fast nen Knoten im Hirn.

Nunja erstmal ans entwirren.

"quarter(quittungen.datum) in (%s,%s,%s)

Nuss ich da nicht sowas haben wie //je nachdem wie viele Quater im Array drinne sind…?

Ich bastel mal.

Fettes Dankeschön!

Oliver
quarter(quittungen.datum)=%s)or
quarter(quittungen.datum)=%s)

ich würde die POST oder GET Abfragen aus dem Formular zu Arrays zusammenfassen und diese dann wie folgt abrfagen

select beiträge.* from beitraege
where
quarter(quittungen.datum) IN ‚".$quarter_array."‘
AND YEAR(quittungen.datum) IN ‚".$jahr_array."‘

ich konnte zwar nicht prüfen ob das so funktioniert, aber so ähnlich habe ich schon einiges realisiert.

mit freundlichem Gruß
Roland dreix
dreix webdesign
E-Mail: [email protected]
Webseite: http://www.dreix.de

Hi Oliver,

Stichworte zur Vereinfachung:
SQL: IN (…) benutzen statt umständlicher OR-Verknüpfungen. Einfacher im SQL-Code und in der Formulierung der Bedingungen aus einem Array (implode ist hier schon der sinnvolle Ansatz).
SQL: Wenn du QUARTER benutzt, dann geht auch YEAR.
PHP: mit array_map() kann eine Funktion (die escape-Funktion) auf alle Elemente eines Array angewendet werden.

Du sprichst von Tabelle „beiträge“, im Code aber ‚quittungen‘. Ich nehme an, es geht um ein und dieselbe Tabelle. Dann müsste dieser Bsp.-Code funktionieren, ein paar Erläuterungen in den Kommentaren.

// "Konfig"-Variable und weitere Hilfsvariablen
$maxYearsBack = 5;
$minYear = date('Y') - $maxYearsBack;
$minDate = "$minYear-01-01";


// MySQL Connection sollte schon existieren,
// bevor mysql\_real\_escape\_string() aufgerufen wird
$dbConnection = mysql\_connect($host, $user, $password);


// array\_quartal enthält ein oder mehrere vom User gewählte Berichts-Quartale.
// Sicherheitshalber leere Elemente entfernen:
foreach(array\_keys($array\_quartal) as $qKey) {
 if (! $array\_quartal[$qKey]) unset($array\_quartal[$qKey]);
}
// .. und dann per array\_map escapen
$array\_quartal = array\_map('mysql\_real\_escape\_string', $array\_quartal);

// IN Bedingung bauen: Sicherheitshalber - auch wenn's Zahlen sind - in 
// einfachen Anführungszeichen. Der implode-String beinhaltet die 
// Anführungszeichen zwischen den Elementen. Vor dem ersten und nach dem
// letzten Element muss ebenfalls ein Anführungszeichen stehen:
$quarterInCondition = "('" . implode("', '", $array\_quartal) . "')";


// Dasselbe für array\_jahre:
foreach(array\_keys($array\_jahre) as $yKey) {
 if (! $array\_jahre[$yKey]) unset($array\_jahre[$yKey]);
}
$array\_jahre = array\_map('mysql\_real\_escape\_string', $array\_jahre);
$yearInCondition = "('" . implode("', '", $array\_jahre) . "')";


// Query bauen
$sql = "SELECT \* FROM quittungen 
WHERE datum \>= '$minDate'
 AND QUARTER(datum) IN $quarterInCondition
 AND YEAR(datum) IN $yearInCondition";

Gruß
Thomas

Hi,

also hier handelt es sich um eine verkürzte IF-Anweisung, schaue bitte hier: http://davidwalsh.name/php-shorthand-if-else-ternary…

In deinem Beispiel wird der Teil hinter dem „?“ dann an $sql_string_tei2 angehangen, wenn die Bedingung $jahreanzahl_array[$d]!=999 zutrifft. Ansonsten wird der Teil hinter dem „:“ angehangen, nämlich nichts (null). Sowas macht man immer dann, wenn man innerhalb eines Strings Entscheidungen treffen muss. Das sollte Dir bei deinem Problem eigentlich helfen.

Hi,
also letztendlich hast Du mir die Lösung geben! Fettes Dankeschön.

Kleine Änderungen waren von Nöten. sprintf nimmt kein array -> vsprintf.

<?php / ********************** dynamisch */
echo " Anzahl Quartale:".count($quartal\_array)." "; echo "Anzahl jahre:".count($jahreanzahl\_array)." "; $statischer\_part = "select beitraege.\* from beitraege where "; foreach ($quartal\_array as &$value) { $value = mysql\_real\_escape\_string($value); } foreach ($jahreanzahl\_array as &$value) { $value = mysql\_real\_escape\_string($value); } $sqlqu="quarter(beitraege.datum) in (".substr(str\_repeat("%s,",count($quartal\_array)),0,-1).")"; $sqlyr=" AND year(beitraege.datum) in (".substr(str\_repeat("%s,",count($jahreanzahl\_array)),0,-1).")"; echo "Dynamisch "; echo "Quartal Teil 1: ".$sqlqu; echo " Jahr Teil 1: ".$sqlyr; echo " TEst vsprintf\_array: ".vsprintf($sqlqu,$quartal\_array)." ".vsprintf($sqlyr,$jahreanzahl\_array); $sql=$statischer\_part.vsprintf($sqlqu,$quartal\_array).vsprintf($sqlyr,$jahreanzahl\_array); ?\> Völlig flexibel und etliches kürzer!

Wenns interessiert:

Ich habe die Lösung mit Hilfe von Styx:

<?php / ********************** dynamisch */
echo " Anzahl Quartale:".count($quartal\_array)." "; echo "Anzahl jahre:".count($jahreanzahl\_array)." "; $statischer\_part = "select beitraege.\* from beitraege where "; foreach ($quartal\_array as &$value) { $value = mysql\_real\_escape\_string($value); } foreach ($jahreanzahl\_array as &$value) { $value = mysql\_real\_escape\_string($value); } $sqlqu="quarter(beitraege.datum) in (".substr(str\_repeat("%s,",count($quartal\_array)),0,-1).")"; $sqlyr=" AND year(beitraege.datum) in (".substr(str\_repeat("%s,",count($jahreanzahl\_array)),0,-1).")"; echo "Dynamisch "; echo "Quartal Teil 1: ".$sqlqu; echo " Jahr Teil 1: ".$sqlyr; echo " TEst vsprintf\_array: ".vsprintf($sqlqu,$quartal\_array)." ".vsprintf($sqlyr,$jahreanzahl\_array); $sql=$statischer\_part.vsprintf($sqlqu,$quartal\_array).vsprintf($sqlyr,$jahreanzahl\_array); ?\> Danke nochmals für Deine Hilfe! So gehts wesentlich kürzer, dynmaisch und sicher!

Wenns interessiert:

Ich habe die Lösung mit Hilfe von Styx:

<?php / ********************** dynamisch */
echo " Anzahl Quartale:".count($quartal\_array)." "; echo "Anzahl jahre:".count($jahreanzahl\_array)." "; $statischer\_part = "select beitraege.\* from beitraege where "; foreach ($quartal\_array as &$value) { $value = mysql\_real\_escape\_string($value); } foreach ($jahreanzahl\_array as &$value) { $value = mysql\_real\_escape\_string($value); } $sqlqu="quarter(beitraege.datum) in (".substr(str\_repeat("%s,",count($quartal\_array)),0,-1).")"; $sqlyr=" AND year(beitraege.datum) in (".substr(str\_repeat("%s,",count($jahreanzahl\_array)),0,-1).")"; echo "Dynamisch "; echo "Quartal Teil 1: ".$sqlqu; echo " Jahr Teil 1: ".$sqlyr; echo " TEst vsprintf\_array: ".vsprintf($sqlqu,$quartal\_array)." ".vsprintf($sqlyr,$jahreanzahl\_array); $sql=$statischer\_part.vsprintf($sqlqu,$quartal\_array).vsprintf($sqlyr,$jahreanzahl\_array); ?\> Danke nochmals für Deine Hilfe! So gehts wesentlich kürzer, dynmaisch und sicher!