Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: fgetcsv now returns false on end of file #388

Merged
merged 1 commit into from Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 0 additions & 46 deletions generated/filesystem.php
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions generator/config/specialCasesFunctions.php
Expand Up @@ -15,4 +15,5 @@
'simplexml_import_dom',
'simplexml_load_file',
'simplexml_load_string',
'fgetcsv', // This function need to return false when iterating on an end of file.
];
52 changes: 52 additions & 0 deletions generator/tests/SpecialCasesTest.php
Expand Up @@ -3,6 +3,7 @@
namespace Safe;

use PHPUnit\Framework\TestCase;
use Safe\Exceptions\FilesystemException;
use Safe\Exceptions\PcreException;

class SpecialCasesTest extends TestCase
Expand All @@ -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);
}
}*/
}
2 changes: 2 additions & 0 deletions generator/tests/csv/test.csv
@@ -0,0 +1,2 @@
test,test
test,test
2 changes: 2 additions & 0 deletions generator/tests/csv/test2.csv
@@ -0,0 +1,2 @@
test,test
test,test
35 changes: 35 additions & 0 deletions lib/special_cases.php
Expand Up @@ -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;
}