From 0f62ad9c7df2c7c8e612ab61da1bade6debae416 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 1 Aug 2025 14:46:33 +0200 Subject: [PATCH 1/2] 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 fdeabd1872d20..598cb8612a68d 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 f0e32360d9165dd34dfd0f7a382507ef4eaa09f4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 2 Dec 2025 15:02:11 +0100 Subject: [PATCH 2/2] fix inconsistent behavior --- NEWS | 2 ++ ext/standard/file.c | 23 ++++++++++--- .../tests/file/file_skip_empty_lines.phpt | 33 +++++++++++++++---- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index d8242f50594c4..9d0a7eb86db00 100644 --- a/NEWS +++ b/NEWS @@ -46,6 +46,8 @@ PHP NEWS - Standard: . Fixed bug GH-19926 (reset internal pointer earlier while splicing array while COW violation flag is still set). (alexandre-daubois) + . Fixed bug GH-18120 (Honor FILE_SKIP_EMPTY_LINES even when + FILE_IGNORE_NEW_LINES is not set). (alexandre-daubois) - Streams: . Added so_reuseaddr streams context socket option that allows disabling diff --git a/ext/standard/file.c b/ext/standard/file.c index 598cb8612a68d..e0f044cd9328b 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) { +}