Tim: Inhalt von While Schleife in Email ausgeben

Hallo zusammen,

ich verzweifel gerade, da ich mich neu in PHP einarbeite (quasi learning by doing).
Ich würde gerne den Inhalt einer While Schleife als Mail versenden.
So weit bin ich: der richtige Inhalt wird bei Aufruf des Scriptes ausgegeben. In der Mail, die verschickt wird, wird allerdings nur das letzte Ergebnis eingespielt.
Kann mir jemand helfen, wo der Fehler liegt?
Danke und Grüße
Tim

  
  
<?php  
  
$sql = "SELECT * FROM wp_fsq_data  
         WHERE date BETWEEN '" . date('Y-m-d', strtotime('-14 days')) . "'  
         AND '" . date('Y-m-d', strtotime('-10 days')) . "'";  
$result = $conn->query($sql);  
  
if ($result->num_rows > 0) {  
     // output data of each row  
     while($row = $result->fetch_assoc()) {  
        echo "<br> Letzter Besuchsbericht: ". date('d.m.Y', strtotime($row["date"])). " - Name: ". $row["f_name"]. " " . $row["l_name"] . "<br>";  
  
		$message = $row["f_name"] . ' '.$row["l_name"].' hat seit dem '.date('d.m.Y', strtotime($row["date"])).' keinen Besuchsbericht mehr abgegeben';  
	}  
		$empfaenger = "xxx@xxx.de";  
		$betreff = "xxx";  
		$headers = "From: xxx <xxx@xxx.de>";  
		mail($empfaenger, $betreff, $message, $headers);  
} else {  
     echo "0 results";  
  
}  
$conn->close();  
?>  

  1. Tach!

    ich verzweifel gerade, da ich mich neu in PHP einarbeite (quasi learning by doing).

    Verzweifeln ist keine geeignete Strategie zur Fehlerfindung. Kontrollausgaben sind eindeutig besser.

    while($row = $result->fetch_assoc()) {

      $message = $row["f\_name"] . ' '.$row["l\_name"].' hat seit dem '.date('d.m.Y', strtotime($row["date"])).' keinen Besuchsbericht mehr abgegeben';  
    

    }

    Zum Beispiel könntest du dir mal den Inhalt von $message nach jedem Schleifendurchlauf anschauen, um zu kontrollieren, ob der Text auch wirklich an $message angehängt wird. Das ist doch das was du eigentlich willst, oder? Vielleicht stellst du ja dabei fest, dass das nicht der Fall ist und der Fehler irgendwo da zu suchen ist.

    Für Kontrollausgaben jedenfalls eignet sich meist var_dump() am besten. Das hat gegenüber einem schnöden echo den Vorteil, dass es bei jeder Art von Wert etwas ausgibt.

    dedlfix.

    1. Zum Beispiel könntest du dir mal den Inhalt von $message nach jedem Schleifendurchlauf anschauen, um zu kontrollieren, ob der Text auch wirklich an $message angehängt wird. Das ist doch das was du eigentlich willst, oder? Vielleicht stellst du ja dabei fest, dass das nicht der Fall ist und der Fehler irgendwo da zu suchen ist.

      Für Kontrollausgaben jedenfalls eignet sich meist var_dump() am besten. Das hat gegenüber einem schnöden echo den Vorteil, dass es bei jeder Art von Wert etwas ausgibt.

      Hi dedlfix,

      danke schön.
      Wenn ich var_dump($message); mache, bekomme ich ebenfalls die richtige Ausgabe:

      string(76) "XY Z hat seit dem 04.02.2015 keinen Besuchsbericht mehr abgegeben"
      string(70) "Test User hat seit dem 04.02.2015 keinen Besuchsbericht mehr abgegeben"

      Nur in der Mail kommts nicht an.
      Wenn ich allerdings mail() in die while-Schleife hänge, bekomme ich für jede gefundene Zeile eine einzelne Email :/

      1. Moin,

        Wenn ich var_dump($message); mache, bekomme ich ebenfalls die richtige Ausgabe:

        richtig? Nein, ich glaube nicht.

        string(76) "XY Z hat seit dem 04.02.2015 keinen Besuchsbericht mehr abgegeben"
        string(70) "Test User hat seit dem 04.02.2015 keinen Besuchsbericht mehr abgegeben"

        Du bekommst in jedem Schleifendurchlauf *eine* Meldung. Aber was du vermutlich möchtest, ist doch wohl ein systematisches Aneinanderhängen der erzeugten Meldungen, nach dem Prinzip von "Ich packe meinen Koffer und nehme mit".

        Also musst du in jedem Schleifendurchlauf den neuen Teilstring an den bereits bestehenden _anhängen_ (der Fachbegriff wäre Stringverkettung). Du weist dagegen einfach nur zu und überschreibst so in jedem Durchlauf die Meldung aus dem vorherigen Durchlauf.

        Nur in der Mail kommts nicht an.

        Doch: Der zuletzt zugewiesene Wert.

        Ciao,
         Martin

        --
        If you believe in telekinesis, raise my hand.
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. Du bekommst in jedem Schleifendurchlauf *eine* Meldung. Aber was du vermutlich möchtest, ist doch wohl ein systematisches Aneinanderhängen der erzeugten Meldungen, nach dem Prinzip von "Ich packe meinen Koffer und nehme mit".

          Genau, das ist mein Ziel

          Also musst du in jedem Schleifendurchlauf den neuen Teilstring an den bereits bestehenden _anhängen_ (der Fachbegriff wäre Stringverkettung). Du weist dagegen einfach nur zu und überschreibst so in jedem Durchlauf die Meldung aus dem vorherigen Durchlauf.

          Ok, da verstehe ich leider gerade nur Bahnhof. Kannst du mir hier weiterhelfen bitte?
          Danke und Grüße

          1. Lieber Tim,

            Also musst du in jedem Schleifendurchlauf den neuen Teilstring an den bereits bestehenden _anhängen_

            das hast Du nicht verstanden?

            Du weist dagegen einfach nur zu und überschreibst so in jedem Durchlauf die Meldung aus dem vorherigen Durchlauf.

            Und das auch nicht? Also ein Beispiel:

            $str = '';  
            $i = 3;  
              
            while ($i > 0) {  
                $str = "i ist $i!";  
                $i--; // macht $i um eins kleiner  
            }  
              
            echo $str; // "i ist 1!"
            

            Du siehst im Beispiel, dass in der Schleife der Inhalt der String-Variablen immer wieder neu definiert (oder in Martins Worten "übschrieben") wird. Anstatt alle "Ausgaben" zu haben, steht nur die letzte "Ausgabe" im String.

            Die Lösung ist hier der .= Operator, der Strings miteinander verkettet (Martin schrieb doch "Stringverkettung"!):

            $str = '';  
            $i = 3;  
              
            while ($i > 0) {  
                $str .= "i ist $i!"; // man beachte den .= Operator!  
                $i--;  
            }  
              
            echo $str; // "i ist 3!i ist 2!i ist 1!"
            

            Klarer geworden?

            Liebe Grüße,

            Felix Riesterer.

            --
            "Wäre die EU ein Staat, der die Aufnahme in die EU beantragen würde, müsste der Antrag zurückgewiesen werden - aus Mangel an demokratischer Substanz." (Martin Schulz, Präsident des EU-Parlamentes)
            1. hi Felix,

              Lieber Tim,

              Also musst du in jedem Schleifendurchlauf den neuen Teilstring an den bereits bestehenden _anhängen_

              das hast Du nicht verstanden?

              Du weist dagegen einfach nur zu und überschreibst so in jedem Durchlauf die Meldung aus dem vorherigen Durchlauf.

              Und das auch nicht? Also ein Beispiel:

              $str = '';

              $i = 3;

              while ($i > 0) {
                  $str = "i ist $i!";
                  $i--; // macht $i um eins kleiner
              }

              echo $str; // "i ist 1!"

              
              >   
              > Du siehst im Beispiel, dass in der Schleife der Inhalt der String-Variablen immer wieder neu definiert (oder in Martins Worten "übschrieben") wird. Anstatt alle "Ausgaben" zu haben, steht nur die letzte "Ausgabe" im String.  
              >   
              > Die Lösung ist hier der .= Operator, der Strings miteinander verkettet (Martin schrieb doch "Stringverkettung"!):  
              >   
              >   
              > ~~~php
              
              $str = '';  
              
              > $i = 3;  
              >   
              > while ($i > 0) {  
              >     $str .= "i ist $i!"; // man beachte den .= Operator!  
              >     $i--;  
              > }  
              >   
              > echo $str; // "i ist 3!i ist 2!i ist 1!"
              
              

              Klarer geworden?

              oder

                
              ob_start();  
              while($row = $result->fetch_assoc()) {  
                      echo "<br> Letzter Besuchsbericht: ". date('d.m.Y', strtotime($row["date"])). " - Name: ". $row["f_name"]. " " . $row["l_name"] . "<br>";  
              }  
              $message = ob_get_clean();  
              
              

              mfg

              tami

              1. Tach!

                [Stringverkettung]
                oder
                [Ausgabepufferung]

                Nein, das ist keine gute Idee. Der Ausgabepuffer ist global für das gesamte Programm zuständig, und mehrere werden übereinandergestapelt. Wenn man ihn für einen String-Puffer einzusetzt, muss man seine Nebenwirkungen beachten. Man kann immer nur den obersten verwenden und nicht gezielt einen beliebigen. Eine Variable hingegen wird nicht von anderen Programmteilen beeinflusst, solange sie nicht direkt angesprochen wird. So eine Lösung klappt nur mit einem einzelnen Text. Möchte man mehrere Texte gleichzeitig erstellen, hat man damit ein Problem. Diese Lösung ist nicht universell verwendbar. (Crockford hätte das garantiert auch nicht empfohlen. ;)

                dedlfix.

                1. hi dedlfix,

                  Tach!

                  [Stringverkettung]
                  oder
                  [Ausgabepufferung]

                  Nein, das ist keine gute Idee. Der Ausgabepuffer ist global für das gesamte Programm zuständig, und mehrere werden übereinandergestapelt. Wenn man ihn für einen String-Puffer einzusetzt, muss man seine Nebenwirkungen beachten. Man kann immer nur den obersten verwenden und nicht gezielt einen beliebigen. Eine Variable hingegen wird nicht von anderen Programmteilen beeinflusst, solange sie nicht direkt angesprochen wird. So eine Lösung klappt nur mit einem einzelnen Text. Möchte man mehrere Texte gleichzeitig erstellen, hat man damit ein Problem. Diese Lösung ist nicht universell verwendbar. (Crockford hätte das garantiert auch nicht empfohlen. ;)

                  Crockford, so wie ich ihn verstehe, versucht fehlerträchtigen Code durch idiotensicheren Code zu ersetzen. So ganz hat sich mir das mit ob_start() und ob_get_clean() noch nicht erschlossen. Finde dazu auch im Manual keinen "kritischen" Hinweis:

                  http://php.net/manual/de/function.ob-start.php

                  "Ausgabepuffer können verschachtelt werden, d.g. Sie können ob_start() erneut aufrufen während bereits ein anderer ob_start() Aufruf aktiv ist. Sie müssen nur sicher stellen das Sie später auch ob_end_flush() entsprechend oft aufrufen. Sind mehrere Callback-Funktion aktiv so werden die Ausgaben der Reihe nach von Ausgabepuffer zu Ausgabepuffer weitergegeben und die Callback-Funktionen in Verschachtelungsreihenfolge aufgerufen."

                  mfg

                  tami

                  1. Tach!

                    Crockford, so wie ich ihn verstehe, versucht fehlerträchtigen Code durch idiotensicheren Code zu ersetzen. So ganz hat sich mir das mit ob_start() und ob_get_clean() noch nicht erschlossen. Finde dazu auch im Manual keinen "kritischen" Hinweis:

                    Das ist per se fehlerträchtig, weil Ausgabepuffer globaler Status (global state) sind. Man versucht sowas zu vermeiden, weil man über lokale Dinge einen viel besseren Überblick behalten kann als zu beachten, was alles Einfluss auf das globale Ding haben kann und was das globale Ding beeinflusst.

                    http://php.net/manual/de/function.ob-start.php

                    "Ausgabepuffer können verschachtelt werden, [...]

                    Verschachteln, ja. Aber sie sind nicht unabhängig voneinander verwendbar und man kann sie auch nicht gezielt ansprechen. Man sollte sie nur verwenden, wenn es gar nicht anders geht, aber nicht als generelle Alternative zu Stringverkettung oder anderen Dingen, die speziell für die zu erledigende Aufgabe vorgesehen sind. Ausgabepuffer sind zum Puffern der Ausgabe vorgesehen, nicht für das Verknüpfen von Strings, die gar nicht ausgegeben werden sollen. Crockford möchte sicher auch, dass man aus einem Konstrukt die Intention dahinter leicht erkennen kann. Bei einer Zweckentfremdung sieht man das eher nicht.

                    dedlfix.

          2. Hallo,

            Also musst du in jedem Schleifendurchlauf den neuen Teilstring an den bereits bestehenden _anhängen_ (der Fachbegriff wäre Stringverkettung). Du weist dagegen einfach nur zu und überschreibst so in jedem Durchlauf die Meldung aus dem vorherigen Durchlauf.
            Ok, da verstehe ich leider gerade nur Bahnhof. Kannst du mir hier weiterhelfen bitte?

            okay, versuchen wir mal, den Bahnhof genauer anzuschauen.

            $message = $row["f_name"] . ' '.$row["l_name"].' hat seit dem '.date('d.m.Y', strtotime($row["date"])).' keinen Besuchsbericht mehr abgegeben';

            Das ist aus deinem ursprünglichen Posting. Hier baust du aus mehreren Teilen einen String zusammen (und da schau her, hier wendest du die Stringverkettung sogar schon an), und weist den so erhaltenen String an $message zu. Was vorher eventuell schon in $message stand, wird dabei überschrieben, ist weg.
            Um den bisherigen Inhalt zu erhalten, müsstest du den eigentlich nur als ersten "Baustein" wieder mit einbauen, quasi nach dem Prinzip:

            $m = $m . $rest;

            Dafür gibt es sogar eine bequeme Kurzschreibweise:

            $m .= $rest;

            Wichtig ist dann, dass man $m _vor_ der Schleife einmal mit einem leeren String vorbelegt, weil sonst der lesende Zugriff im ersten Schleifendurchlauf eine Notice wegen der noch nicht existierenden Variablen schmeißt.

            Oh, und irgendwann wirst du dann feststellen, dass es ganz nett wäre, jede Zeile (jede Message) mit einem Zeilenumbruch abzuschließen. :-)

            So long,
             Martin

            --
            Wer barfuß geht, dem kann man nicht die Schuld in die Schuhe schieben.
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            1. Danke!!!
              Konnte nur mit dem Wort Verkettung nichts anfangen. Klappt nun, danke an alle!!!

            2. Tach!

              $m .= $rest;
              Wichtig ist dann, dass man $m _vor_ der Schleife einmal mit einem leeren String vorbelegt, weil sonst der lesende Zugriff im ersten Schleifendurchlauf eine Notice wegen der noch nicht existierenden Variablen schmeißt.

              Oder noch schlimmer, irgendwelches Zeug von vorher ausgeführtem Code drinstehen hat, wenn man diese Variable mehrfach verwendet. Ganz früher war das sogar mal sicherheitsrelevant, weil man von außen beliebig Variablen in das Script schleusen konnte. Dieses Feature wurde zwar entfernt, es ist aber weiterhin guter Stil, Variablen vor dem Gebrauch gezielt zu initialisieren.

              dedlfix.

          3. Also musst du in jedem Schleifendurchlauf den neuen Teilstring an den bereits bestehenden _anhängen_ (der Fachbegriff wäre Stringverkettung). Du weist dagegen einfach nur zu und überschreibst so in jedem Durchlauf die Meldung aus dem vorherigen Durchlauf.

            Ok, da verstehe ich leider gerade nur Bahnhof. Kannst du mir hier weiterhelfen bitte?

            Ich weiss jetzt nicht, ob das an der Formatierung durch die Forumssoftware lag, aber der Code, denn du zitiert hast, ist nicht sinngemäß eingerückt. Dadurch geht dir möglicherweise der Überblick verloren.

            Du machst im Moment Folgendes:

            while($row = $result->fetch_assoc()) {  
               $message = $row["f_name"] . ' '.$row["l_name"].' hat seit dem '.date('d.m.Y',}mail($empfaenger, $betreff, $message, $headers);
            

            In anderen Worten:

            1 Datenbankergebnis vorhanden (Abfrage in while):
            2    message mit dem Ergebnistext belegen
            3    zu Zeile 1 springen; falls jedoch kein weiteres Ergebnis, bei 4 weitermachen
            4 Mail abschicken

            Was du machen möchtest:

            1 Datenbankergebnis vorhanden (Abfrage in while):
            2    an message den Ergebnistext _anhängen_
            3    zu Zeile 1 springen; falls jedoch kein weiteres Ergebnis, bei 4 weitermachen
            4 Mail abschicken

            Beachte den Unterschied in Zeile 2. Wie du das umsetzen kannst, hast bereits in obigem Code gezeigt; schau mal genau hin, wie bzw. aus was du message belegst.