PHP Funktion zur Datenbankabfrage zeigt unterschiedliches Verhalten

Hi Community,

ich schreibe momentan eine kleine Webapplikation. So weit, so gut. Das Schema ist folgendes: erst wird geprüft, ob $_POST["user"] und $_POST["password"] gesetzt sind und auch richtig sind.

PHP:
if((!empty($_POST["user"])) and (!empty($_POST["password"])))
Wenn ja, fragt er die Daten ab und erzeugt eine Tabelle in der die Daten geordnet wiedergegeben werden. Weiterhin wird $_SESSION[logged_in] = 1 gesetzt.

Wenn die index.php nochmals aufgerufen wird und $_SESSION["logged_in"] = 1 gesetzt ist werden die Daten direkt abgerufen, also ohne Passwortabfrage.

PHP:
elseif($_SESSION["logged_in"] == 1)
In beiden Fällen (also nach dem Login und dem Wiederaufrufen mit $_SESSION["logged_in"] = 1) wird die Funktion showUserData($user) aufgerufen. Sie ruft die Daten ab, die mit dem übergebenen User in Verbindung stehen.
Das Komische: logge ich mich ein, ruft er die Daten normal ab. Keine Fehlermeldung, alles super.
Klicke ich jetzt auf einen Link und gehe wieder auf die index.php scheitert showUserData($user) und gibt aus:

Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource
Ich weiß, was die Meldung bedeutet, weiß aber nicht warum sie erscheint. Der Username wird per Sessionvariable übergeben und den query string den ich mir vor dem query ausgeben lasse, stimmt.
Ich weiß momentan nicht mehr weiter. Hat jemand eine Idee? In jedem Fall ist der Query valide, also warum scheitert er trotzdem, sodass die obige Fehlermeldung kommt? Warum funktioniert das direkt nach dem Login und später nicht mehr?

P.S.: Alle Datenbankaufrufe der Applikation werden mit mysql_close geschlossen.
 
ohne den gesamten Code zu sehen, kann man nur mutmaßen...

1.) auch wenn's nicht direkt zum Problem gehört - ich hoffe, du nutzt nicht direkt $_POST['user'] und $_POST['password'] in der SQL-Query - da wären nämlich Tür und Tor für SQL-Injections offen (dazu gibt es hier im Forum schon Threads)

2.) was sagt mysql_errno() und mysql_error()?

also z.B.
PHP:
<?php
$result = mysql_query('SELECT ....');
if (!$result) {
  throw new Exception('Datenbank-Fehler: [' . mysql_errno() . '] ' . mysql_error());
}
?>
 
Hi,

ohne Quellcode von der betreffenden Funtkion kann man nur raten.
Ich rate mal: Du machst irgendwas in deinem MySQL-Aufruf, um Fehlermeldungen zu verdecken (bzw. hast das PHP Error Reporting auf einen zu niedrigen Wert gestellt), z.B. durch ein Voranstellen eines "@"-Zeichens vor den Aufruf (oder durch ein ErrorReporting ohne E_NOTICE).
Aus irgendeinem Grund schlägt dein MySQL-Aufruf fehl (warum, kann man wieder nur raten; vermutlich hast du entweder das Query nicht korrekt zusammengebaut, obwohl du das behauptest, oder die Verbindung ist zu oder irgendein anderer der mannigfaltigen MySQL-Fehler tritt auf), es wird keine Fehlermeldung geschmissen und dein MySQL-Result-Objekt ist null.

Ergo, wenn du fundiertere Hilfe möchtest: Poste mal den PHP-Code um die Abfrage, vor allem auch das zusammenbauen des Query-Strings.
Zusätzlich kannst du direkt nach der Query mit mysql_errno() und mysql_error herausfinden, welchen Fehler der MySQL-Aufruf genau gemacht hat.
Dann sieht man weiter.

mfg, metax.

edit: Wie immer zu langsam ...
 
Scheinbar wirft das bei mir keine Exceptions. Ich kriege keine Fehlernummer auf bei $objects (quasi mein "$result"). Ich poste mal den Code für die Abfrage.

PHP:
function showUserData($user)
  {
    $connection = DBLogin();
    $clean_user = mysql_real_escape_string($user);
    $query = "SELECT amount, purpose, day, month, year FROM spendings WHERE id IN (SELECT id FROM user WHERE user = \"".$clean_user."\")";
    echo $query;
    $objects = mysql_query($query);
    echo var_dump($objects);
    echo "<table>";
    echo "<tr><th>Purpose</th><th>Amount</th></tr>";
    while($row = mysql_fetch_object($objects))
    {
      
      $zahl = sprintf("%01.2f", $row->amount);
      echo "<tr><td>".$row->purpose."</td><td>".$zahl." €</td></tr>";
    }
    echo "</table>";
    
    mysql_close($connection);
  }
Das ist die besagte Funktion. Nach dem Einloggen: alles Klasse. Rufe ich aber eine andere Seite auf und kehre zu ihr zurück, schlägt die Abfrage fehl. var_dump sagt, dass $objects (die den Rückgabewert von mysql_query aufnimmt) boolean und false ist. Für gewöhnlich habe ich das, wenn ein Fehler in der SQL - Syntax ist, aber die ist richtig.

Im Anhang mal die index.php.
 
Was liefert denn mysql_error() und mysql_errno() nach der Abfrage mit mysql_query() zurück?
Siehe auch hier: http://de.php.net/mysql_query
mysql_query() liefert genau dann false zurück, wenn ein Fehler auftritt.
Also musst du noch den von uns vorgeschlagenen Code einbauen und die Fehlermeldung herausfinden.
 
Zuletzt bearbeitet:
Ich danke für eure Hilfe: ich habe es! Habe wohl vorhin einen Fehler bei der Integration von beavisbees Code gemacht, nun hat die Exception aber gegriffen. Der Fehler: keine Datenbank selektiert.

Das Problem ist folgendes: Bei der Login - Prozedur kommt es zum Aufruf von mysql_select_db.
Wenn ich irgendwann wieder auf die Seite gehe, prüft er ob USER und PASSWORD gePOSTet wurden. Wenn nein, prüft er auf eine Session. Die ist vorhanden. Das Problem: ich rufe direkt showUserData dann auf. Dem geht aber kein mysql_select_db voraus. Und daraufhin läuft das Query natürlich ins Leere.

Danke für eure schnelle Hilfe.
 
bitte, bitte, gern geschehen.

und noch zwei kleine Tipps bezüglich deiner SQL-Query:

Code:
"SELECT amount, purpose, day, month, year FROM spendings WHERE id IN (SELECT id FROM user WHERE user = \"".$clean_user."\")"
verschachtelte Queries sollte man nur da verwenden, wo wirklich nötig...

gehe ich richtig in der Annahme, dass in der user-Tabelle immer nur jeder User einmal vorkommt und eine eindeutige ID hat?

Code:
"SELECT
    s.amount,
    s.purpose,
    s.day,
    s.month,
    s.year
FROM
    spendings s,
    user u
WHERE
    s.id=u.id
    AND
    u.user = \"".$clean_user."\"
"

oder

Code:
"SELECT
    s.amount,
    s.purpose,
    s.day,
    s.month,
    s.year
FROM
    spendings s
  INNER JOIN user u ON (s.id=u.id)
WHERE
    u.user = \"".$clean_user."\"
"

hab's jetzt aus Zeitgründen nicht probiert, aber wenn ich mich nicht vertippt habe, dann sollte das so funktionieren.

in der Tabelle "user" ist das Feld "id" ja sicherlich der PrimaryKey und somit schon ein Index, in der Tabelle "spendings" solltest du dann der Performance wegen auf das Feld "id" noch 'nen Index legen.

mehr zu JOINs:
http://dev.mysql.com/doc/refman/5.1/de/join.html
http://aktuell.de.selfhtml.org/artikel/datenbanken/joins/


und du verwendest sowohl in der Tabelle "user" als auch in der Tabelle "spendings" das Feld "id" für die User-ID... wenn du in der Tabelle "spendings" das Feld "user_id" nennst, kann ein dritter, der über deine Datenbank drüber schaut, wesentlich einfacher nachvollziehen, wie die Tabellen miteinander verknüpft sind... wenn du die Felder in beiden Tabellen gleich benannt haben möchtest, dann würde sich eben in beiden Tabellen "user_id" oder "uid" empfehlen - macht die Sache für Außenstehende einfach wesentlich einfacher lesbar ;)
 
erm ... beavis, dir ist schon klar was das bei großen tabellen bewirkt, oder?
kartesisches produkt bilden, und dann filtern ... eine subquery dagegen, wird wirklich sequentiell ausgeführt (bestenfalls O(N+M) statt O(N*M)) ... soll heißen ein seek auf die hoffentlich indizierte user spalte der user tabelle (OHNE jeden datensatz dieser, mit jedem datensatz der spendings tabelle zu verknüpfen, bevor man sucht) und danach mit einer oder mehreren userids ein seek auf die hoffentlich indizierte id spalte der spendings tabelle (wieder OHNE kartesisches produkt)

eine subquery dürfte speziell bei großen tabellen deutlich speicher schonender zu machen sein ... was die laufzeit effizienz von mysql angeht ... solange nur nach einem wert gesucht wird, versuche den 'IN' operator zu meiden ... '=' ist speziell bei größeren tabellen deutlich schneller

allerdings würde ich sagen ist hier weder eine subquery noch ein join gefragt:
ist ein user angemeldet, kann man in der regel seine id in der session hinterlegen ... es geht schneller die id von dort zu nehmen, als immer den namen in die id aufzulösen, wenn die id gebraucht wird ...
 
Zurück
Oben