Franz: PDO Problem mit LIMIT

Hallo in die eloquente Runde!

Auf meinem Rechner zu Hause geht es. Jetzt habe ich es Online gestellt und es funzt nicht mehr.

Wenn ich in der SELECT Anweisung :nummer driekt mit der 3 etc. Anspreche geht es. Also ohne :nummer.

Das komische ist eben, das es zuhause auf dem Rechner geht und auf dem Server eben nicht.

$nummer =3;

$statement 	= $pdo->prepare("SELECT * FROM city ORDER BY id ASC LIMIT :nummer ,1");
$result 	= $statement->execute(array('nummer'=>$nummer ));	
$ergebnis	= $statement->fetch();

Franz

  1. Hallo,

    Auf meinem Rechner zu Hause geht es. Jetzt habe ich es Online gestellt und es funzt nicht mehr.

    dann solltest du dich als erstes fragen: Was ist unterschiedlich? Anderes DBMS? Andere PHP-Version?

    Das komische ist eben, das es zuhause auf dem Rechner geht und auf dem Server eben nicht.

    Leider war "geht nicht" noch nie eine hilfreiche Fehlerbeschreibung. Welche Fehlermeldungen, welche Ergebnisse bekommst du? Ich hoffe doch, dass du Fehlermeldungen (auch Notices) im Entwicklungsstadium auch anzeigen lässt. Die sind nämlich beim Debugging Gold wert.

    $nummer =3;
    
    $statement 	= $pdo->prepare("SELECT * FROM city ORDER BY id ASC LIMIT :nummer ,1");
    $result 	= $statement->execute(array('nummer'=>$nummer ));	
    $ergebnis	= $statement->fetch();
    

    Keinerlei Fehlerbehandlung. Du verwendest die Ergebnisse der einzelnen Abfragestufen, ohne sie anzusehen, gehst einfach davon aus, dass alles sauber läuft. Erst ganz zum Schluss stellst du fest, dass du nicht das Ergebnis bekommst, was du erwartest. Dabei kann der eigentliche Fehler schon viel früher passiert sein.

    Debugging heißt: Schritt für Schritt verfolgen, was da wirklich passiert!

    Live long and pros healthy,
     Martin

    --
    Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
    1. Auf meiner Testebene kommt kein Fehler und die Anzeige ist korrekt. Auf dem Server wird kein Fehler angezeigt, error_reporting(E_ALL).

      Nur die Ausgabe ist leer, als ob kein Treffer erzeilt wurde. Ich gehe davon aus, das es :nummer ist, da ich wenn ich sie direkt setze angezeigt wird.

      Wie kann ich am besten vorgehen um mir den Fehler anzeigen zu lassen.

      1. Hi,

        Auf meiner Testebene kommt kein Fehler und die Anzeige ist korrekt. Auf dem Server wird kein Fehler angezeigt, error_reporting(E_ALL).

        werden Fehler auch generell angezeigt?
        display_errors = 1 in der php.ini, alternativ ini_set('display_errors', '1'); am Scriptanfang?

        Nur die Ausgabe ist leer, als ob kein Treffer erzeilt wurde. Ich gehe davon aus, das es :nummer ist, da ich wenn ich sie direkt setze angezeigt wird.

        Dein Beispielcode ist so kurz und überschaubar, dass mir kein Grund einfällt, warum das so sein sollte. Hast du vielleicht für Forum-Beispiel zu stark vereinfacht? Ist dein tatsächlicher Code in Wirklichkeit komplexer?

        Wie kann ich am besten vorgehen um mir den Fehler anzeigen zu lassen.

        Schrittweise. Prüfe nach jedem SQL-Methodenaufruf, was du zurückbekommst und ob dieses Ergebnis plausibel ist. Das ist die beste Systematik, um erstmal zu finden, an welcher Stelle es schiefgeht.

        Live long and pros healthy,
         Martin

        --
        Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
      2. Hallo Franz,

        bevor DU lange suchst, eine ganz blöde Frage: Bist Du überzeugt und hast Du es überprüft, dass die Datenbank, die Du am benutzt, überhaupt Einträge in der city-Tabelle hat?

        Grundsätzlich sieht dein SQL korrekt aus, und der Umstand, dass der Array-Parameter von execute zur Bindung eines String-Parameters führt, scheint auf deiner Entwicklerkiste nichts auszumachen, daher hoffe ich mal, dass das nicht das Problem ist. Unsauber ist es schon, weil LIMIT eine Zahl erwartet und keinen String. Die sauberere Lösung ist, mit bindValue oder bindParam zu arbeiten. Ich schreib's unten mal als Beispiel mit hinein. Wenn man sowas macht, übergibt man die Parameter nicht mehr an execute(). Aber wie gesagt: ich glaube nicht dass es nötig ist. Der Unterschied zwischen bindParam und bindValue ist, dass bindParam beim execute in die Variable schaut, d.h. wenn Du 5 execute machst und jedesmal der Variablen einen anderen Wert gibst, wird auch jedesmal ein anderer Wert benutzt. Bei bindValue bindest Du einmal einen festen Wert.

        Und error_reporting genügt bei SQL Abfragen nicht. Du musst nach den prepare und nach dem fetch prüfen, ob das Ergebnis FALSE ist.

        // prepare liefert ein Statement oder FALSE
        
        $statement 	= $pdo->prepare("SELECT * FROM city ORDER BY id ASC LIMIT :nummer ,1");
        if ($statement === FALSE) {
           $errInfo = $pdo->errorInfo();
           echo "Prepare-Fehler! SQLSTATE=$errInfo[0], Driver Errorcode $errInfo[1]<br>Driver message: $errInfo[2]<br>";
        }
        
        // Beispiel für explizite Bindung
        $statement->bindParam(':nummer', $nummer, PDO::PARAM_INT);
        $statement->bindValue(':nummer', $nummer, PDO::PARAM_INT);
        
        // execute liefert immer nur TRUE oder FALSE
        if (!$statement->execute(array('nummer'=>$nummer )))	
           $errInfo = $pdo->errorInfo();
           echo "Execute-Fehler! SQLSTATE=$errInfo[0], Driver Errorcode $errInfo[1]<br>Driver message: $errInfo[2]<br>";
        }
        $ergebnis	= $statement->fetch();
        if ($ergebnis === FALSE) {
           $errInfo = $pdo->errorInfo();
           echo "Fetch-Fehler! SQLSTATE=$errInfo[0], Driver Errorcode $errInfo[1]<br>Driver message: $errInfo[2]<br>";
        }
        

        Der Vergleich auf FALSE muss mit === erfolgen, um ausschließlich das boolsche FALSE zu erwischen und nicht irgendeinen möglichen falsy-Wert.

        Eine solche Fehlerbehandlung kann man auch in eine Funktion auslagern, und ob echo für dich der richtige Weg ist oder ob Du ein anderes Logging verwendest, hängt von deiner Webseite ab. Der echo ist nur ein Beispiel (und kann je nach Bauweise deiner Seite auch zu Problemen führen).

        Rolf

        --
        sumpsi - posui - obstruxi
  2. Lieber Franz,

    $result 	= $statement->execute(array('nummer'=>$nummer ));	
    

    der Array-Schlüssel sollte auch einen Doppelpunkt am Anfang haben:

    $result 	= $statement->execute(array(
      ':nummer' => $nummer
    ));	
    

    Offensichtlich ist dieser Doppelpunkt im Array auf manchen Systemen erforderlich und auf anderen nicht. Ob das der feine Unterschied zwischen MySQL und MariaDB ist - keine Ahnung und ist mir auch egal.

    Liebe Grüße

    Felix Riesterer