Sven: Javascipt Fehler

Hallo,

was mache ich hier falsch?

$(document).ready(function() {

function refresh() {
                $.ajax({
                type: 'POST',
                url: './reload.php',
                data: { 
					ID: '".$ID."',
					Art: 'K'
				},
				success : function(data) {
                var einzeldata = JSON.parse( data );
				if ( datenset.typ === 'success' ) {
                $('.status').show(300);
				} else if (datenset.typ === 'logout') {
                $('.status').show(300);
				exit;
				} else {
                //$('.inline_error').html(datenset.wert);
				}
				setTimeout(refresh, 5000);
                },error:function(e){
                //alert('Ajax Error')
				;}
    });
}

setTimeout(refresh, 5000);

});

reload.php (Quasicode)

$session_ok = 1;

if(session vorbei) {
    $wertinhalt = 'Autologout!';
    $session_ok = 0;
    $data = array(
        array('id' => '','wert' => $wertinhalt,'typ' => 'logout')
    );
}

if($session_ok == 1) {
    if(... == 1) {
        $wertinhalt = "Es liegt eine Änderung vor, bitte Seite neu laden...";
        $data = array(
            array('id' => '','wert' => $wertinhalt,'typ' => 'success')
        );
    } else {
        $data = array(
            array('id' => '','wert' => $wertinhalt,'typ' => 'test')
        );
    }
}

$encodiert = json_encode($data);
echo $encodiert;

Wenn ein JSON String vom datenset.typ "success" kommt, wird die Statuszeile eingeblendet und alles läuft.

Wenn aber eine vom datenset.typ "logout" kommt, dann erhalte ich nr eine Fehlermeldung:

Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
    success http://localhost/reload.php?
  

Es scheint folgender JSON-String beim Script anzukommen:

[{"id":"","wert":null,"typ":"test"}]

Kann mir einer erklären, was hier falsch läuft und wie ich das permanente Feuern des Ajax schlicht nach einem Logout des Users abbrechen kann, auch wenn dieser Browsertab die ganze Zeit geöffnet bleibt?

Natürlich am liebsten mit einer Meldung in der Statuszeile, dass der User ausgeloggt wurde. Das war mein Ziel obigen Codes.

Sven

  1. Hallo Sven,

    Wenn aber eine vom datenset.typ "logout" kommt, dann erhalte ich nr eine Fehlermeldung:

    Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
        success http://localhost/reload.php?
    

    Es scheint folgender JSON-String beim Script anzukommen:

    [{"id":"","wert":null,"typ":"test"}]
    

    Punkt 1: Es wäre nicht verständlich, wo im Logout-Fall ein JSON-Objekt mit typ=test herkommt. Du setzt $session_ok auf 0 und überspringst den Folgeteil damit. Wenn da typ=test steht, war die Session valide und ... war nicht gleich 1.

    Warum überhaupt $wertinhalt setzen? Die Konstante 'Autologout' kannst Du auch direkt im Array eintragen.

    Warum überhaupt eine $session_ok Variable? Kannst Du den Teil, der nur bei einer gültigen Session laufen soll, nicht einfach in ein else verpacken?

    Punkt 2: Der Syntax-Error. Der muss von JavaScript kommen, PHP wirft keinen Syntax-Error beim Parsen von kaputtem JSON. Debugging mit alerts ist - mit Verlaub - Kacke. Verwende console.log und mach die Entwicklerwerkzeuge vom Browser auf, um die Konsole zu sehen. Und dann gib vor dem JSON.parse den Inhalt von data aus. Alternativ kannst Du Dir im Netzwerk-Tab der Entwicklerwerkzeuge auch die Antwort des Ajax-Aufrufs anschauen.

    Ich bin nämlich nicht überzeugt, dass da das drin steht, was Du meinst. Ich nehme an, dass da eine PHP Notice drin steht, dass irgendwas nicht passt, und die ist natürlich kein valides JSON. Wenn ich im Firefox einen JSON.parse Aufruf mache und ihm JSON Müll übergebe, bekomme ich genau deine Meldung.

    Punkt 3: Deine zurückgegebenen Daten. Warum hüllst Du das Objekt in ein Array ein? Das ist nicht nötig. Du musst das Array dann am Client nur unnötig auspacken - ich würde annehmen, das hast Du in deinem geposteten Code herausgenommen. Denn dies hier kann nicht funktionieren:

            var einzeldata = JSON.parse( data );
            if ( datenset.typ === 'success' ) {
    

    Woher käme der Wert in datenset, wenn Du dort nicht vorher einzeldata[0] abgelegt hättest?!

    Punkt 3: Content-Type. Beim Zurückgeben eines JSON-Strings ist es empfehlenswert, zu Beginn des Scripts diese Funktion aufzurufen, um dem Browser mitzuteilen, dass dies kein HTML ist.

    header('Content-Type: application/json; charset=utf-8');
    

    Punkt 4: Abfrage von "session vorbei" ohne Polling: Geht nicht. Du hast PHP-seitig keine Wächterfunktion vorliegen, die beim Verfall einer Session getriggert wird. Ich weiß auch gar nicht, wie man PHP sagen sollte, dass eine Session eine maximale Lebensdauer hat. Man kann dem Session-GarbageCollector eine Zeit mitgeben, nach der es ihm erlaubt ist, alte Sessions abzuräumen. Der läuft aber nicht deterministisch, sondern startet zufällig mit einer gewissen Wahrscheinlichkeit. Wann genau das passiert, habe ich gerade im PHP Handbuch nicht gefunden, und vor 16 Jahren schrieb ein gewisser Matt dies.

    D.h. Du kannst dem Client nur die Timeout-Zeit deiner Sessions mitteilen und der Client kann dann mittels setTimeout einen eigenen Timer starten. Den muss er natürlich bei jedem Serverkontakt, der die Session aktualisiert, zurücksetzen (setTimeout gibt ein Löschticket zurück, mit dem Du clearTimeout aufrufen kannst um den Timer zu löschen).

    Punkt 5: Dein Timer. Ich habe Dir zwar gerade empfohlen, ihn abzuschaffen und es anders zu lösen, aber wenn Du nochmal einen Intervall-Timer brauchst, nimm die setInterval-Funktion statt setTimeout.

    Punkt 6: Deine Codegenerierung. Ich sehe da

          data: { 
              ID: '".$ID."',
              Art: 'K'
          },
    

    Und das heißt: Du gibst das JavaScript als einen langen String aus, und brichst Dir vermutlich einen ab, wenn Du Anführungszeichen benutzt.

    Bessere Lösung:

    <?php
       // bla bla code code
    ?>
    <script>
    $(document).ready(function() {
    
    function refresh() {
      $.ajax({ 
        type: 'POST',
        url: './reload.php',
        data: { 
          ID: '<?= $ID ?>',
          Art: 'K'
        },
    		success : function(data) {
           ...
        }
       ...
    }
    </script>
    <?php
       // Weiteres PHP
    

    D.h. du schaltest den PHP-Modus einfach aus und schreibst JavaScript. Ein guter Code-Editor sollte damit zumindest ansatzweise klarkommen. In dem Moment, wo Du den Wert von $ID brauchst, verwendest Du das PHP-Tag <?= ?>, mit dem Du den Wert einer Variablen oder eines Ausdrucks in die Ausgabe einsteuern kannst.

    Punkt 7: An Stelle eines ready-Handlers mit jQuery kannst Du dein <script> Element auch einfach mit dem Attribut defer versehen. Solche Scripte werden ausgeführt, wenn das DOM fertig aufgebaut ist.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      unglaublich, wie Du Dich mit soviel (Fremd)Code auseinandersetzt, das ist schon klasse!

      [{"id":"","wert":null,"typ":"test"}]
      

      Punkt 1: Es wäre nicht verständlich, wo im Logout-Fall ein JSON-Objekt mit typ=test herkommt. Du setzt $session_ok auf 0 und überspringst den Folgeteil damit. Wenn da typ=test steht, war die Session valide und ... war nicht gleich 1.

      Das sehe ich genauso. Deshalb frage ich hier nach.

      Warum überhaupt eine $session_ok Variable? Kannst Du den Teil, der nur bei einer gültigen Session laufen soll, nicht einfach in ein else verpacken?

      Eigentlich schon, aber ich frage nur jede halbe Stunde nach, ob die Session noch gültig ist und dann würde auch der Restcode nur jede halbe Stunde laufen. Daher der Umweg über $session_ok.

      Punkt 2: Der Syntax-Error. Der muss von JavaScript kommen, PHP wirft keinen Syntax-Error beim Parsen von kaputtem JSON. Debugging mit alerts ist - mit Verlaub - Kacke. Verwende console.log und mach die Entwicklerwerkzeuge vom Browser auf, um die Konsole zu sehen.

      Genau dort habe ich ja die Fehlermeldung heraus kopiert.

      Und dann gib vor dem JSON.parse den Inhalt von data aus. Alternativ kannst Du Dir im Netzwerk-Tab der Entwicklerwerkzeuge auch die Antwort des Ajax-Aufrufs anschauen.

      Weiß ich nicht, wie geht.

      Ich bin nämlich nicht überzeugt, dass da das drin steht, was Du meinst. Ich nehme an, dass da eine PHP Notice drin steht, dass irgendwas nicht passt, und die ist natürlich kein valides JSON. Wenn ich im Firefox einen JSON.parse Aufruf mache und ihm JSON Müll übergebe, bekomme ich genau deine Meldung.

      Wäre eine plausible Lösung. Würde aber dann tatsächlich bedeuten, dass nicht beim Browser ankommt, was ich vermute. Ich sagte ja auch, "es scheint dort anzukommen".

      Punkt 3: Deine zurückgegebenen Daten. Warum hüllst Du das Objekt in ein Array ein? Das ist nicht nötig. Du musst das Array dann am Client nur unnötig auspacken - ich würde annehmen, das hast Du in deinem geposteten Code herausgenommen. Denn dies hier kann nicht funktionieren:

              var einzeldata = JSON.parse( data );
              if ( datenset.typ === 'success' ) {
      

      Woher käme der Wert in datenset, wenn Du dort nicht vorher einzeldata[0] abgelegt hättest?!

      Hast recht. Ich hatte mit den ganzen heraus gelöschten alerts auch Wesentliches nicht gepostet, sorry.

      var einzeldata = JSON.parse( data );
      for ( var i = 0; i < einzeldata.length; i++ ) {
      var datenset = einzeldata[ i ];
      }
      

      Punkt 3: Content-Type. Beim Zurückgeben eines JSON-Strings ist es empfehlenswert, zu Beginn des Scripts diese Funktion aufzurufen, um dem Browser mitzuteilen, dass dies kein HTML ist.

      header('Content-Type: application/json; charset=utf-8');
      

      An welcher Stelle mache ich das?

      Punkt 4: Abfrage von "session vorbei" ohne Polling: Geht nicht. Du hast PHP-seitig keine Wächterfunktion vorliegen, die beim Verfall einer Session getriggert wird. Ich weiß auch gar nicht, wie man PHP sagen sollte, dass eine Session eine maximale Lebensdauer hat. Man kann dem Session-GarbageCollector eine Zeit mitgeben, nach der es ihm erlaubt ist, alte Sessions abzuräumen. Der läuft aber nicht deterministisch, sondern startet zufällig mit einer gewissen Wahrscheinlichkeit. Wann genau das passiert, habe ich gerade im PHP Handbuch nicht gefunden, und vor 16 Jahren schrieb ein gewisser Matt dies.

      D.h. Du kannst dem Client nur die Timeout-Zeit deiner Sessions mitteilen und der Client kann dann mittels setTimeout einen eigenen Timer starten. Den muss er natürlich bei jedem Serverkontakt, der die Session aktualisiert, zurücksetzen (setTimeout gibt ein Löschticket zurück, mit dem Du clearTimeout aufrufen kannst um den Timer zu löschen).

      Nein, das mache ich ganz anders.
      Ich habe in den Konfigdatenm eine $maxtime gesetzt.
      Zudem wird für jeden User eine Session generiert, die Session-ID in eine db eingetragen und bei jedem Seitenaufruf der Datetime-Stempel aktualisiert. So brauche ich jetzt nur in php zu schauen, ob now() für diesen User größer ist als sein Stempel + $maxtime.

      Sven

    2. Hallo Rolf,

      Punkt 2: Der Syntax-Error. Der muss von JavaScript kommen, PHP wirft keinen Syntax-Error beim Parsen von kaputtem JSON. Debugging mit alerts ist - mit Verlaub - Kacke. Verwende console.log und mach die Entwicklerwerkzeuge vom Browser auf, um die Konsole zu sehen. Und dann gib vor dem JSON.parse den Inhalt von data aus. Alternativ kannst Du Dir im Netzwerk-Tab der Entwicklerwerkzeuge auch die Antwort des Ajax-Aufrufs anschauen.

      Es kommt keine Antwort mehr, ich erhalte sofort nachdem ich über php-admin die Spalte des letzten Eintrags so abändere, dass der letzte Eintrag + $maxtime kleiner als now() ist, auf das releod-script einen http-Status 302 und folglich keine Antwort mehr.

      Sven

      1. Hallo Sven,

        woher kommt ein 302-Status? Den müsstet Du doch setzen. Der Server dürfte den nicht abhängig von der Existenz einer Session erzeugen und PHP unter der Haube auch nicht.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Kann mir einer erklären, was ein Fehler 302 genau ist?

          1. Hallo localhorst2,

            Fehler? Was für ein Fehler?

            HTTP Statuscodes

            Rolf

            --
            sumpsi - posui - obstruxi
        2. @@Rolf B

          woher kommt ein 302-Status? Den müsstet Du doch setzen.

          302 ist doch der, den man nicht mehr setzen sollte‽ [Wikipedia]

          🖖 Живіть довго і процвітайте

          --
          „Im Vergleich mit Elon Musk bei Twitter ist ein Elefant im Porzellanladen eine Ballerina.“
          — @Grantscheam auf Twitter
        3. Hallo Sven,

          woher kommt ein 302-Status? Den müsstet Du doch setzen. Der Server dürfte den nicht abhängig von der Existenz einer Session erzeugen und PHP unter der Haube auch nicht.

          Nein, ich setze den nicht.
          Es muss daran liegen, dass die Session beendet wird und somit eines der Scripte, die beteiligt sind, auf die Login-Seite umleitet.
          Aber welches?
          Das reloadscript habe ich eigens deshalb ausgenommen, damit das nicht passiert.
          Das Script, welches den Ajax abfeuert kann es doch auch nicht sein, oder? Denn das liegt ja schon auf dem Client und bleibt somit unverändert.

          Bin grad ratlos.

          Sven

          1. Hallo Sven,

            okay, ich kenne natürlich dein Gesamtkunstwerk nicht. Aber wenn der 302 irgendwo gesetzt wird, dass muss das von reload.php ausgehen - es sei denn, du hast PHP so konfiguriert, dass für jeden Request erstmal ein Vorab-Code ausgeführt wird. Das erreicht man mit der Option… Optiooon… Es gibt also diese Option, die…

            Das hab ich doch irgendwann beim Handbuchschmökern mal (geht murmelnd ab…)

            eine kleine Ewigkeit später

            Wo war ich? Ach ja.

            Das erreicht man mit der Option auto_prepend_file. Wenn dieser Vorab-Code ebenfalls die Session prüft und eigenmächtig aktiv wird, dann musst Du ihn so aufschlauen, dass er bei$_SERVER['SCRIPT_NAME'] == '/reload.php' nicht aktiv wird.


            Ich habe eine Weile gegoogelt, bis mir auto_prepend_file wieder einfiel. Jetzt, wo ich die Antwort fertig habe, dachte ich: teste doch mal den Besserwisser dieses Planeten! Nein nein, nicht Sebastian Klussmann.

            Rolf: Hi, do you know about php

            ChatGPT: Yes, I do. bla bla bla

            Rolf: drückt ESC
            Rolf: do you know specifics about php ini settins?

            ChatGPT: ist von settins völlig unbeeindruckt
            ChatGPT: Yes, I can help you with that. beginnt den nächsten Monolog

            Rolf: drückt ESC
            Rolf: I want to run some PHP code before my real program starts. can i configure that?

            ChatGPT: Yes, you can configure PHP to run some code before your main program starts by using the auto_prepend_file directive in your php.ini file. This directive specifies the name of a PHP script that will be automatically included before the main script runs.

            Here's how to use it:

            1. Open your php.ini file in a text editor.
            2. Search for the auto_prepend_file

            Rolf: 😲 - irgendwie ist meine Kinnlade vorher auf die ESC Taste gefallen

            ChatGPT: I apologize, it looks like my previous response was incomplete. Let me finish it:

            If the auto_prepend_file directive is not already present in your php.ini file, add the following line: auto_prepend_file = "/path/to/your/prepend/script.php"

            Replace "/path/to/your/prepend/script.php" with the actual path to your PHP script that you want to run before the main program.

            Save the php.ini file and restart your web server for the changes to take effect.

            Now, every time you run a PHP script, the code in your auto_prepend_file script will be executed before the main program starts. You can use this feature to set up environment variables, load libraries, or perform any other initialization tasks that your main program requires.

            Ihr solltet demnächst ChatGPT fragen und nicht das Forum… Das ist wirklich jemand mit überragendem und vom Himmel geworfenen Wissen.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Guten Morgen!

              Ich habe eine Weile gegoogelt, bis mir auto_prepend_file wieder einfiel.

              Jetzt, wo ich die Antwort fertig habe, dachte ich: teste doch mal den Besserwisser dieses Planeten! Nein nein, nicht Sebastian Klussmann.

              Rolf: Hi, do you know about php

              ChatGPT: Yes, I do. bla bla bla

              Now, every time you run a PHP script, the code in your auto_prepend_file script will be executed before the main program starts. You can use this feature to set up environment variables, load libraries, or perform any other initialization tasks that your main program requires.

              Ihr solltet demnächst ChatGPT fragen und nicht das Forum… Das ist wirklich jemand mit überragendem und vom Himmel geworfenen Wissen.

              Rolf

              Ja, habe vor einiger Zeit dies überflogen:

              Coding Won’t Exist In 5 Years. This Is Why (javascript.plainenglish.io)

              Problem ist wohl aber weiterhin eine gute Fragestellung zu entwerfen, Suchbegriffe zu formulieren und dann entstehende unbeabsichtigte Fehler (aus der fehlerhaften Aufgabenstellung heraus) zu analysieren.

              Das Thema wäre was für unseren Blog!

              Herzliche Grüße

              Matthias Scharwies

              --
              Ich habe heute rausgefunden, dass in das Pizzafach meines Rucksacks auch ein Laptop passt!
              1. Hallo Matthias,

                das Problem ist vor allem, dass diese Bots eigentlich dümmer als Papageien sind. Ein Papagei weiss wenigstens gelegentlich, was die Laute bedeuten die er von sich gibt.

                Bei ChatGPT ist das nach allem, was ich weiß, nicht der Fall. Umso erstaunter war ich über die Antwort.

                Rolf

                --
                sumpsi - posui - obstruxi