diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 34678ea3d0f7f..7bcb771dae84b 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -4128,7 +4128,9 @@ PHP_FUNCTION(mb_send_mail) || orig_str.encoding->no_encoding == mbfl_no_encoding_pass) { orig_str.encoding = mbfl_identify_encoding(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); } - pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, CRLF, sizeof("Subject: [PHP-jp nnnnnnnn]" CRLF) - 1); + const char *line_sep = PG(mail_mixed_lf_and_crlf) ? "\n" : CRLF; + size_t line_sep_len = strlen(line_sep); + pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, line_sep, strlen("Subject: [PHP-jp nnnnnnnn]") + line_sep_len); if (pstr != NULL) { subject_buf = subject = (char *)pstr->val; } @@ -4167,14 +4169,14 @@ PHP_FUNCTION(mb_send_mail) n = ZSTR_LEN(str_headers); mbfl_memory_device_strncat(&device, p, n); if (n > 0 && p[n - 1] != '\n') { - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + mbfl_memory_device_strncat(&device, line_sep, line_sep_len); } zend_string_release_ex(str_headers, 0); } if (!zend_hash_str_exists(&ht_headers, "mime-version", sizeof("mime-version") - 1)) { mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1); - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + mbfl_memory_device_strncat(&device, line_sep, line_sep_len); } if (!suppressed_hdrs.cnt_type) { @@ -4185,7 +4187,7 @@ PHP_FUNCTION(mb_send_mail) mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1); mbfl_memory_device_strcat(&device, p); } - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + mbfl_memory_device_strncat(&device, line_sep, line_sep_len); } if (!suppressed_hdrs.cnt_trans_enc) { mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1); @@ -4194,10 +4196,12 @@ PHP_FUNCTION(mb_send_mail) p = "7bit"; } mbfl_memory_device_strcat(&device, p); - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + mbfl_memory_device_strncat(&device, line_sep, line_sep_len); } - mbfl_memory_device_unput(&device); + if (!PG(mail_mixed_lf_and_crlf)) { + mbfl_memory_device_unput(&device); + } mbfl_memory_device_unput(&device); mbfl_memory_device_output('\0', &device); str_headers = zend_string_init((char *)device.buffer, strlen((char *)device.buffer), 0); diff --git a/ext/mbstring/tests/gh8086.phpt b/ext/mbstring/tests/gh8086.phpt new file mode 100644 index 0000000000000..2eeed67e5b483 --- /dev/null +++ b/ext/mbstring/tests/gh8086.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-8086 (mb_send_mail() function not working correctly in PHP 8.x) +--SKIPIF-- + +--INI-- +sendmail_path={MAIL:{PWD}/gh8086.eml} +mail.mixed_lf_and_crlf=on +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(6) diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 55790e6100fce..ef4c8c60a874e 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -429,6 +429,8 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co MAIL_RET(0); } + char *line_sep = PG(mail_mixed_lf_and_crlf) ? "\n" : "\r\n"; + if (PG(mail_x_header)) { const char *tmp = zend_get_executed_filename(); zend_string *f; @@ -436,7 +438,7 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co f = php_basename(tmp, strlen(tmp), NULL, 0); if (headers != NULL && *headers) { - spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\r\n%s", php_getuid(), ZSTR_VAL(f), headers); + spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%s%s", php_getuid(), ZSTR_VAL(f), line_sep, headers); } else { spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f)); } @@ -510,12 +512,12 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co MAIL_RET(0); } #endif - fprintf(sendmail, "To: %s\r\n", to); - fprintf(sendmail, "Subject: %s\r\n", subject); + fprintf(sendmail, "To: %s%s", to, line_sep); + fprintf(sendmail, "Subject: %s%s", subject, line_sep); if (hdr != NULL) { - fprintf(sendmail, "%s\r\n", hdr); + fprintf(sendmail, "%s%s", hdr, line_sep); } - fprintf(sendmail, "\r\n%s\r\n", message); + fprintf(sendmail, "%s%s%s", line_sep, message, line_sep); ret = pclose(sendmail); #if PHP_SIGCHILD diff --git a/ext/standard/tests/mail/gh8086.phpt b/ext/standard/tests/mail/gh8086.phpt new file mode 100644 index 0000000000000..fba5cc56bb450 --- /dev/null +++ b/ext/standard/tests/mail/gh8086.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-8086 (Mail() function not working correctly in PHP 8.x) +--INI-- +sendmail_path={MAIL:gh8086.out} +mail.mixed_lf_and_crlf=on +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +int(5) diff --git a/main/main.c b/main/main.c index 8be52d316a159..6b8a9e6bd1990 100644 --- a/main/main.c +++ b/main/main.c @@ -737,6 +737,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("SMTP", "localhost",PHP_INI_ALL, NULL) PHP_INI_ENTRY("smtp_port", "25", PHP_INI_ALL, NULL) STD_PHP_INI_BOOLEAN("mail.add_x_header", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_x_header, php_core_globals, core_globals) + 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) STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals) PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap) PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit) diff --git a/main/php_globals.h b/main/php_globals.h index cbf0271c7b763..0e004bd011181 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -153,6 +153,7 @@ struct _php_core_globals { char *request_order; bool mail_x_header; + bool mail_mixed_lf_and_crlf; char *mail_log; bool in_error_log; diff --git a/php.ini-development b/php.ini-development index 70c6b00555844..ba75e4933ba7c 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1095,6 +1095,10 @@ smtp_port = 25 ; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename mail.add_x_header = Off +; Use mixed LF and CRLF line separators to keep compatibility with some +; RFC 2822 non conformant MTA. +mail.mixed_lf_and_crlf = Off + ; The path to a log file that will log all mail() calls. Log entries include ; the full path of the script, line number, To address and headers. ;mail.log = diff --git a/php.ini-production b/php.ini-production index 21627c9142487..9f9ff22586d6d 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1097,6 +1097,10 @@ smtp_port = 25 ; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename mail.add_x_header = Off +; Use mixed LF and CRLF line separators to keep compatibility with some +; RFC 2822 non conformant MTA. +mail.mixed_lf_and_crlf = Off + ; The path to a log file that will log all mail() calls. Log entries include ; the full path of the script, line number, To address and headers. ;mail.log =