Problem mit Kontaktformular
Peter
- php
Hallo zusammen,
woran kann es liegen, dass eine einfache mail-Anweisung in PHP immer eine Zeile zuviel in der Mail mitsendet?
Die betreffende Zeile ist lediglich
$abgesendet= mail($empfaenger,$betreff,$_POST['inhalt'],"From: ".$_POST['name']." <".strtolower($_POST['absender']).">");
Ich raste gleich aus. Da ist doch kein Fehler drin, oder?
Gruß
Also ich habe es jetzt mit der Zeile
$inhalt = str_replace("\n", "", $_POST['inhalt']);
geschafft. Aber das ist doch nicht normal oder?
Hello,
Also ich habe es jetzt mit der Zeile
$inhalt = str_replace("\n", "", $_POST['inhalt']);
Du bist zwar schon auf dem richtigen Weg, aber dann aolltest Du lieber nur "\r\n" gegen "\n" austauschen.
Wenn Du nämlich jetzt einen "kaputten" Linux-Browser als Absender erwischst, der meint, er müsse nur "\n" für die Zeilenschaltung senden, dann hast Du nachher gar keine Zeilenschlatungen mehr. Das gleiche gilt für einen "kaputten" MAC-Browser (älterer Bauart). Der würde dann nämlich nur "\r" senden.
Dabei müssten beide "\r\n" senden, denn das ist im HTTP-Standard festgelegt.
Wenn Du nun also nur die doppelten gegen einfache austauschst, und auf einer Linux-Kiste bietet sich dann wiederum "\n" als Zielgröße an, sollte es eigetnlich immer klappen.
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hello,
woran kann es liegen, dass eine einfache mail-Anweisung in PHP immer eine Zeile zuviel in der Mail mitsendet?
Die betreffende Zeile ist lediglich$abgesendet= mail($empfaenger,$betreff,$_POST['inhalt'],"From: ".$_POST['name']." <".strtolower($_POST['absender']).">");
Diese Anweisung wird hoffentlich nie so in einem öffentlich zugänglichen Script stehen!
Durch die ungeprüfte Übernahme von extternen Werten ($_POST['name']) ind die Header der Mail (hier 'From:') kann ein Angreifer die Mail für seine Zwecke missbrauchen. Es ist ggf. sogar ein komplettes Überschreiben der von Dir eigentlich vorgesehehen Header möglich.
Nun zur eigentlichen Frage: Wo ist eine Leerzeile zuviel? Bei jeder Zeilenschaltung oder nur am Ende?
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hallo und vielen Dank für deine Antwort.
Bin noch ganz am Anfang von dem Script. Die einzelnen Werte sollen per isset überprüft werden und zusätzlich soll ein Spamschutz eingebaut werden. Ist das trotzdem noch unsicher?
Wenn im Formular eine Leerzeile durch Enter drücken entsteht, wird jedes mal eine weitere Leerzeile angehängt.
Hello,
Wenn im Formular eine Leerzeile durch Enter drücken entsteht, wird jedes mal eine weitere Leerzeile angehängt.
Das mag noch ein Fehler der Funktion mail() sein.
Normalerweise sollen Zeilenschaltungen in Mail-Headern immer durch \r\n durchgeführt werden.
Das sind auch die Zeichen, die aus dem Browser für eine Zeilenschaltung kommen sollten und zwar vollkommen unabhängig davon, ob der auf einem MAC, einer WinDOSe oder einem UNIX-Derivat läuft.
Wenn die Browser das nicht machen, verhalten sie sich falsch.
Die PHP-Entwickler scheinen aber in der Mail-Funktion auch etwas verbogen zu haben.
Sie machen im Body aus jedem \n ein \r\n und aus jedem \r auch.
Ulkigerweise werden die Header richtig behandelt. Aber das liegt wahrscheinslich daran, dass alle Heasder vorher in einer Tabelle (Array) gesammelt werden, und dann erst am Ende zum mailheader verbunden werden.
Wenn Du nun also Texte aus einem intakten Browser erhältst, und diese in einer Mail mittels der PHP Mail()-Funtktion weitersenden willst, dann musst Du einfach die \r\n gegen \n austauschen.
$bodytext = str_replace("\r\n", "\n", $bodytext);
Danach funktioniert es auch mit der PHP mail()-Funktion.
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Stimmt, jetzt funktioniert alles wie es soll.
Vielen Dank auch für die interessante Erklärung.
Wie sieht es denn mit der Sicherheit aus, wenn ich die Angaben aus dem Formular mit isset überprüfe und zusätzlich einen Spamschutz einbaue?
Hello,
Stimmt, jetzt funktioniert alles wie es soll.
Vielen Dank auch für die interessante Erklärung.Wie sieht es denn mit der Sicherheit aus, wenn ich die Angaben aus dem Formular mit isset überprüfe und zusätzlich einen Spamschutz einbaue?
$abgesendet= mail($empfaenger,$betreff,$_POST['inhalt'],"From: ".$_POST['name']." <".strtolower($_POST['absender']).">");
Das Problem sind alle Werte, die Einzug in die Header einer eMail nehmen.
Das sind
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
also kurz geschrieben:
mail($to, $subject, $message, $headers, $parameters)
$to
$subject
$headers
($parameters)
Wenn Du nun ein "From: email@example.org" angeben lassen willst, und jemand schreibt Dir dort
"From: email@eaxamle.org\r\nTo: <ganz viele adressen>"
rein, dann wird die email ggf. an jemand ganz anderen, und ggf. auch an ganz viele andere Leute verschickt...
das musst Du eben abfangen.
Es wurde hier oft genug diskutiert, wie man das machen sollte. Ich persönlich komme immer wieder zu dem Ergebnis, dass es für die Sicherheit ausreichen sollte, wenn man genau ein '@' verlangt aunf verhindert, dass "\r\n", "\r" oder "\n" enthalten sind in diesen Zeilen.
Sind Umbruchzeichen enthalten, die ja über das angebotene Formular normalerweise gar nicht hingelangen konnten, dann kann es scih nur um einen Misbrauchsversuch handeln, und man sollte sofort abbrechen.
Wenn das From-Feld daten enthielt, aber kein @, lohnt sich das Weiterarbeiten für diesen Client eigentlich auch nicht. Vielleicht sollte man ihn dann in einen "netten Dialog" verstricken :-))
Für das Dubject-Feld gilt für die Zeilenumbrüche das Gleiche.
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
An sowas habe ich gar nicht gedacht.
Ich habe aber jetzt mal versucht mein Formular selber zu hacken und festgestellt, dass der Code der die E-Mail Adresse überprüft das nicht zulässt. Ich werde aber noch weiter versuchen das Teil sicherer zu machen.
Vielen Dank.
Hello,
Das mag noch ein Fehler der Funktion mail() sein.
PHP schiebt das übrigens auf die verwendeten Mailer auf dem Unix-System.
Ich kann mir aber nicht vorstellen, dass ein (neures) Postfix diesen Fehler hat.
Und das habe ich gerade eben zum Testen benutzt.
Ich habe in die Standard-Mail-Implementation von Mail noch nicht reingeschaut.
Sollte ich aber mal versuchen...
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hello,
PHP schiebt das übrigens auf die verwendeten Mailer auf dem Unix-System.
Ich kann mir aber nicht vorstellen, dass ein (neures) Postfix diesen Fehler hat.
Und das habe ich gerade eben zum Testen benutzt.
sieht so aus, dass es wirklich postfix ist, dass hier die \r\n im Mailbody verdoppelt.
Ich habe mal versucht, dass nachzuvollziehen, was mit den Funtkionsargumenten bis zur Übergabe an den Mailer geschieht, konnte da aber nicht finden, ob die auf dem Wege bis zu dieser Stelle schon irgendwqo manipuliert wurden.
#ifdef PHP_WIN32
sendmail = popen(sendmail_cmd, "wb");
#else
/* Since popen() doesn't indicate if the internal fork() doesn't work
* (e.g. the shell can't be executed) we explicitely set it to 0 to be
* sure we don't catch any older errno value. */
errno = 0;
sendmail = popen(sendmail_cmd, "w");
#endif
if (extra_cmd != NULL)
efree (sendmail_cmd);
if (sendmail) {
#ifndef PHP_WIN32
if (EACCES == errno) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
pclose(sendmail);
return 0;
}
#endif
fprintf(sendmail, "To: %s\n", to);
fprintf(sendmail, "Subject: %s\n", subject);
if (headers != NULL) {
fprintf(sendmail, "%s\n", headers);
}
fprintf(sendmail, "\n%s\n", message);
ret = pclose(sendmail);
Und hier wird die Message einfach auf den geöffneten Kanal geschrieben.
Das würde bedeuten, dass sich PHP-Mail() bewusst falsch verhält, indem es Header und Body nur mit einem einfachen "\n" abschließt. Oder es bestehen einfach noch Missverständnisse darüber, an welcher Stelle die HTTP- und MIME-Spezifikation hergestellt werden muss.
Wenn Postfix meint, es müsse das selber tun, dann muss man das wissen.
Wird dann nämlich ein anderer Mailer verwendet, der sich nicht dafür verantwortlich fühlt, funktioniert nachher nix mehr.
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
echo $begrüßung;
Ich habe mal versucht, dass nachzuvollziehen, was mit den Funtkionsargumenten bis zur Übergabe an den Mailer geschieht, konnte da aber nicht finden, ob die auf dem Wege bis zu dieser Stelle schon irgendwqo manipuliert wurden.
Ich nehme mal die Verion 1.96 aus dem CSV in der annotierten Version, da gibt es Zeilennummern.
fprintf(sendmail, "To: %s\n", to);
fprintf(sendmail, "Subject: %s\n", subject);
if (headers != NULL) {
fprintf(sendmail, "%s\n", headers);
}
fprintf(sendmail, "\n%s\n", message);
ret = pclose(sendmail);
> Und hier wird die Message einfach auf den geöffneten Kanal geschrieben.
Ja, das ist der Teil, der die Header und den Body zusammenbaut. Im Original zu finden ab Zeile 235. Das ist nicht RFC-konform (nur \n statt \r\n), muss aber offensichtlich so sein, weil sonst die Empfehlung aus dem Handbuch "If messages are not received, try using a LF (\n) only. Some poor quality Unix mail transfer agents ..." nicht funktionieren tät. Im Bugtracker fand ich eine Diskussion zu diesem Thema: [#15841](http://bugs.php.net/bug.php?id=15841). Interessanter Punkt in der Diskussion: Unter Unix wird kein SMTP gesprochen sondern mit dem Mailprogramm des Systems. Der sollte systemtypische Zeilenumbrüche entgegennehmen und sie dann beim SMTP-Prozess korrekt gemäß RFC umsetzen. Windows spricht jedoch direkt SMTP, da braucht es eigentlich korrekterweise die \r\n.
Für die beiden extra zu verwendenden Header-Teile to und subject gibt es übrigens eine Behandlung in den Zeilen 114 bis 152. Hier werden alle von [ctype](http://de2.php.net/manual/en/ref.ctype.php) als "cntrl"-Zeichen gewertete Zeichen in ein Leerzeichen umgeschrieben (mit der ab Zeile 124 erwähnten Ausnahme).
> Das würde bedeuten, dass sich PHP-Mail() bewusst falsch verhält, indem es Header und Body nur mit einem einfachen "\n" abschließt. Oder es bestehen einfach noch Missverständnisse darüber, an welcher Stelle die HTTP- und MIME-Spezifikation hergestellt werden muss.
Ja, sieht so aus.
echo "$verabschiedung $name";