diff --git a/generated/filesystem.php b/generated/filesystem.php index de1a704d..df545f84 100644 --- a/generated/filesystem.php +++ b/generated/filesystem.php @@ -226,52 +226,6 @@ function fflush($stream): void } -/** - * Similar to fgets except that - * fgetcsv parses the line it reads for fields in - * CSV format and returns an array containing the fields - * read. - * - * @param resource $stream A valid file pointer to a file successfully opened by - * fopen, popen, or - * fsockopen. - * @param int $length Must be greater than the longest line (in characters) to be found in - * the CSV file (allowing for trailing line-end characters). Otherwise the - * line is split in chunks of length characters, - * unless the split would occur inside an enclosure. - * - * Omitting this parameter (or setting it to 0, - * or NULL in PHP 8.0.0 or later) the maximum line length is not limited, - * which is slightly slower. - * @param string $separator The optional separator parameter sets the field separator (one single-byte character only). - * @param string $enclosure The optional enclosure parameter sets the field enclosure character (one single-byte character only). - * @param string $escape The optional escape parameter sets the escape character (at most one single-byte character). - * An empty string ("") disables the proprietary escape mechanism. - * @return array|null Returns an indexed array containing the fields read on success. - * @throws FilesystemException - * - */ -function fgetcsv($stream, int $length = null, string $separator = ",", string $enclosure = "\"", string $escape = "\\"): ?array -{ - error_clear_last(); - if ($escape !== "\\") { - $safeResult = \fgetcsv($stream, $length, $separator, $enclosure, $escape); - } elseif ($enclosure !== "\"") { - $safeResult = \fgetcsv($stream, $length, $separator, $enclosure); - } elseif ($separator !== ",") { - $safeResult = \fgetcsv($stream, $length, $separator); - } elseif ($length !== null) { - $safeResult = \fgetcsv($stream, $length); - } else { - $safeResult = \fgetcsv($stream); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - /** * This function is similar to file, except that * file_get_contents returns the file in a diff --git a/generated/functionsList.php b/generated/functionsList.php index 60fbea9a..8d853952 100644 --- a/generated/functionsList.php +++ b/generated/functionsList.php @@ -913,7 +913,6 @@ 'simplexml_import_dom', 'simplexml_load_file', 'simplexml_load_string', - 'sleep', 'socket_accept', 'socket_addrinfo_bind', 'socket_addrinfo_connect', diff --git a/generated/misc.php b/generated/misc.php index b608509d..ab4ac59b 100644 --- a/generated/misc.php +++ b/generated/misc.php @@ -418,32 +418,6 @@ function sapi_windows_vt100_support($stream, bool $enable = null): void } -/** - * - * - * @param int $seconds Halt time in seconds. - * @return int Returns zero on success. - * - * If the call was interrupted by a signal, sleep returns - * a non-zero value. On Windows, this value will always be - * 192 (the value of the - * WAIT_IO_COMPLETION constant within the Windows API). - * On other platforms, the return value will be the number of seconds left to - * sleep. - * @throws MiscException - * - */ -function sleep(int $seconds): int -{ - error_clear_last(); - $safeResult = \sleep($seconds); - if ($safeResult === false) { - throw MiscException::createFromPhpError(); - } - return $safeResult; -} - - /** * Delays program execution for the given number of * seconds and nanoseconds. diff --git a/generator/config/specialCasesFunctions.php b/generator/config/specialCasesFunctions.php index 7b830d2f..cc6782ce 100644 --- a/generator/config/specialCasesFunctions.php +++ b/generator/config/specialCasesFunctions.php @@ -15,4 +15,5 @@ 'simplexml_import_dom', 'simplexml_load_file', 'simplexml_load_string', + 'fgetcsv', // This function need to return false when iterating on a newline. ]; diff --git a/generator/tests/SpecialCasesTest.php b/generator/tests/SpecialCasesTest.php index c90a7343..e5f97232 100644 --- a/generator/tests/SpecialCasesTest.php +++ b/generator/tests/SpecialCasesTest.php @@ -3,6 +3,7 @@ namespace Safe; use PHPUnit\Framework\TestCase; +use Safe\Exceptions\FilesystemException; use Safe\Exceptions\PcreException; class SpecialCasesTest extends TestCase @@ -18,4 +19,55 @@ public function testPregReplace() $this->expectExceptionMessage('PREG_BAD_UTF8_ERROR: Invalid UTF8 character'); preg_replace("/([\s,]+)/u", "foo", "\xc3\x28"); } + + public function testFgetcsvWithTrailingNewline() + { + require_once __DIR__.'/../../lib/special_cases.php'; + require_once __DIR__.'/../../lib/Exceptions/SafeExceptionInterface.php'; + require_once __DIR__.'/../../generated/Exceptions/FilesystemException.php'; + + + if (($handle = \fopen(__DIR__."/csv/test.csv", "r")) === false) { + throw new \RuntimeException('Test file could not be opened.'); + } + + while (($data = fgetcsv($handle, 1000, ",")) !== false) { + $this->assertEquals(['test', 'test'], $data); + } + \fclose($handle); + } + + public function testFgetcsvReturnFalseonEndOfFile() + { + require_once __DIR__.'/../../lib/special_cases.php'; + require_once __DIR__.'/../../lib/Exceptions/SafeExceptionInterface.php'; + require_once __DIR__.'/../../generated/Exceptions/FilesystemException.php'; + + + if (($handle = \fopen(__DIR__."/csv/test2.csv", "r")) === false) { + throw new \RuntimeException('Test file could not be opened.'); + } + + while (($data = fgetcsv($handle, 1000, ",")) !== false) { + $this->assertEquals(['test', 'test'], $data); + } + $this->assertEquals(false, $data); + \fclose($handle); + } + + /*public function testFgetcsvThrowsOnError() + { + require_once __DIR__.'/../../lib/special_cases.php'; + require_once __DIR__.'/../../lib/Exceptions/SafeExceptionInterface.php'; + require_once __DIR__.'/../../generated/Exceptions/FilesystemException.php'; + + if (($handle = \fopen(__DIR__."/csv/test3.csv", "r")) === false) { + throw new \RuntimeException('Test file could not be opened.'); + } + + $this->expectException(FilesystemException::class); + while (($data = fgetcsv($handle, 1000, ",")) !== false) { + echo var_export($data, true); + } + }*/ } diff --git a/generator/tests/csv/test.csv b/generator/tests/csv/test.csv new file mode 100644 index 00000000..5a1d59be --- /dev/null +++ b/generator/tests/csv/test.csv @@ -0,0 +1,2 @@ +test,test +test,test diff --git a/generator/tests/csv/test2.csv b/generator/tests/csv/test2.csv new file mode 100644 index 00000000..790c42bc --- /dev/null +++ b/generator/tests/csv/test2.csv @@ -0,0 +1,2 @@ +test,test +test,test \ No newline at end of file diff --git a/lib/special_cases.php b/lib/special_cases.php index 2f21ed00..a4e85a93 100644 --- a/lib/special_cases.php +++ b/lib/special_cases.php @@ -405,3 +405,38 @@ function fputcsv($stream, array $fields, string $separator = ",", string $enclos } return $result; } + +/** + * Similar to fgets except that + * fgetcsv parses the line it reads for fields in + * CSV format and returns an array containing the fields + * read. + * + * @param resource $stream A valid file pointer to a file successfully opened by + * fopen, popen, or + * fsockopen. + * @param int<0, max>|null $length Must be greater than the longest line (in characters) to be found in + * the CSV file (allowing for trailing line-end characters). Otherwise the + * line is split in chunks of length characters, + * unless the split would occur inside an enclosure. + * + * Omitting this parameter (or setting it to 0, + * or NULL in PHP 8.0.0 or later) the maximum line length is not limited, + * which is slightly slower. + * @param string $separator The optional separator parameter sets the field separator (one single-byte character only). + * @param string $enclosure The optional enclosure parameter sets the field enclosure character (one single-byte character only). + * @param string $escape The optional escape parameter sets the escape character (at most one single-byte character). + * An empty string ("") disables the proprietary escape mechanism. + * @return mixed[]|false Returns an indexed array containing the fields read on success or false when there is no more lines. + * @throws FilesystemException + * + */ +function fgetcsv($stream, int $length = null, string $separator = ",", string $enclosure = "\"", string $escape = "\\"): array|false +{ + error_clear_last(); + $safeResult = \fgetcsv($stream, $length, $separator, $enclosure, $escape); + if ($safeResult === false && \feof($stream) === false) { + throw FilesystemException::createFromPhpError(); + } + return $safeResult; +} diff --git a/rector-migrate.php b/rector-migrate.php index a7c7b475..2204db68 100644 --- a/rector-migrate.php +++ b/rector-migrate.php @@ -920,7 +920,6 @@ 'simplexml_import_dom' => 'Safe\simplexml_import_dom', 'simplexml_load_file' => 'Safe\simplexml_load_file', 'simplexml_load_string' => 'Safe\simplexml_load_string', - 'sleep' => 'Safe\sleep', 'socket_accept' => 'Safe\socket_accept', 'socket_addrinfo_bind' => 'Safe\socket_addrinfo_bind', 'socket_addrinfo_connect' => 'Safe\socket_addrinfo_connect',