mysql-db auslesen mit while und alle Werte in einer var speichen
DerWaldgeist
- php
Hallo,
ich habe folgendes Problem: Ich möchte aus einer Datenbank per Suchfunktion bestimmte Werte auslesen (mit while weiterverarbeiten) und das Ergebnis der Suche in einer temp-Datei speichern.
Hier sollen wenn z.Bsp. nach allen Personen aus einem Land gesucht wird, die zugehörigen Daten für Vor- und Nachnamen herausgesucht werden und dann in eine Variable geschrieben werden - etwa in diesem Stil:
$ganznamen = "Name1,Name2,Name3,Name4,Name5";
Das Problem ist, dass die Variable $ganznamen zwar wenn ich sie per echo ausgeben lasse in der richtigen Form und vollständig ist ("Name1,Name2,Name3,Name4,Name5"), aber in die temp.php Datei wird lediglich der allerletzte Wert eingetragen (also etwa Name5) ? ...
Mein Skript sieht momentan etwa so aus:
<?php
include "connect.php"; // die Verbindung zur Datenbank steht da drin
$data // $data kommt per Post an $_POST ... (steht halt ein Land drin)
$abfrage = "SELECT * FROM dbname WHERE land LIKE '".$data."'";
$suche = mysql_query($abfrage);
while($sdata = mysql_fetch_object($suche))
{
$ergeb1 = $sdata3->vorname;
$ergeb2 = $sdata3->nachname;
$ergeb3 = $sdata3->land;
// Die Var wird zusammengesetzt
$ganznamen = $ergeb1." ".$ergeb2.",";
echo $ganzname; // hier stimmt noch alles (Name1,Name2,usw.)
/**** TEMP DATA EINTRAG --> temp.php ****/
$input = "<?"."php "."\n"."$"."namen = '".$ganznamen."';"."\n"." ?>";
/*********/
$fpB = fopen("temp.php", 'w', TRUE);
fwrite($fpB, $input, strlen($input));
fclose ($fpB); // hier steht leider nur noch der letzte Wert drin ???
} //ende while
mysql_free_result($suche);
?>
Ich hoffe es kann mir da irgendjemand helfen -- irgendwie scheint es so als ob beim "fwrite" alle Werte bis auf den letzten überschrieben sind, so dass nur der letzte Name der Liste eingetragen wird ... verstehe aber nicht warum - habe dann versucht das schreiben in die temp.php erst nach der while-schleife durchzuführen (also nach dem } //ende while ), aber das ergibt leider auch das selbe ergebnis ... wie kriege ich denn alle Werte (Name1,Name2,usw.) in eine dauerhaft (bis zum ende des skriptes) existente Variable ??
Danke schonmal :-)
echo $begrüßung;
$data // $data kommt per Post an $_POST ... (steht halt ein Land drin)
Was per POST ankommt steht in $_POST drin. Deswegen heißt dieses Array ja auch so. Diese Werte in andere Variablen umzukopieren ist sinnlos. Einem $_POST sieht man sofort die Herkunft der Daten an und kann sich dann das Kommentieren und Beachten bei "einfachen" Variablen sparen. Wenn das Anlegen per register_globals automatisch passiert, so setzt du auf ein seit Jahren auf der Abschussliste stehendes Feature.
$abfrage = "SELECT * FROM dbname WHERE land LIKE '".$data."'";
Wann immer du Werte in einen Kontext bringst, sind diese Werte kontextgerecht zu behandeln. Wenn jemand aus Côte d'Ivoire kommt, bekommst du nur einen Syntaxfehler. Wenn jemand ' OR 1 eingibt, ist das Abfrageergebnis nicht mehr in deinem Sinne. Und wenn jemand ' UNION SELECT * FROM mysql.user eingibt, kann das unter Umständen ernsthafte Auswirkungen für deine Daten nach sich ziehen. Um etwas in einen String in einem MySQL-Statement einzufügen ist, ist dieser Wert mit mysql_real_escape_string() zu behandeln. Wenn du auf Magic Quotes vertraust, dann baust du ebenfalls auf ein veraltetes Feature. Deaktiviere die Magic Quotes, was du sowieso tun must, wenn du mit mysql_real_escape_string() arbeitest.
Und dann gibt es die Funktion sprintf(), mit der man etwas mehr Übersicht in zusammenzusetzende String bekommen kann.
$abfrage = sprintf("SELECT * FROM dbname WHERE land LIKE '%s'", mysql_real_escape_string($_POST['data']));
$suche = mysql_query($abfrage);
while($sdata = mysql_fetch_object($suche))
Ein mysql_query() kann als Ergebnis ein false zurückmelden, wenn es seine Aufgabe mit einer Aufgabe vorzeitig beenden musste. Diesen Zustand solltest du zum einen nicht ignorieren, denn ein false ist kein gültiges Argument für die Fetch-Funktionen. Zum anderen ist es keine gute Idee, einfach das Script weiterlaufen zu lassen, als ob nichts wäre, denn das ergibt meist weitere nicht mehr funktionierende Abhängigkeiten. Zudem steht der Anwender da und weiß nicht, was er falsch gemacht hat (falls er überhaupt daran schuldig ist) und wie er trotzdem noch an sein Ziel kommen kann.
$ergeb1 = $sdata3->vorname;
$ergeb2 = $sdata3->nachname;
$ergeb3 = $sdata3->land;
Schon wieder ein Umkopieren ohne Sinn.
$input = "<?"."php "."\n"."$"."namen = '".$ganznamen."';"."\n"." ?>";
Es ist nicht erforderlich, die Zeichenfolge <?php, so sie in einem String notiert ist, auseinanderzunehmen. Auch muss man für \n einen ""-String nicht verlassen. Und das erste $ kann man durch Voranstellen eines \ entschärfen. Du tust dir und den Codelesern keinen Gefallen, wenn du Strings dermaßen auseinandergerissen notierst.
$input = "<?php \n\$namen = '$ganznamen';\n ?>";
Außerdem ist es garantiert nicht der Sicherheit dienlich, wenn du Code aus Benutzereingaben zusammenbaust, noch dazu vermutlich ungefilterten. Manche Leute heißen dann auf einmal ';phpinfo(); $foo=' oder noch unangenehmer.
// Die Var wird zusammengesetzt
$ganznamen = $ergeb1." ".$ergeb2.",";
echo $ganzname; // hier stimmt noch alles (Name1,Name2,usw.)
Sicher? $ganzname und $ganznamen sind zwei unterschiedliche Variablen. Hast du das error_reporting auf E_ALL stehen? Wenn das nicht nur ein Abtippfehler ist, könnte dir PHP daraufhin mit einer Notice anzeigen, dass $ganzname nicht existiert.
/**** TEMP DATA EINTRAG --> temp.php ****/
$input = "<?"."php "."\n"."$"."namen = '".$ganznamen."';"."\n"." ?>";
Und hier? Stimmt hier auch noch alles? Sprich: Du schreibst ja $input in die Datei, also solltest du dessen Inhalt kontrollieren. Beachte hierbei ebenfalls, dass du einen Kontextwechsel vorliegen hast und besonders bei der Ausgabe der < und > eine HTML-gerechte Notation an den Browser schicken musst. htmlspecialchars() hilft dir dabei.
/*********/
$fpB = fopen("temp.php", 'w', TRUE);
fwrite($fpB, $input, strlen($input));
Wieder keine Fehlerbehandlung. Bist du außerdem sicher, dass du beim dritten Parameter das true und seine Auswirkungen haben möchtest?
fclose ($fpB); // hier steht leider nur noch der letzte Wert drin ???
} //ende while
Nunja, du öffnest und schließt die Datei in jedem while-Schleifen-Durchgang, was schonmal unnötig aufwendig ist. Weiterhin verwendest du den Mode w. Lies bitte im Handbuch zu fopen() nach, was der macht, ob das in deinem Sinne ist und ob es nicht etwas besseres gibt. Am besten wäre jedoch, das Öffnen und Schließen außerhalb der while-Schleife anzusiedeln.
echo "$verabschiedung $name";
Hi,
puh, danke erst mal für die infos :-), offenbar ist mein code ja ganz schön unsauber - hab' mir php selber beigebracht per try and error, da schleichen sich solche sachen irgendwie immer ein.
Ich habe jetzt versucht mein Skript etwas zu verbessern.
Das deaktivieren der magic_quotes_gpc funktioniert leider nicht; ich habe versucht es per .htaccess (php_flag magic_quotes_gpc off) auszuschalten aber da kriege ich dann nur noch 500 Server Error. An die php.ini darf ich leider nicht ran. Momentan ist die Konfiguration folgend:
magic_quotes_gpc On On
magic_quotes_runtime Off Off
magic_quotes_sybase Off Off
Dennoch scheint das umgebaute Skript zu tun was es soll, ich lasse mir die Ergebnisse vorher einzeln anzeigen und das geht alles.
Nur: auch wenn ich die temp.php erst nach dem Ende der While schleife schreibe, kriege ich nur den zuletzt durchlaufenen Wert. Offenbar wird bei jedem durchlauf der while-Schleife der vorige Wert in der $ganznamen überschrieben, so dass man nur den letzten Wert erhält - eigentlich logisch.
Ich habe das Problem jetzt nur auf eine etwas umständlich-riskante Art lösen können indem ich einmal vor der while-Schleife den Anfang der temp.php schreibe, dann in der while-schleife die Daten einfüge und nach der while-Schleife das Ende der temp.php einfüge. Man schreibt dann bei 100 Personen also 102 mal in die Datei ... ob das wohl gut ist ???
Momentan also etwa so:
<?php
// Fehlermeldungen
error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);
include "connect.php"; // die Verbindung zur Datenbank steht da drin
$abfrage = sprintf("SELECT * FROM dbname WHERE land LIKE '%s'", mysql_real_escape_string($_POST['data']));
$suche = mysql_query($abfrage);
if (!$suche) {
die('Fehler 001 ' . mysql_error());
exit;
}
// ANFANG DER temp.php
$start = "<?php \n\$namen = '";
$fp0 = fopen("temp.php", 'w');
fwrite($fp0, $start, strlen($start));
fclose ($fp0);
while($sdata = mysql_fetch_object($suche))
{
$ergeb1 = $sdata3->vorname;
$ergeb2 = $sdata3->nachname;
$ergeb3 = $sdata3->land;
/**** TEMP DATA EINTRAG --> temp_adr.php ****/
$ganznamen = $ergeb1." ".$ergeb2.",";
$fpA = fopen("temp.php", 'a+b');
fwrite($fpA, $ganznamen, strlen($ganznamen));
fclose ($fpA);
} //ende while
// ENDE der temp.php
$inputB = "';\n ?>";
$fpA2 = fopen("temp.php", 'a+b');
fwrite($fpA2, $inputB, strlen($inputB));
fclose ($fpA2);
mysql_free_result($suche);
?>
Falls es da eine bessere Lösung gibt, wärs' super ... Danke ...
Hi nochmal,
sorry, habe 'grade bemerkt, dass ich die erste Antwort auf meine Frage übersehen hatte - werde das hier
/**** Array der Namen ****/
$namen[] = $ganznamen;
/*...*/
jetzt mal versuchen - bin einfach zu müde heute ...
Hi DerWaldgeist!
sorry, habe 'grade bemerkt, dass ich die erste Antwort auf meine Frage übersehen hatte - werde das hier
/**** Array der Namen ****/
$namen[] = $ganznamen;
/*...*/jetzt mal versuchen
Tu das. Es wird deinen Code erheblich verkürzen und einfacher lesbar machen.
bin einfach zu müde heute ...
Du solltest die Uhr eine Stunde zurück-, nicht vorstellen.
Zur Information: Es ist jetzt 11:36. ;-)
MfG H☼psel
... so, die dritte Tasse Kafee und der Waldgeist ist wieder fast ein Mensch ;-)
... das war die Lösung:
// ...
$namen[] = $ganznamen;
} // ende while
$weralso = implode(",", $namen);
echo "Namenliste: ".$weralso;
// ... dann erst die temp.php erstellen ...
:-) ein vieles Danke nochmal
echo $begrüßung;
Das deaktivieren der magic_quotes_gpc funktioniert leider nicht;
Für diesen Fall gab es auf der verlinkten Seite einen Codeschnipsel, den man am Anfang des Scripts einbauen kann. Der macht die Auswirkungen der Magic Quotes zur Laufzeit rückgängig.
Dennoch scheint das umgebaute Skript zu tun was es soll, ich lasse mir die Ergebnisse vorher einzeln anzeigen und das geht alles.
Die Magic Quotes sind zwar für die Entschärfung einiger Zeichen vorgesehen, aber die Maskierungen für SQL-Statements sind in anderen Zusammenhängen unbrauchbar. Ein Affenformular beispielsweise wirft die Daten dem Anwender so lange wieder vor die Füße, bis der keine Fehler mehr drin hat. Eine Datenbank ist dabei nicht im Spiel, die Magic Quotes also nicht brauchbar, sie kommen aber in die HTML-Ausgabe, wenn man sie nicht entfernt.
Nur: auch wenn ich die temp.php erst nach dem Ende der While schleife schreibe, kriege ich nur den zuletzt durchlaufenen Wert.
Das wäre auch eine Möglichkeit. Setzt zuerst die auszugebenden Daten in einem String zusammen und schreibe den dann in einem Rutsch. Das verbraucht aber Speicher, je länger der String wird desto mehr. Die Daten gleich wegzuschreiben ist ressourcenschonender.
Offenbar wird bei jedem durchlauf der while-Schleife der vorige Wert in der $ganznamen überschrieben, so dass man nur den letzten Wert erhält - eigentlich logisch.
Kontrollausgabe helfen, Licht ins Dunkle zu bringen. Spekulieren muss man bei Programmieren normalerweise nicht.
Ich habe das Problem jetzt nur auf eine etwas umständlich-riskante Art lösen können indem ich einmal vor der while-Schleife den Anfang der temp.php schreibe, dann in der while-schleife die Daten einfüge und nach der while-Schleife das Ende der temp.php einfüge. Man schreibt dann bei 100 Personen also 102 mal in die Datei ... ob das wohl gut ist ???
Es ist kein Problem, mehrfach in eine Datei zu schreiben. Sie muss dazu aber nicht jedes Mal geöffnet und wieder geschlossen werden. Einmal vor bzw. nach dem die Daten zusammensuchenden Teil reicht.
$suche = mysql_query($abfrage);
if (!$suche) {
die('Fehler 001 ' . mysql_error());
exit;
Ein die() beendet bereits das Script. Ein exit danach wird nie ausgeführt werden. Allerdings ist die() keine Fehlerbehandlung, oder wie es Cheatah trefflicher formulieren konnte: http://community.de.selfhtml.org/zitatesammlung/zitat1282
Der Anwender kann mit einem MySQL-Fehlermeldungstext nichts anfangen. Wenn er es doch kann, will man nicht, dass dieser Anwender damit was zum Nachteil meiner Datenbank anfangen kann. Fehlermeldungen sollte man so behandeln, dass nur der Administrator sie zu Gesciht bekommt. Der Anwender sollte eine für ihn sinnvolle Meldung vorgesetzt bekommen. Die sollte sich im restlichen Layout der Seite befinden und nicht am Ende einer halben, abgebrochenen Seite stehen.
echo "$verabschiedung $name";
Moin!
Wann immer du Werte in einen Kontext bringst, sind diese Werte kontextgerecht zu behandeln. Wenn jemand aus Côte d'Ivoire kommt, bekommst du nur einen Syntaxfehler.
$input = "<?php \n\$namen = '$ganznamen';\n ?>";
Was für den Kontext "Variableninhalt kommt in SQL" gilt, gilt natürlich auch für den Kontext "Variableninhalt kommt in PHP-Sourcecode" - nur sind die Konsequenzen hier drastischer, wenn man dabei irgendeinen Fehler macht. Ausserdem ist das Escaping komplizierter, weil es für die hier notwendigen Ersetzungen von Zeichen in sichere Ersatzzeichen keine komplett fertige Funktion gibt.
Außerdem ist es garantiert nicht der Sicherheit dienlich, wenn du Code aus Benutzereingaben zusammenbaust, noch dazu vermutlich ungefilterten. Manche Leute heißen dann auf einmal ';phpinfo(); $foo=' oder noch unangenehmer.
Leider lieferst du an dieser Stelle den gefährlichen Code, und nicht den Versuch des ungefährlichen Codes.
- Sven Rautenberg
echo $begrüßung;
Wann immer du Werte in einen Kontext bringst, sind diese Werte kontextgerecht zu behandeln. Wenn jemand aus Côte d'Ivoire kommt, bekommst du nur einen Syntaxfehler.
$input = "<?php \n\$namen = '$ganznamen';\n ?>";
Was für den Kontext "Variableninhalt kommt in SQL" gilt, gilt natürlich auch für den Kontext "Variableninhalt kommt in PHP-Sourcecode" - nur sind die Konsequenzen hier drastischer, wenn man dabei irgendeinen Fehler macht. Ausserdem ist das Escaping komplizierter, weil es für die hier notwendigen Ersetzungen von Zeichen in sichere Ersatzzeichen keine komplett fertige Funktion gibt.
Ich erwähnte etwas weiter unten und in etwas anderem Zusammenhang das passende Werkzeug dazu: htmlspecialchars(). So wäre es für diese Stelle richtig gewesen:
$input = sprintf("<?php \n\$namen = '%s';\n ?>", htmlspecialchars($ganznamen, ENT_QUOTES));
Das ENT_QUOTES wird in dem Fall benötigt, da der Wert von $ganznamen hier mit ' eingerahmt ist. Dieses Zeichen wird von htmlspecialchars() normal nicht beachtet, muss aber in dem Fall. Mit ENT_QUOTES wird ein ' zu ' umgearbeitet und kann somit nicht mehr den String beenden.
Außerdem ist es garantiert nicht der Sicherheit dienlich, wenn du Code aus Benutzereingaben zusammenbaust, noch dazu vermutlich ungefilterten. Manche Leute heißen dann auf einmal ';phpinfo(); $foo=' oder noch unangenehmer.
Leider lieferst du an dieser Stelle den gefährlichen Code, und nicht den Versuch des ungefährlichen Codes.
Es ist immer gut, wenn noch mal jemand kritisch drüberschaut. Danke.
echo "$verabschiedung $name";
Moin!
Wann immer du Werte in einen Kontext bringst, sind diese Werte kontextgerecht zu behandeln. Wenn jemand aus Côte d'Ivoire kommt, bekommst du nur einen Syntaxfehler.
$input = "<?php \n\$namen = '$ganznamen';\n ?>";
Was für den Kontext "Variableninhalt kommt in SQL" gilt, gilt natürlich auch für den Kontext "Variableninhalt kommt in PHP-Sourcecode" - nur sind die Konsequenzen hier drastischer, wenn man dabei irgendeinen Fehler macht. Ausserdem ist das Escaping komplizierter, weil es für die hier notwendigen Ersetzungen von Zeichen in sichere Ersatzzeichen keine komplett fertige Funktion gibt.Ich erwähnte etwas weiter unten und in etwas anderem Zusammenhang das passende Werkzeug dazu: htmlspecialchars(). So wäre es für diese Stelle richtig gewesen:
Das ist das falsche Werkzeug.
Sinn der Übung ist es, PHP-Code zu generieren. Der Code soll so aussehen, dass eine Variable den Inhalt eines Strings zugewiesen bekommt, und der Stringinhalt stand vorher in der Datenbank.
Mit HTML-Escaping bist du da vollkommen falsch. Stattdessen musst du dich auf die Vorkommen von Anführungszeichen sowie Steuerzeichen wie Newline, Linefeed, Tabs etc. konzentrieren. Halt alle die Zeichen, die normalerweise unsichtbar bleiben.
- Sven Rautenberg
echo $begrüßung;
Das ist das falsche Werkzeug.
Stimmt. Ein HTML-Kontext liegt zu diesem Zeitpunkt nicht vor. Warum ich den unterstellt habe, entzieht sich grad meiner Kenntnis.
Sinn der Übung ist es, PHP-Code zu generieren. Der Code soll so aussehen, dass eine Variable den Inhalt eines Strings zugewiesen bekommt, und der Stringinhalt stand vorher in der Datenbank.
Mit HTML-Escaping bist du da vollkommen falsch. Stattdessen musst du dich auf die Vorkommen von Anführungszeichen sowie Steuerzeichen wie Newline, Linefeed, Tabs etc. konzentrieren. Halt alle die Zeichen, die normalerweise unsichtbar bleiben.
Einfache Anführungszeichen und der Backslash reichen. Letzerer muss zudem nur beachtet werden, wenn er vor einem ' steht. Es stört aber auch nicht, wenn er einzeln stehend als \ notiert wird. Für alle anderen Zeichen gibt es innerhalb eines Single-quoted-Strings keine Ersatz-Notation. Auch nicht für Steuerzeichen.
Also reicht ein strtr($ganznamen, array('\' => '\\', ''' => '\'')) beim Einfügen des Wertes.
echo "$verabschiedung $name";
Hi DerWaldgeist!
ich habe folgendes Problem: Ich möchte aus einer Datenbank per Suchfunktion bestimmte Werte auslesen (mit while weiterverarbeiten) und das Ergebnis der Suche in einer temp-Datei speichern.
Warum? Du kannst auch temporäre Tabellen in MySQL nutzen.
Ich hoffe es kann mir da irgendjemand helfen -- irgendwie scheint es so als ob beim "fwrite" alle Werte bis auf den letzten überschrieben sind, so dass nur der letzte Name der Liste eingetragen wird ... verstehe aber nicht warum [...]
Du öffnest die Datei in der Schleife immer wieder mit 'w'. Beachte dazu den Eintrag aus dem Manual:
"Öffnet die Datei nur zum Schreiben und setzt den Dateizeiger auf den Anfang der Datei sowie die Länge der Datei auf 0 Byte. Wenn die Datei nicht existiert wird versucht sie anzulegen."
Das bedeutet, du überschreibst die Datei jedesmal wieder. Entweder, du nutzt also 'a', oder du speicherst die Zwischenwerte in der Schleife und arbeitest danach mit ihnen weiter.
Ich würde es so machen:
while($sdata = mysql_fetch_object($suche)) {
/*..*/
/**** Array der Namen ****/
$namen[] = $ganznamen;
/*...*/
}
So hast du am Ende alle Namen in einem Array und kannst damit machen, was immer du vorhast, z. B. zu einem kommasepariertem String implodieren und in einer Datei abspeichern.
MfG H☼psel