From b637450ee2ec9742f7b49648c4f110c947d24c9c Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 1 Aug 2025 14:46:33 +0200 Subject: [PATCH 1/3] Fix GH-18120: Honor `FILE_SKIP_EMPTY_LINES` even when `FILE_IGNORE_NEW_LINES` is not set --- ext/standard/file.c | 10 ++ .../tests/file/file_skip_empty_lines.phpt | 103 ++++++++++++++++++ ext/standard/tests/file/file_variation.phpt | 10 +- ext/standard/tests/file/file_variation7.phpt | 9 +- 4 files changed, 118 insertions(+), 14 deletions(-) create mode 100644 ext/standard/tests/file/file_skip_empty_lines.phpt diff --git a/ext/standard/file.c b/ext/standard/file.c index 364985f786b7e..7f1b6b1b0aedf 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -640,6 +640,16 @@ PHP_FUNCTION(file) do { p++; parse_eol: + if (skip_blank_lines) { + int windows_eol = 0; + if (p != ZSTR_VAL(target_buf) && eol_marker == '\n' && *(p - 1) == '\r') { + windows_eol++; + } + if (p-s-windows_eol == 1) { + s = p; + continue; + } + } add_index_stringl(return_value, i++, s, p-s); s = p; } while ((p = memchr(p, eol_marker, (e-p)))); diff --git a/ext/standard/tests/file/file_skip_empty_lines.phpt b/ext/standard/tests/file/file_skip_empty_lines.phpt new file mode 100644 index 0000000000000..88093aae81615 --- /dev/null +++ b/ext/standard/tests/file/file_skip_empty_lines.phpt @@ -0,0 +1,103 @@ +--TEST-- +Test file() function with FILE_SKIP_EMPTY_LINES flag +--FILE-- + +--EXPECT-- +array(3) { + [0]=> + string(6) "First +" + [1]=> + string(7) "Second +" + [2]=> + string(6) "Third +" +} +array(3) { + [0]=> + string(5) "First" + [1]=> + string(6) "Second" + [2]=> + string(5) "Third" +} +array(6) { + [0]=> + string(5) "First" + [1]=> + string(0) "" + [2]=> + string(6) "Second" + [3]=> + string(0) "" + [4]=> + string(0) "" + [5]=> + string(5) "Third" +} +array(6) { + [0]=> + string(6) "First +" + [1]=> + string(1) " +" + [2]=> + string(7) "Second +" + [3]=> + string(1) " +" + [4]=> + string(1) " +" + [5]=> + string(6) "Third +" +} +array(3) { + [0]=> + string(7) "First +" + [1]=> + string(2) " +" + [2]=> + string(8) "Second +" +} +array(2) { + [0]=> + string(5) "First" + [1]=> + string(6) "Second" +} diff --git a/ext/standard/tests/file/file_variation.phpt b/ext/standard/tests/file/file_variation.phpt index 2c46f039c2398..3a69c0bc24eb1 100644 --- a/ext/standard/tests/file/file_variation.phpt +++ b/ext/standard/tests/file/file_variation.phpt @@ -106,20 +106,14 @@ array(5) { [4]=> string(5) " data" } -array(5) { +array(3) { [0]=> string(4) "Gar " [1]=> - string(1) " -" - [2]=> string(6) "bage " - [3]=> - string(1) " -" - [4]=> + [2]=> string(5) " data" } *** Testing with variation in use_include_path argument *** diff --git a/ext/standard/tests/file/file_variation7.phpt b/ext/standard/tests/file/file_variation7.phpt index 72af244a54e17..15d1f319a91d3 100644 --- a/ext/standard/tests/file/file_variation7.phpt +++ b/ext/standard/tests/file/file_variation7.phpt @@ -62,20 +62,17 @@ array(5) { } file() with FILE_SKIP_EMPTY_LINES: -array(5) { +array(4) { [0]=> string(7) "Line 1 " [1]=> - string(1) " -" - [2]=> string(2) " " - [3]=> + [2]=> string(3) " " - [4]=> + [3]=> string(7) "\Line 3" } From 47ddc2745dcc1fc59d8a30546a3d87313ce52d0d Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 2 Dec 2025 15:02:11 +0100 Subject: [PATCH 2/3] fix inconsistent behavior --- ext/standard/file.c | 23 ++++++++++--- .../tests/file/file_skip_empty_lines.phpt | 33 +++++++++++++++---- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/ext/standard/file.c b/ext/standard/file.c index 7f1b6b1b0aedf..9ea28608a415b 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -641,11 +641,26 @@ PHP_FUNCTION(file) p++; parse_eol: if (skip_blank_lines) { - int windows_eol = 0; - if (p != ZSTR_VAL(target_buf) && eol_marker == '\n' && *(p - 1) == '\r') { - windows_eol++; + size_t eol_len = 1; + + if (eol_marker == '\n') { + if (p - ZSTR_VAL(target_buf) >= 2 && *(p - 2) == '\r' && *(p - 1) == '\n') { + eol_len = 2; + } else if (p == e && p > s) { + const char *check = p - 1; + while (check > s && *check == '\r') { + check--; + } + if (check == s && *check == '\r') { + s = p; + continue; + } + eol_len = 1; + } } - if (p-s-windows_eol == 1) { + + size_t line_len = p - s; + if (line_len == eol_len) { s = p; continue; } diff --git a/ext/standard/tests/file/file_skip_empty_lines.phpt b/ext/standard/tests/file/file_skip_empty_lines.phpt index 88093aae81615..d19e8431b55e7 100644 --- a/ext/standard/tests/file/file_skip_empty_lines.phpt +++ b/ext/standard/tests/file/file_skip_empty_lines.phpt @@ -1,5 +1,5 @@ --TEST-- -Test file() function with FILE_SKIP_EMPTY_LINES flag +GH-18120 (Honor FILE_SKIP_EMPTY_LINES even when FILE_IGNORE_NEW_LINES is not set) --FILE-- +--CLEAN-- + --EXPECT-- array(3) { [0]=> @@ -84,14 +100,11 @@ array(6) { string(6) "Third " } -array(3) { +array(2) { [0]=> string(7) "First " [1]=> - string(2) " -" - [2]=> string(8) "Second " } @@ -101,3 +114,11 @@ array(2) { [1]=> string(6) "Second" } +array(0) { +} +array(0) { +} +array(0) { +} +array(0) { +} From 369ec875e06676a5dd0ee77c58e68b009b4472f4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 26 Mar 2026 07:54:13 +0100 Subject: [PATCH 3/3] Address latest comment --- NEWS | 2 ++ ext/standard/file.c | 23 ++++--------------- .../tests/file/file_skip_empty_lines.phpt | 7 ++++++ 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/NEWS b/NEWS index e2df869dfbc7d..03b677539baa8 100644 --- a/NEWS +++ b/NEWS @@ -140,6 +140,8 @@ PHP NEWS . Fixed bug GH-13204 (glob() fails if square bracket is in current directory). (ndossche) . Add array size maximum to array_diff(). (ndossche) + . Fixed bug GH-18120 (Honor FILE_SKIP_EMPTY_LINES even when + FILE_IGNORE_NEW_LINES is not set). (alexandre-daubois) - Streams: . Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream diff --git a/ext/standard/file.c b/ext/standard/file.c index 9ea28608a415b..e5793c79f487a 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -641,26 +641,11 @@ PHP_FUNCTION(file) p++; parse_eol: if (skip_blank_lines) { - size_t eol_len = 1; - - if (eol_marker == '\n') { - if (p - ZSTR_VAL(target_buf) >= 2 && *(p - 2) == '\r' && *(p - 1) == '\n') { - eol_len = 2; - } else if (p == e && p > s) { - const char *check = p - 1; - while (check > s && *check == '\r') { - check--; - } - if (check == s && *check == '\r') { - s = p; - continue; - } - eol_len = 1; - } + const char *c = s; + while (c < p && (*c == '\n' || *c == '\r')) { + c++; } - - size_t line_len = p - s; - if (line_len == eol_len) { + if (c == p) { s = p; continue; } diff --git a/ext/standard/tests/file/file_skip_empty_lines.phpt b/ext/standard/tests/file/file_skip_empty_lines.phpt index d19e8431b55e7..62d2d1ee874c7 100644 --- a/ext/standard/tests/file/file_skip_empty_lines.phpt +++ b/ext/standard/tests/file/file_skip_empty_lines.phpt @@ -43,6 +43,11 @@ var_dump($lines); file_put_contents($test_file, "\r\n"); $lines = file($test_file, FILE_SKIP_EMPTY_LINES); var_dump($lines); + +file_put_contents($test_file, "\r\r\n\n"); +$lines = file($test_file, FILE_SKIP_EMPTY_LINES); +var_dump($lines); + ?> --CLEAN-- @@ -122,3 +127,5 @@ array(0) { } array(0) { } +array(0) { +}