I have tried in many ways to create something efficient, however no way could validate everything, which ended up having to opt for while
even with fgets
(or fgetcsv
).
This format you want is basically the CSV, however this file format is not so advanced, it is impossible to limit the number of columns in a "practical" way, an example of checking would be this:
<?php
function validaCSV($arquivo, $limite = 3, $delimitador = ';', $tamanho = 0)
{
$handle = fopen($arquivo, 'rb');
$valido = true;
if ($handle) {
while (feof($handle) === false) {
$data = fgetcsv($handle, $tamanho, $delimitador);
if ($data && count($data) !== $limite) {
$valido = false; //Seta false
break;
}
}
fclose($handle);
} else {
$valido = true;
}
return $valido;
}
Usage example (expected column pattern is 3
):
var_dump(validaCSV('arquivo.txt')); //Checa se todas linhas tem 3 colunas
var_dump(validaCSV('arquivo.txt', 5)); //Checa se todas linhas tem 5 colunas
Will return true
if valid, otherwise return false
If you want to read the file, if it is valid, use the following:
To avoid memory peaks, if the file is invalid, I created two whiles, it is a bit slower but it will not consume both the server (in case of invalid files)
Note: In the example I used yield
so you can use it within a while
its own
function lerCSV($arquivo, $limite = 3, $delimitador = ';', $tamanho = 0)
{
$handle = fopen($arquivo, 'rb');
if ($handle) {
while (feof($handle) === false) {
$data = fgetcsv($handle, $tamanho, $delimitador);
if ($data && count($data) !== $limite) {
throw new Exception('O numero de colunas excedeu o limite de ' . $limite);
}
}
//Volta o ponteiro para o inicio do arquivo para poder usar novamente o while
rewind($handle);
while (feof($handle) === false) {
$data = fgetcsv($handle, $tamanho, $delimitador);
if ($data) { //Impede linhas vazias de retornarem false como valor
yield $data;
}
}
fclose($handle);
} else {
throw new Exception('Arquivo inválido: ' . $arquivo);
}
}
Example usage:
foreach(lerCSV('a.csv') as $linha) {
var_dump($linha);
}
It will issue Exception if the file is invalid / non-existent or if the line number is not determined in the function (default is 3
)
Extra (with SplFileObject
)
I was looking at the situation of the file being opened in the case of yield
, because if there is a break;
in foreach
, the file may not be closed, When the class is "destroyed" (will occur SplFileObject
(internal) of the class), then at this point the file will be "freed", as explained in this question:
The SPL version looks like this:
<?php
function SplLerCSV($arquivo, $limite = 3, $delimiter = ';', $enclosure = '"', $escape = '\')
{
$file = new SplFileObject($arquivo);
$minCol = $limite - 1;
while ($file->eof() === false) {
$data = $file->fgetcsv($delimiter, $enclosure, $escape);
if (isset($data[$minCol]) && count($data) !== $limite) {
throw new Exception('O numero de colunas excedeu o limite de ' . $limite);
}
}
//Volta o ponteiro para o inicio do arquivo para poder usar novamente o while
$file->rewind();
while ($file->eof() === false) {
$data = $file->fgetcsv($delimiter, $enclosure, $escape);
if (isset($data[$minCol])) { //Impede linhas vazias de retornarem [ 0 => NULL ] como valor
yield $data;
}
}
}
//Usando
foreach (SplLerCSV('a.csv') as $value) {
var_dump($value);
}