Skip to content

Commit 90c7755

Browse files
committed
Fix GH-8086: Introduce mail.mixed_lf_and_crlf INI
When this INI option is enabled, it reverts the line separator for headers and message to LF which was a non conformant behavior in PHP 7. It is done because some non conformant MTAs fail to parse CRLF line separator for headers and body.
1 parent 9faa3f1 commit 90c7755

File tree

6 files changed

+35
-5
lines changed

6 files changed

+35
-5
lines changed

ext/standard/mail.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -429,14 +429,16 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co
429429
MAIL_RET(0);
430430
}
431431

432+
char *line_sep = PG(mail_mixed_lf_and_crlf) ? "\n" : "\r\n";
433+
432434
if (PG(mail_x_header)) {
433435
const char *tmp = zend_get_executed_filename();
434436
zend_string *f;
435437

436438
f = php_basename(tmp, strlen(tmp), NULL, 0);
437439

438440
if (headers != NULL && *headers) {
439-
spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\r\n%s", php_getuid(), ZSTR_VAL(f), headers);
441+
spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%s%s", php_getuid(), ZSTR_VAL(f), line_sep, headers);
440442
} else {
441443
spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
442444
}
@@ -510,12 +512,12 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co
510512
MAIL_RET(0);
511513
}
512514
#endif
513-
fprintf(sendmail, "To: %s\r\n", to);
514-
fprintf(sendmail, "Subject: %s\r\n", subject);
515+
fprintf(sendmail, "To: %s%s", to, line_sep);
516+
fprintf(sendmail, "Subject: %s%s", subject, line_sep);
515517
if (hdr != NULL) {
516-
fprintf(sendmail, "%s\r\n", hdr);
518+
fprintf(sendmail, "%s%s", hdr, line_sep);
517519
}
518-
fprintf(sendmail, "\r\n%s\r\n", message);
520+
fprintf(sendmail, "%s%s%s", line_sep, message, line_sep);
519521
ret = pclose(sendmail);
520522

521523
#if PHP_SIGCHILD

ext/standard/tests/mail/gh8086.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
GH-8086 (Mail() function not working correctly in PHP 8.x)
3+
--INI--
4+
sendmail_path={MAIL:bug47983.out}
5+
mail.mixed_lf_and_crlf=on
6+
--FILE--
7+
<?php
8+
var_dump(mail('user@example.com', 'Test Subject', 'A Message', 'KHeaders'));
9+
$mail = file_get_contents('bug47983.out');
10+
var_dump(preg_match_all('/(?<!\r)\n/', $mail));
11+
?>
12+
--CLEAN--
13+
<?php
14+
unlink('bug47983.out');
15+
?>
16+
--EXPECT--
17+
bool(true)
18+
int(5)

main/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ PHP_INI_BEGIN()
737737
PHP_INI_ENTRY("SMTP", "localhost",PHP_INI_ALL, NULL)
738738
PHP_INI_ENTRY("smtp_port", "25", PHP_INI_ALL, NULL)
739739
STD_PHP_INI_BOOLEAN("mail.add_x_header", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_x_header, php_core_globals, core_globals)
740+
STD_PHP_INI_BOOLEAN("mail.mixed_lf_and_crlf", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_mixed_lf_and_crlf, php_core_globals, core_globals)
740741
STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals)
741742
PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap)
742743
PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit)

main/php_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ struct _php_core_globals {
153153
char *request_order;
154154

155155
bool mail_x_header;
156+
bool mail_mixed_lf_and_crlf;
156157
char *mail_log;
157158

158159
bool in_error_log;

php.ini-development

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,10 @@ smtp_port = 25
10951095
; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
10961096
mail.add_x_header = Off
10971097

1098+
; Use mixed LF and CRLF line separators to keep compatibility with some
1099+
; RFC 2822 non conformant MTA.
1100+
mail.mixed_lf_and_crlf = Off
1101+
10981102
; The path to a log file that will log all mail() calls. Log entries include
10991103
; the full path of the script, line number, To address and headers.
11001104
;mail.log =

php.ini-production

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,10 @@ smtp_port = 25
10971097
; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
10981098
mail.add_x_header = Off
10991099

1100+
; Use mixed LF and CRLF line separators to keep compatibility with some
1101+
; RFC 2822 non conformant MTA.
1102+
mail.mixed_lf_and_crlf = Off
1103+
11001104
; The path to a log file that will log all mail() calls. Log entries include
11011105
; the full path of the script, line number, To address and headers.
11021106
;mail.log =

0 commit comments

Comments
 (0)