Werkstudent1: json_encode für komplexe objekte

Hi,

ich arbeite mit an einem Wordpress-Projekt und soll mit natives PHP, AJAX und HTML ein Suchfeld, implementieren, dass relevante Posts ausgibt.

Serverseitig möchte ich ich dann ein json mit dem Format

{ 
  "0":{ "title": some_title, "content":some_content},
  "1":{ "title": some_title, "content":some_content},
  "2":{ "title": some_title, "content":some_content},
  "3":{ "title": some_title, "content":some_content},
  ...
  "n":{ "title": some_title, "content":some_content},
}

zurückschicken.

some_content ist ein wp-post, dass html tags und sonstiges zeug enthalten kann.

Wenn ich json_encde auf ganz simple Beispiele Verwende, funktioniert das, aber auf meine content angewandt, bekomme ich kein valides oder zumindest kein schönes json zurück

        $arrays= array();
        $arr1= array( "bla1" => 1, "bla2" => 2, "bla3" => 3, "bla4" => 4, );
        $arr2= array( "bla1" => 1, "bla2" => 2, "bla3" => 3, "bla4" => 4, );
        array_push($arrays, $arr1 );
        array_push( $arrays, $arr2);
        echo json_encode($arrays);

Ausgabe:

[{"bla1":1,"bla2":2,"bla3":3,"bla4":4},{"bla1":1,"bla2":2,"bla3":3,"bla4":4}] 

Mein json mit dem content aus der Datenbank sieht so aus:

[
	"{\"title\":\"Startseite\",\"content\":\"..\"}",
	false,
	"{\"title\":\"Downloads\",\"content\":\"..\"}",
	"{\"title\":\"Kontakt\",\"content\":\"..\"}",
	"{\"title\":\"Impressum\",\"content\":\"..\"}",
	"{\"title\":\"Datenschutz\",\"content\":\"..\"}",
	false,
	false,
	false,
	false,
	"{\"title\":\"Graues Murmeltier\",\"content\":\"Man unterscheidet drei Unterarten:ul M. b. baibacinali M. b. centralisli M. b. kastschenkoiliul..\"}",
	false
] 


Ich bekomme da an mehrere stellen false zurück. Das passiert erst bei der umwandlung in json. zum anderen ist das kein Valides json.

Danke und Viele Grüße Werkstudent1

  1. Tach!

    Serverseitig möchte ich ich dann ein json mit dem Format

    Dafür hast du zwei Möglichkeiten. Zum einen kannst du json_encode() mit ein paar Options steuern, wie du die Ausgabe gern hättest. Wenn da keine passende Ausgabe entsteht, ist Möglichkeit Nummer 2, selbst die Ausgabe zu erzeugen.

    { 
      "0":{ "title": some_title, "content":some_content},
      "1":{ "title": some_title, "content":some_content},
      "2":{ "title": some_title, "content":some_content},
      "3":{ "title": some_title, "content":some_content},
      ...
      "n":{ "title": some_title, "content":some_content},
    }
    
    

    Warum möchtest du ein Array als Objekt nachbilden?

    dedlfix.

    1. Hi,

      Ich möchte einen json an ajax schicken. Mit den Optionen habe ich auch etwas gebastelt, aber irgendwas sinnvolles kam da auch nicht bei raus. Ich habe mir jetzt mit Strings mein eigenes json gebaut. sieht jetzt deutlich besser aus. Danke.

      Gibt es eigentlich eine elegantere Variante ohne eine Million str_replace die html tags eines textes wegzukriegen?

        
              $json_string="{";
              $json_index = 0;
              if (mysqli_num_rows($result) > 0) {
                  // output data of each row
                  while($row = mysqli_fetch_assoc($result)) {
                      $content= $row["post_content"];
                      $content= str_replace("<img", "", $content );
                      $content= str_replace("/>", "", $content );
      
                      $content= str_replace("<li", "", $content );
                      $content= str_replace("<h1>", "", $content );
                      $content= str_replace("<h2>", "", $content );
                      $content= str_replace("</h2>", "", $content );
                      $content= str_replace("<blockquote>", "", $content );
                      $content= str_replace("</blockquote>", "", $content );
                      $content= str_replace("\n", "", $content );
                      $content= str_replace("\r", "", $content );
                      $content= str_replace("\t", "", $content );
                      $content= str_replace('"', "'", $content );
                      $content= str_replace(">", "", $content );
                      $content= str_replace("<", "", $content );
                      $content= str_replace("/", "", $content );
      
                      $arr = explode(".", $content);
                      $short="";
                      $length = sizeof($arr);
                      for ($i = 0; $i <= $length; $i++) {
                          if(strlen($short) < 300){
                              $short= $short . $arr[$i] . ".";
                          }
                      }
                      // Ab hier geht etwas bei der umwandlung in json schief
                      $json_string = $json_string . '"'. $json_index .'":{ "title":"' . $row["post_title"] .'", "content":"' . $short .'"},';
                      $json_index++;
                  }
              } else {
                  echo "0 results";
              }
      
              $json_string = substr($json_string, 0, -1);
              $json_string = $json_string . "}";
              echo $json_string;
      
              mysqli_close($conn);
              ?>
      

      Beste Grüßen

      Werkstudent1

      1. Tach!

        Ich möchte einen json an ajax schicken. Mit den Optionen habe ich auch etwas gebastelt, aber irgendwas sinnvolles kam da auch nicht bei raus. Ich habe mir jetzt mit Strings mein eigenes json gebaut. sieht jetzt deutlich besser aus. Danke.

        Bleibt trotzdem die Frage, warum du ein Array als Objekt und nicht als richtiges Array darstellen möchtest.

        Gibt es eigentlich eine elegantere Variante ohne eine Million str_replace die html tags eines textes wegzukriegen?

        strip_tags(), aber das entfernt alles, was irgendwie nach Tag aussieht. Es sei denn, du übergibst ihm eine Liste der zu beachtenden Tags.

                    // Ab hier geht etwas bei der umwandlung in json schief
                    $json_string = $json_string . '"'. $json_index .'":{ "title":"' . $row["post_title"] .'", "content":"' . $short .'"},';
        

        Der Kommentar hat recht, denn in dem Code beachtest du nicht, dass Anführungszeichen in den Werten (im besten Fall nur) die JSON-Syntax kaputtmachen. Der Kontextwechsel und die Maskierregeln müssen immer beachtet werden, wenn Werte irgendwo eingefügt werden.

        dedlfix.

        1. Hi,

          Bleibt trotzdem die Frage, warum du ein Array als Objekt und nicht als richtiges Array darstellen möchtest.

          Meine aufgabe lautet ein suchfeld zu bauen, wo man ein keyword reinschreiben kann. Alle Artikel, wo das Keyword vorkommen sollen dann auf der Seite, wo ich gesucht habe angezeigt werden. Meine idee war das keyword per ajax an den server zu schicken, ein json vom server zurückzubekommen und dann bei erfolg das json zu verarbeiten.

          Wenn es einen besseren weg gibt, bin ich ganz Ohr :)

          Der Kontextwechsel und die Maskierregeln müssen immer beachtet werden, wenn Werte irgendwo eingefügt werden.

          Ich habe erstmal ganz brachial alle " und ' entfernt und alle HTML-Tags entfernt. Müsste vorerst reichen. Wenn die Aufgabe zum größten Teil gelöst ist, kann ich später schauen, wie ich das eleganter löse.

                  $json_string="{";
                  $json_index = 0;
                  if (mysqli_num_rows($result) > 0) {
                      // output data of each row
                      while($row = mysqli_fetch_assoc($result)) {
                          $content= $row["post_content"];
                          $title= $row["post_title"];
          
                          //HTML TAGS ENFERNEN und Context maskieren
                          $title= strip_tags($title);
                          $title= str_replace("'", "", $title );
                          $title= str_replace('"', '', $title );
          
                          $content= strip_tags($content);
                          $content= str_replace("'", "", $content );
                          $content= str_replace('"', '', $content );
                          
                          //Content kuerzen
                          $arr = explode(".", $content);
                          $short="";
                          $length = sizeof($arr);
                          for ($i = 0; $i <= $length; $i++) {
                              if(strlen($short) < 300){
                                  $short= $short . $arr[$i] . ".";
                              }
                          }
                          $short= $short .  "..";
                          
                          // json bauen
                          $json_string = $json_string . '"'. $json_index .'":{ "title":"' . $title .'", "content":"' . $short .'"},';
                          $json_index++;
                      }
                  } else {
                      echo "0 results";
                  }
          
                  $json_string = substr($json_string, 0, -1);
                  $json_string = $json_string . "}";
                  echo $json_string;
          
          

          Gruß

          Werkstudent1

          1. Tach!

            Bleibt trotzdem die Frage, warum du ein Array als Objekt und nicht als richtiges Array darstellen möchtest.

            [ein Irr-Elefant]

            Das meinte ich nicht, sondern warum du ein Objekt mit numerischen Eigenschaftsnamen

            { 
              "0":{ "title": some_title, "content":some_content},
              "1":{ "title": some_title, "content":some_content},
              "2":{ "title": some_title, "content":some_content},
              "3":{ "title": some_title, "content":some_content},
              ...
              "n":{ "title": some_title, "content":some_content},
            }
            

            und nicht ein Array nimmst, das von Haus aus numerische Indexwerte hat?

            [ 
              { "title": some_title, "content":some_content},
              { "title": some_title, "content":some_content},
              { "title": some_title, "content":some_content},
              { "title": some_title, "content":some_content},
              ...
              { "title": some_title, "content":some_content}
            ]
            

            dedlfix.

        2. Hallo,

          Bleibt trotzdem die Frage, warum du ein Array als Objekt und nicht als richtiges Array darstellen möchtest.

          Vielleicht, weil er es nicht besser weiß?

          Werkstudent, ein Array von Objekten lässt sich in JSON auch darstellen, ohne die Array-Indexe vorneweg zu stellen. Das hat Du in deinem eingangs gezeigten bla bla bla Beispiel schon selbst demonstriert.

          Wenn Du UNBEDINGT die von Dir gezeigte Objektstruktur mit Indexen als Schlüssel haben willst, dann hast Du in PHP ein Problem, weil PHP numerisch aussehende Schlüssel als Indexe behandelt, d.h. selbst wenn Du in deiner bla bla bla Demo schreiben würdest:

          //php
          $arrays= array( "0" => $arr1, "1" => $arr2 );
          

          dann würde json_encode immer noch eine Array-Struktur erzeugen, keine Objektstruktur.

          Aber wie gesagt - warum überhaupt eine Objektstruktur erzwingen? Du kannst im Javascript das von PHP encodete Array genauso gut verarbeiten wie ein Objekt

          // Javascript
          a = [ { bla: 10 }, { bla: 12 }, { bla: 14 } ];
          console.log(a[1].bla);      // -> 12
          console.log(a["1"].bla);    // -> ebenfalls 12
          

          Zu deinem kaputten json_encode Ergebnis vom Anfang: Es sieht so aus, als würdest Du jede Zeile einzeln encoden, das Ergebnis in ein Array stellen und dann das Array nochmal encoden. Das KANN man machen, aber weder muss noch sollte man es tun. Die "false" Einträge deuten darauf hin, dass dein innerer json_encode auf einen Fehler gelaufen ist. Welcher das ist, lässt sich so nicht sagen; ich weiß ja auch nicht was Du da sonst noch drumherum gemacht hast.

          Aber wie wär's hiermit:

          $zeilen = ARRAY();       // oder: $zeilen = [];
          while($row = mysqli_fetch_assoc($result)) {
             $zeilen[] = ARRAY("titel" => htmlspecialchars($row["post_title"]), 
                               "content" => htmlspecialchars(getShortText($row["post_content"])));
          }
          $json_string = json_encode($zeilen);
          

          $zeilen[] = blablabla ist ein kompakter array_push.

          Die Verwendung von json_encode nimmt Dir die Arbeit ab, deine Inhalte JSON-konform zu maskieren. Und htmlspecialchars nimmt Dir die Arbeit ab, Sonderzeichen zu maskieren, die Dir ggf. das HTML-Layout zerreißen.

          Das Ermitteln des Short-Text aus dem post_content lagerst Du sinnvollerweise in eine Funktion aus, dann hast Du lesbareren Code, kannst sie separat testen und vielleicht sogar wiederverwenden. Gefällt dem Prof bestimmt :)

          Bekommst Du aus dem json_encode ein false heraus, müsstest Du mal zu Beginn des PHP Scripts error_reporting(E_ALL) aufrufen und die Ajax-URL direkt in die Browser-Adresszeile eingeben, dann müsstest Du entstehende Fehler zu sehen bekommen. Du kannst auch die Funktion json_last_error() benutzen, um im false-Fall weitere Informationen zu erhalten. Vermutlich ist es ein encoding-Problem; json_encode erwartet UTF-8 codierte Strings. Wenn Du in deinem Script nicht mit UTF-Strings arbeitest (sprich: deine DB-Verbindung latin-1 codierte Strings liefert), dann kannst Du mit utf8_encode() nachhelfen.

          Rolf

          --
          sumpsi - posui - clusi
          1. Hi,

            ich verstehe. Den Array müsste ich am Ende in jedem Fall bevor ich es an den Client schicke in json umwandeln. Sehe ich das richig?

            Andere Frage: Ich möchte den Request mit ajax verarbeiten. den Input schicke ich an results.php und den json möchte ich zurück haben. Wie mache ich das?

                <body>
                    <form action="./results.php">
                        <label for="search">Search</label>
                        <input type="text" id="q" name="q" />
                        <input type="submit">
                    </form>
            
                    <script>
                        jQuery('document').ready(function () {
                            //ajax wird wird zu testzwecken nicht aufgerufen. form statt #form, dann wird die funktion aufgerufen.
                            jQuery('form').submit(function(event){
                                event.preventDefault();
                                var data = $(this).serialize() + "&" + $.param(data);
                                $.ajax({
                                    type: "GET",
                                    dataType: "json",
                                    url: "./results.php", //Relative or absolute path to response.php file
                                    data: data,
                                    success: function(data) {
                                       
                                    }
                                });
                            });
                        });
                    </script>
                </body>
            

            gruß

            Werkstudent

            1. Hallo @Werkstudent1,

              ich verstehe. Den Array müsste ich am Ende in jedem Fall bevor ich es an den Client schicke in json umwandeln. Sehe ich das richig?

              Ja, und nur genau einmal.

              Andere Frage: Ich möchte den Request mit ajax verarbeiten. den Input schicke ich an results.php und den json möchte ich zurück haben. Wie mache ich das?

              Fast genau so wie angegeben – oder an welcher Stelle hängt es?

                  <body>
                      <form action="./results.php">
                          <label for="search">Search</label>
                          <input type="text" id="q" name="q" />
                          <input type="submit">
                      </form>
              

              Das for des label Elements muss auf ein Eingabeelement mit gleicher ID zeigen. Bei dir gibt es kein Element mit der ID search. Mein Vorschlag für dein form:

              <form action="results.php">
                  <label>Search: <input type="search" name="q"></label>
                  <button type="submit">Submit</button>
              </form>
              

              Weiter:

              jQuery('document').ready(function () {
                  //ajax wird wird zu testzwecken nicht aufgerufen. form statt #form, dann wird die funktion aufgerufen.
                  jQuery('form').submit(function(event){
              

              An welche Formulare hängt sich dieses submit eigentlich alles?

                      event.preventDefault();
                      var data = $(this).serialize() + "&" + $.param(data);
                      $.ajax({
                          type: "GET",
                          dataType: "json",
                          url: "./results.php", //Relative or absolute path to response.php file
                          data: data,
                          success: function(data) {
              

              In dieser Funktion hier hast du das Ergebnis von results.php in der Variablen data und kannst damit arbeiten.

                          }
                      });
                  });
              });
              
              1. Hab das soweit hingekriegt.

                    <body>
                        <form id="form" action="./results.php">
                            <label for="q">Search</label>
                            <input type="text" id="q" name="q" />
                            <input type="submit">
                        </form>
                
                
                        <div class="container" id="container"></div>
                
                        <script>
                            jQuery('document').ready(function () {
                                jQuery('#form').submit(function(event){
                                    event.preventDefault();
                                    console.log("works");
                
                                    $.ajax({
                
                                        type: "GET",
                                        contentType: "application/json",
                                        url: "./results.php",
                                        data: "{}",
                                        dataType: "json",
                                        success: function (data) {
                                            for(var i=0; i<data.length; i++){
                                                $("#container").append("<div><h2>"+data[i].title+"</h2><p>"+data[i].content+"</p></div>");
                                            }
                                        },
                                        error: function (err) {
                
                                            console.log(err);
                                        }
                                    });
                
                                });
                            });
                        </script>
                    </body>
                

                jetzt habe ich allerdings das Problem, dass anscheinend ein leeres string über ajax geschickt wird, weil, ich bei jeder Suchanfrage alle artikel kriege. Ohne ajax bekomme ich nur die Artikel die ich möchte.

                Gruß

                Werkstudent1

                1. Hallo @Werkstudent1,

                  jetzt habe ich allerdings das Problem, dass anscheinend ein leeres string über ajax geschickt wird, weil, ich bei jeder Suchanfrage alle artikel kriege.

                  dann lass dir doch einmal data direkt anzeigen.

                  Viele Grüße
                  Robert

                  1. Hi, danke. Es läuft. Habe mit dem ajax keine daten mitgeschickt. data= $(this).serialize hat die lage gerettet.

                    Habe ursprünglich nur arrays verwendet und es hat nicht funktioniert. Deshalb habe ich das mit objekten versucht. Hätte einfach utf8_encode machen sollen.

                    Das for des label Elements muss auf ein Eingabeelement mit gleicher ID zeigen. Bei dir gibt es kein Element mit der ID search.

                    Das kommt von schnelles einseitiges refactorn :)

                    Danke für die Hilfen. Ich mach jetzt Feierabend :)

                2. Hi,

                  type: "GET", data: "{}",

                  einen Messagebody (data) mit Request-Method GET senden zu wollen passt ja auch nicht zusammen. Das ist zwar möglich, aber nicht üblich und normalerweise sollte das eine Lib gar nicht zulassen.

                  MfG

                  1. Hallo pl,

                    ApiFuzius sagt: Es gehe der Weg der Daten über den Query-Parameter, wenn AJAX einen GET auszuführen im Begriffe ist.

                    Rolf

                    --
                    sumpsi - posui - clusi
                    1. hi

                      ApiFuzius sagt: Es gehe der Weg der Daten über den Query-Parameter, wenn AJAX einen GET auszuführen im Begriffe ist.

                      Die fetchAPI sieht das nicht so verbissen. Da kannst Du Deine Requestmethoden nennen wie Du willst. fetch verweigert zwar auch das Senden eines body mit GET aber sobald Du die Methode GED nennst gehts 😉

                      1. Hallo pl,

                        na, warum tut fetch das wohl?

                        Und ob Du mit Ursula K. Le Guins Earthsea-Zauberer besser dran bist? Webserver, die einen body bei GET verweigern, könnten auch unbekannte Verben ignorieren.

                        Rolf

                        --
                        sumpsi - posui - clusi
                        1. Moin,

                          na, warum tut fetch das wohl?

                          Und ob Du mit Ursula K. Le Guins Earthsea-Zauberer besser dran bist? Webserver, die einen body bei GET verweigern, könnten auch unbekannte Verben ignorieren.

                          Warum sollte ma sich da auch einschränken wollen? Und was soll eine Abhängigkeit von der Requestmethode bringen? Der Glaube an den POSTman ist ein Aberglaube 😉

                          MfG 😉

              2. Hallo Robert,

                jQuery('form').submit(function(event){
                

                An welche Formulare hängt sich dieses submit eigentlich alles?

                Genauso viele, wie Chuck Norris Liegestütze schafft: ALLE.

                😂

                Rolf

                --
                sumpsi - posui - clusi
                1. Hallo @Rolf B,

                  jQuery('form').submit(function(event){
                  

                  An welche Formulare hängt sich dieses submit eigentlich alles?

                  Genauso viele, wie Chuck Norris Liegestütze schafft: ALLE.

                  Und wahrscheinlich ein einer Endlosschleife – die zweimal durchlaufen wird.

                  Viele Grüße
                  Robert