Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

273
vendor/league/csv/src/AbstractCsv.php vendored Normal file
View File

@@ -0,0 +1,273 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv;
use InvalidArgumentException;
use IteratorAggregate;
use JsonSerializable;
use League\Csv\Config\Controls;
use League\Csv\Config\Output;
use League\Csv\Modifier\QueryFilter;
use League\Csv\Modifier\StreamFilter;
use League\Csv\Modifier\StreamIterator;
use SplFileInfo;
use SplFileObject;
use SplTempFileObject;
/**
* An abstract class to enable basic CSV manipulation
*
* @package League.csv
* @since 4.0.0
*
*/
abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
{
use Controls;
use Output;
use QueryFilter;
use StreamFilter;
/**
* UTF-8 BOM sequence
*/
const BOM_UTF8 = "\xEF\xBB\xBF";
/**
* UTF-16 BE BOM sequence
*/
const BOM_UTF16_BE = "\xFE\xFF";
/**
* UTF-16 LE BOM sequence
*/
const BOM_UTF16_LE = "\xFF\xFE";
/**
* UTF-32 BE BOM sequence
*/
const BOM_UTF32_BE = "\x00\x00\xFE\xFF";
/**
* UTF-32 LE BOM sequence
*/
const BOM_UTF32_LE = "\xFF\xFE\x00\x00";
/**
* The path
*
* can be a StreamIterator object, a SplFileObject object or the string path to a file
*
* @var StreamIterator|SplFileObject|string
*/
protected $path;
/**
* The file open mode flag
*
* @var string
*/
protected $open_mode;
/**
* Creates a new instance
*
* The path must be an SplFileInfo object
* an object that implements the `__toString` method
* a path to a file
*
* @param StreamIterator|SplFileObject|string $path The file path
* @param string $open_mode The file open mode flag
*/
protected function __construct($path, $open_mode = 'r+')
{
$this->open_mode = strtolower($open_mode);
$this->path = $path;
$this->initStreamFilter($this->path);
}
/**
* The destructor
*/
public function __destruct()
{
$this->path = null;
}
/**
* Return a new {@link AbstractCsv} from a SplFileObject
*
* @param SplFileObject $file
*
* @return static
*/
public static function createFromFileObject(SplFileObject $file)
{
$csv = new static($file);
$controls = $file->getCsvControl();
$csv->setDelimiter($controls[0]);
$csv->setEnclosure($controls[1]);
if (isset($controls[2])) {
$csv->setEscape($controls[2]);
}
return $csv;
}
/**
* Return a new {@link AbstractCsv} from a PHP resource stream or a StreamIterator
*
* @param resource $stream
*
* @return static
*/
public static function createFromStream($stream)
{
return new static(new StreamIterator($stream));
}
/**
* Return a new {@link AbstractCsv} from a string
*
* The string must be an object that implements the `__toString` method,
* or a string
*
* @param string $str the string
*
* @return static
*/
public static function createFromString($str)
{
$file = new SplTempFileObject();
$file->fwrite(static::validateString($str));
return new static($file);
}
/**
* validate a string
*
* @param mixed $str the value to evaluate as a string
*
* @throws InvalidArgumentException if the submitted data can not be converted to string
*
* @return string
*/
protected static function validateString($str)
{
if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
return (string) $str;
}
throw new InvalidArgumentException('Expected data must be a string or stringable');
}
/**
* Return a new {@link AbstractCsv} from a file path
*
* @param mixed $path file path
* @param string $open_mode the file open mode flag
*
* @throws InvalidArgumentException If $path is a SplTempFileObject object
*
* @return static
*/
public static function createFromPath($path, $open_mode = 'r+')
{
if ($path instanceof SplTempFileObject) {
throw new InvalidArgumentException('an `SplTempFileObject` object does not contain a valid path');
}
if ($path instanceof SplFileInfo) {
$path = $path->getPath().'/'.$path->getBasename();
}
return new static(static::validateString($path), $open_mode);
}
/**
* Return a new {@link AbstractCsv} instance from another {@link AbstractCsv} object
*
* @param string $class the class to be instantiated
* @param string $open_mode the file open mode flag
*
* @return static
*/
protected function newInstance($class, $open_mode)
{
$csv = new $class($this->path, $open_mode);
$csv->delimiter = $this->delimiter;
$csv->enclosure = $this->enclosure;
$csv->escape = $this->escape;
$csv->input_encoding = $this->input_encoding;
$csv->input_bom = $this->input_bom;
$csv->output_bom = $this->output_bom;
$csv->newline = $this->newline;
return $csv;
}
/**
* Return a new {@link Writer} instance from a {@link AbstractCsv} object
*
* @param string $open_mode the file open mode flag
*
* @return Writer
*/
public function newWriter($open_mode = 'r+')
{
return $this->newInstance(Writer::class, $open_mode);
}
/**
* Return a new {@link Reader} instance from a {@link AbstractCsv} object
*
* @param string $open_mode the file open mode flag
*
* @return Reader
*/
public function newReader($open_mode = 'r+')
{
return $this->newInstance(Reader::class, $open_mode);
}
/**
* Returns the inner CSV Document Iterator object
*
* @return StreamIterator|SplFileObject
*/
public function getIterator()
{
$iterator = $this->setIterator();
$iterator->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
$iterator->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
return $iterator;
}
/**
* Set the Inner Iterator
*
* @return StreamIterator|SplFileObject
*/
protected function setIterator()
{
if ($this->path instanceof StreamIterator || $this->path instanceof SplFileObject) {
return $this->path;
}
return new SplFileObject($this->getStreamFilterPath(), $this->open_mode);
}
}

View File

@@ -0,0 +1,235 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Config;
use CallbackFilterIterator;
use InvalidArgumentException;
use LimitIterator;
use SplFileObject;
/**
* A trait to configure and check CSV file and content
*
* @package League.csv
* @since 6.0.0
*
*/
trait Controls
{
/**
* the field delimiter (one character only)
*
* @var string
*/
protected $delimiter = ',';
/**
* the field enclosure character (one character only)
*
* @var string
*/
protected $enclosure = '"';
/**
* the field escape character (one character only)
*
* @var string
*/
protected $escape = '\\';
/**
* newline character
*
* @var string
*/
protected $newline = "\n";
/**
* Sets the field delimiter
*
* @param string $delimiter
*
* @throws InvalidArgumentException If $delimiter is not a single character
*
* @return $this
*/
public function setDelimiter($delimiter)
{
if (!$this->isValidCsvControls($delimiter)) {
throw new InvalidArgumentException('The delimiter must be a single character');
}
$this->delimiter = $delimiter;
return $this;
}
/**
* Tell whether the submitted string is a valid CSV Control character
*
* @param string $str The submitted string
*
* @return bool
*/
protected function isValidCsvControls($str)
{
return 1 == mb_strlen($str);
}
/**
* Returns the current field delimiter
*
* @return string
*/
public function getDelimiter()
{
return $this->delimiter;
}
/**
* Detect Delimiters occurences in the CSV
*
* Returns a associative array where each key represents
* a valid delimiter and each value the number of occurences
*
* @param string[] $delimiters the delimiters to consider
* @param int $nb_rows Detection is made using $nb_rows of the CSV
*
* @return array
*/
public function fetchDelimitersOccurrence(array $delimiters, $nb_rows = 1)
{
$nb_rows = $this->validateInteger($nb_rows, 1, 'The number of rows to consider must be a valid positive integer');
$filter_row = function ($row) {
return is_array($row) && count($row) > 1;
};
$delimiters = array_unique(array_filter($delimiters, [$this, 'isValidCsvControls']));
$csv = $this->getIterator();
$res = [];
foreach ($delimiters as $delim) {
$csv->setCsvControl($delim, $this->enclosure, $this->escape);
$iterator = new CallbackFilterIterator(new LimitIterator($csv, 0, $nb_rows), $filter_row);
$res[$delim] = count(iterator_to_array($iterator, false), COUNT_RECURSIVE);
}
arsort($res, SORT_NUMERIC);
return $res;
}
/**
* Validate an integer
*
* @param int $int
* @param int $minValue
* @param string $errorMessage
*
* @throws InvalidArgumentException If the value is invalid
*
* @return int
*/
protected function validateInteger($int, $minValue, $errorMessage)
{
if (false === ($int = filter_var($int, FILTER_VALIDATE_INT, ['options' => ['min_range' => $minValue]]))) {
throw new InvalidArgumentException($errorMessage);
}
return $int;
}
/**
* Returns the CSV Iterator
*
* @return SplFileObject
*/
abstract public function getIterator();
/**
* Sets the field enclosure
*
* @param string $enclosure
*
* @throws InvalidArgumentException If $enclosure is not a single character
*
* @return $this
*/
public function setEnclosure($enclosure)
{
if (!$this->isValidCsvControls($enclosure)) {
throw new InvalidArgumentException('The enclosure must be a single character');
}
$this->enclosure = $enclosure;
return $this;
}
/**
* Returns the current field enclosure
*
* @return string
*/
public function getEnclosure()
{
return $this->enclosure;
}
/**
* Sets the field escape character
*
* @param string $escape
*
* @throws InvalidArgumentException If $escape is not a single character
*
* @return $this
*/
public function setEscape($escape)
{
if (!$this->isValidCsvControls($escape)) {
throw new InvalidArgumentException('The escape character must be a single character');
}
$this->escape = $escape;
return $this;
}
/**
* Returns the current field escape character
*
* @return string
*/
public function getEscape()
{
return $this->escape;
}
/**
* Sets the newline sequence characters
*
* @param string $newline
*
* @return static
*/
public function setNewline($newline)
{
$this->newline = (string) $newline;
return $this;
}
/**
* Returns the current newline sequence characters
*
* @return string
*/
public function getNewline()
{
return $this->newline;
}
}

309
vendor/league/csv/src/Config/Output.php vendored Normal file
View File

@@ -0,0 +1,309 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Config;
use DomDocument;
use InvalidArgumentException;
use Iterator;
use League\Csv\AbstractCsv;
use League\Csv\Modifier\MapIterator;
use SplFileObject;
/**
* A trait to output CSV
*
* @package League.csv
* @since 6.3.0
*
*/
trait Output
{
/**
* Charset Encoding for the CSV
*
* @var string
*/
protected $input_encoding = 'UTF-8';
/**
* The Input file BOM character
* @var string
*/
protected $input_bom;
/**
* The Output file BOM character
* @var string
*/
protected $output_bom = '';
/**
* Sets the CSV encoding charset
*
* @param string $str
*
* @return static
*/
public function setInputEncoding($str)
{
$str = str_replace('_', '-', $str);
$str = filter_var($str, FILTER_SANITIZE_STRING, ['flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH]);
if (empty($str)) {
throw new InvalidArgumentException('you should use a valid charset');
}
$this->input_encoding = strtoupper($str);
return $this;
}
/**
* Sets the CSV encoding charset
*
* DEPRECATION WARNING! This method will be removed in the next major point release
*
* @deprecated deprecated since version 8.1
*
* @param string $str
*
* @return static
*/
public function setEncodingFrom($str)
{
return $this->setInputEncoding($str);
}
/**
* Gets the source CSV encoding charset
*
* @return string
*/
public function getInputEncoding()
{
return $this->input_encoding;
}
/**
* Gets the source CSV encoding charset
*
* DEPRECATION WARNING! This method will be removed in the next major point release
*
* @deprecated deprecated since version 8.1
*
* @return string
*/
public function getEncodingFrom()
{
return $this->getInputEncoding();
}
/**
* Sets the BOM sequence to prepend the CSV on output
*
* @param string $str The BOM sequence
*
* @return static
*/
public function setOutputBOM($str)
{
if (empty($str)) {
$this->output_bom = '';
return $this;
}
$this->output_bom = (string) $str;
return $this;
}
/**
* Returns the BOM sequence in use on Output methods
*
* @return string
*/
public function getOutputBOM()
{
return $this->output_bom;
}
/**
* Returns the BOM sequence of the given CSV
*
* @return string
*/
public function getInputBOM()
{
if (null === $this->input_bom) {
$bom = [
AbstractCsv::BOM_UTF32_BE, AbstractCsv::BOM_UTF32_LE,
AbstractCsv::BOM_UTF16_BE, AbstractCsv::BOM_UTF16_LE, AbstractCsv::BOM_UTF8,
];
$csv = $this->getIterator();
$csv->setFlags(SplFileObject::READ_CSV);
$csv->rewind();
$line = $csv->fgets();
$res = array_filter($bom, function ($sequence) use ($line) {
return strpos($line, $sequence) === 0;
});
$this->input_bom = (string) array_shift($res);
}
return $this->input_bom;
}
/**
* @inheritdoc
*/
abstract public function getIterator();
/**
* Outputs all data on the CSV file
*
* @param string $filename CSV downloaded name if present adds extra headers
*
* @return int Returns the number of characters read from the handle
* and passed through to the output.
*/
public function output($filename = null)
{
if (null !== $filename) {
$filename = filter_var($filename, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
header('Content-Type: text/csv');
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=\"$filename\"");
}
return $this->fpassthru();
}
/**
* Outputs all data from the CSV
*
* @return int Returns the number of characters read from the handle
* and passed through to the output.
*/
protected function fpassthru()
{
$bom = '';
$input_bom = $this->getInputBOM();
if ($this->output_bom && $input_bom != $this->output_bom) {
$bom = $this->output_bom;
}
$csv = $this->getIterator();
$csv->setFlags(SplFileObject::READ_CSV);
$csv->rewind();
if (!empty($bom)) {
$csv->fseek(mb_strlen($input_bom));
}
echo $bom;
$res = $csv->fpassthru();
return $res + strlen($bom);
}
/**
* Retrieves the CSV content
*
* @return string
*/
public function __toString()
{
ob_start();
$this->fpassthru();
return ob_get_clean();
}
/**
* @inheritdoc
*/
public function jsonSerialize()
{
return iterator_to_array($this->convertToUtf8($this->getQueryIterator()), false);
}
/**
* Returns the CSV Iterator
*
* @return Iterator
*/
abstract protected function getQueryIterator();
/**
* Convert Csv file into UTF-8
*
* @param Iterator $iterator
*
* @return Iterator
*/
protected function convertToUtf8(Iterator $iterator)
{
if (stripos($this->input_encoding, 'UTF-8') !== false) {
return $iterator;
}
$convert_cell = function ($value) {
return mb_convert_encoding($value, 'UTF-8', $this->input_encoding);
};
$convert_row = function (array $row) use ($convert_cell) {
return array_map($convert_cell, $row);
};
return new MapIterator($iterator, $convert_row);
}
/**
* Returns a HTML table representation of the CSV Table
*
* @param string $class_attr optional classname
*
* @return string
*/
public function toHTML($class_attr = 'table-csv-data')
{
$doc = $this->toXML('table', 'tr', 'td');
$doc->documentElement->setAttribute('class', $class_attr);
return $doc->saveHTML($doc->documentElement);
}
/**
* Transforms a CSV into a XML
*
* @param string $root_name XML root node name
* @param string $row_name XML row node name
* @param string $cell_name XML cell node name
*
* @return DomDocument
*/
public function toXML($root_name = 'csv', $row_name = 'row', $cell_name = 'cell')
{
$doc = new DomDocument('1.0', 'UTF-8');
$root = $doc->createElement($root_name);
foreach ($this->convertToUtf8($this->getQueryIterator()) as $row) {
$rowElement = $doc->createElement($row_name);
array_walk($row, function ($value) use (&$rowElement, $doc, $cell_name) {
$content = $doc->createTextNode($value);
$cell = $doc->createElement($cell_name);
$cell->appendChild($content);
$rowElement->appendChild($cell);
});
$root->appendChild($rowElement);
}
$doc->appendChild($root);
return $doc;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Exception;
use InvalidArgumentException;
/**
* Thrown when a data is not validated prior to insertion
*
* @package League.csv
* @since 7.0.0
*
*/
class InvalidRowException extends InvalidArgumentException
{
/**
* Validator which did not validated the data
* @var string
*/
private $name;
/**
* Validator Data which caused the error
* @var array
*/
private $data;
/**
* New Instance
*
* @param string $name validator name
* @param array $data invalid data
* @param string $message exception message
*/
public function __construct($name, array $data = [], $message = '')
{
parent::__construct($message);
$this->name = $name;
$this->data = $data;
}
/**
* return the validator name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* return the invalid data submitted
*
* @return array
*/
public function getData()
{
return $this->data;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Modifier;
use Iterator;
use IteratorIterator;
/**
* A simple MapIterator
*
* @package League.csv
* @since 3.3.0
* @internal used internally to modify CSV content
*
*/
class MapIterator extends IteratorIterator
{
/**
* The function to be apply on all InnerIterator element
*
* @var callable
*/
private $callable;
/**
* The Constructor
*
* @param Iterator $iterator
* @param callable $callable
*/
public function __construct(Iterator $iterator, callable $callable)
{
parent::__construct($iterator);
$this->callable = $callable;
}
/**
* Get the value of the current element
*/
public function current()
{
$iterator = $this->getInnerIterator();
return call_user_func($this->callable, $iterator->current(), $iterator->key(), $iterator);
}
}

View File

@@ -0,0 +1,298 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Modifier;
use ArrayIterator;
use CallbackFilterIterator;
use Iterator;
use LimitIterator;
/**
* A Trait to Query rows against a SplFileObject
*
* @package League.csv
* @since 4.2.1
*
*/
trait QueryFilter
{
/**
* Callables to filter the iterator
*
* @var callable[]
*/
protected $iterator_filters = [];
/**
* Callables to sort the iterator
*
* @var callable[]
*/
protected $iterator_sort_by = [];
/**
* iterator Offset
*
* @var int
*/
protected $iterator_offset = 0;
/**
* iterator maximum length
*
* @var int
*/
protected $iterator_limit = -1;
/**
* Stripping BOM status
*
* @var boolean
*/
protected $strip_bom = false;
/**
* Stripping BOM setter
*
* @param bool $status
*
* @return $this
*/
public function stripBom($status)
{
$this->strip_bom = (bool) $status;
return $this;
}
/**
* @inheritdoc
*/
abstract public function getInputBOM();
/**
* Set LimitIterator Offset
*
* @param $offset
*
* @return $this
*/
public function setOffset($offset = 0)
{
$this->iterator_offset = $this->validateInteger($offset, 0, 'the offset must be a positive integer or 0');
return $this;
}
/**
* @inheritdoc
*/
abstract protected function validateInteger($int, $minValue, $errorMessage);
/**
* Set LimitIterator Count
*
* @param int $limit
*
* @return $this
*/
public function setLimit($limit = -1)
{
$this->iterator_limit = $this->validateInteger($limit, -1, 'the limit must an integer greater or equals to -1');
return $this;
}
/**
* Set an Iterator sorting callable function
*
* @param callable $callable
*
* @return $this
*/
public function addSortBy(callable $callable)
{
$this->iterator_sort_by[] = $callable;
return $this;
}
/**
* Set the Iterator filter method
*
* @param callable $callable
*
* @return $this
*/
public function addFilter(callable $callable)
{
$this->iterator_filters[] = $callable;
return $this;
}
/**
* @inheritdoc
*/
abstract public function getEnclosure();
/**
* Returns the CSV Iterator
*
* @return Iterator
*/
protected function getQueryIterator()
{
$normalizedCsv = function ($row) {
return is_array($row) && $row != [null];
};
array_unshift($this->iterator_filters, $normalizedCsv);
$iterator = $this->getIterator();
$iterator = $this->applyBomStripping($iterator);
$iterator = $this->applyIteratorFilter($iterator);
$iterator = $this->applyIteratorSortBy($iterator);
$iterator = $this->applyIteratorInterval($iterator);
return $iterator;
}
/**
* @inheritdoc
*/
abstract public function getIterator();
/**
* Remove the BOM sequence from the CSV
*
* @param Iterator $iterator
*
* @return Iterator
*/
protected function applyBomStripping(Iterator $iterator)
{
if (!$this->strip_bom) {
return $iterator;
}
if (!$this->isBomStrippable()) {
$this->strip_bom = false;
return $iterator;
}
$this->strip_bom = false;
return $this->getStripBomIterator($iterator);
}
/**
* Tell whether we can strip or not the leading BOM sequence
*
* @return bool
*/
protected function isBomStrippable()
{
return !empty($this->getInputBOM()) && $this->strip_bom;
}
/**
* Return the Iterator without the BOM sequence
*
* @param Iterator $iterator
*
* @return Iterator
*/
protected function getStripBomIterator(Iterator $iterator)
{
$bom_length = mb_strlen($this->getInputBOM());
$enclosure = $this->getEnclosure();
$strip_bom = function ($row, $index) use ($bom_length, $enclosure) {
if (0 != $index) {
return $row;
}
$row[0] = mb_substr($row[0], $bom_length);
if (mb_substr($row[0], 0, 1) === $enclosure && mb_substr($row[0], -1, 1) === $enclosure) {
$row[0] = mb_substr($row[0], 1, -1);
}
return $row;
};
return new MapIterator($iterator, $strip_bom);
}
/**
* Filter the Iterator
*
* @param Iterator $iterator
*
* @return Iterator
*/
protected function applyIteratorFilter(Iterator $iterator)
{
$reducer = function ($iterator, $callable) {
return new CallbackFilterIterator($iterator, $callable);
};
$iterator = array_reduce($this->iterator_filters, $reducer, $iterator);
$this->iterator_filters = [];
return $iterator;
}
/**
* Sort the Iterator
*
* @param Iterator $iterator
*
* @return Iterator
*/
protected function applyIteratorSortBy(Iterator $iterator)
{
if (!$this->iterator_sort_by) {
return $iterator;
}
$obj = new ArrayIterator(iterator_to_array($iterator));
$obj->uasort(function ($row_a, $row_b) {
$res = 0;
foreach ($this->iterator_sort_by as $compare) {
if (0 !== ($res = call_user_func($compare, $row_a, $row_b))) {
break;
}
}
return $res;
});
$this->iterator_sort_by = [];
return $obj;
}
/**
* Sort the Iterator
*
* @param Iterator $iterator
*
* @return Iterator
*/
protected function applyIteratorInterval(Iterator $iterator)
{
$offset = $this->iterator_offset;
$limit = $this->iterator_limit;
$this->iterator_limit = -1;
$this->iterator_offset = 0;
return new LimitIterator($iterator, $offset, $limit);
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Modifier;
use League\Csv\Exception\InvalidRowException;
/**
* Trait to format and validate the row before insertion
*
* @package League.csv
* @since 7.0.0
*
*/
trait RowFilter
{
/**
* Callables to validate the row before insertion
*
* @var callable[]
*/
protected $validators = [];
/**
* Callables to format the row before insertion
*
* @var callable[]
*/
protected $formatters = [];
/**
* add a formatter to the collection
*
* @param callable $callable
*
* @return $this
*/
public function addFormatter(callable $callable)
{
$this->formatters[] = $callable;
return $this;
}
/**
* Remove a formatter from the collection
*
* @param callable $callable
*
* @return $this
*/
public function removeFormatter(callable $callable)
{
$res = array_search($callable, $this->formatters, true);
unset($this->formatters[$res]);
return $this;
}
/**
* Detect if the formatter is already registered
*
* @param callable $callable
*
* @return bool
*/
public function hasFormatter(callable $callable)
{
return false !== array_search($callable, $this->formatters, true);
}
/**
* Remove all registered formatter
*
* @return $this
*/
public function clearFormatters()
{
$this->formatters = [];
return $this;
}
/**
* add a Validator to the collection
*
* @param callable $callable
* @param string $name the rule name
*
* @return $this
*/
public function addValidator(callable $callable, $name)
{
$name = $this->validateString($name);
$this->validators[$name] = $callable;
return $this;
}
/**
* @inheritdoc
*/
abstract protected function validateString($str);
/**
* Remove a validator from the collection
*
* @param string $name the validator name
*
* @return $this
*/
public function removeValidator($name)
{
$name = $this->validateString($name);
unset($this->validators[$name]);
return $this;
}
/**
* Detect if a validator is already registered
*
* @param string $name the validator name
*
* @return bool
*/
public function hasValidator($name)
{
$name = $this->validateString($name);
return isset($this->validators[$name]);
}
/**
* Remove all registered validators
*
* @return $this
*/
public function clearValidators()
{
$this->validators = [];
return $this;
}
/**
* Format the given row
*
* @param array $row
*
* @return array
*/
protected function formatRow(array $row)
{
foreach ($this->formatters as $formatter) {
$row = call_user_func($formatter, $row);
}
return $row;
}
/**
* Validate a row
*
* @param array $row
*
* @throws InvalidRowException If the validation failed
*/
protected function validateRow(array $row)
{
foreach ($this->validators as $name => $validator) {
if (true !== call_user_func($validator, $row)) {
throw new InvalidRowException($name, $row, 'row validation failed');
}
}
}
}

View File

@@ -0,0 +1,299 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Modifier;
use LogicException;
use OutOfBoundsException;
use SplFileObject;
/**
* A Trait to ease PHP Stream Filters manipulation
* with a SplFileObject
*
* @package League.csv
* @since 6.0.0
*
*/
trait StreamFilter
{
/**
* collection of stream filters
*
* @var array
*/
protected $stream_filters = [];
/**
* Stream filtering mode to apply on all filters
*
* @var int
*/
protected $stream_filter_mode = STREAM_FILTER_ALL;
/**
*the real path
*
* @var string the real path to the file
*
*/
protected $stream_uri;
/**
* PHP Stream Filter Regex
*
* @var string
*/
protected $stream_regex = ',^
php://filter/
(?P<mode>:?read=|write=)? # The resource open mode
(?P<filters>.*?) # The resource registered filters
/resource=(?P<resource>.*) # The resource path
$,ix';
/**
* Internal path setter
*
* The path must be an SplFileInfo object
* an object that implements the `__toString` method
* a path to a file
*
* @param StreamIterator|SplFileObject|string $path The file path
*/
protected function initStreamFilter($path)
{
$this->stream_filters = [];
if (!is_string($path)) {
$this->stream_uri = null;
return;
}
if (!preg_match($this->stream_regex, $path, $matches)) {
$this->stream_uri = $path;
return;
}
$this->stream_uri = $matches['resource'];
$this->stream_filters = array_map('urldecode', explode('|', $matches['filters']));
$this->stream_filter_mode = $this->fetchStreamModeAsInt($matches['mode']);
}
/**
* Get the stream mode
*
* @param string $mode
*
* @return int
*/
protected function fetchStreamModeAsInt($mode)
{
$mode = strtolower($mode);
$mode = rtrim($mode, '=');
if ('write' == $mode) {
return STREAM_FILTER_WRITE;
}
if ('read' == $mode) {
return STREAM_FILTER_READ;
}
return STREAM_FILTER_ALL;
}
/**
* Check if the trait methods can be used
*
* @throws LogicException If the API can not be use
*/
protected function assertStreamable()
{
if (!is_string($this->stream_uri)) {
throw new LogicException('The stream filter API can not be used');
}
}
/**
* Tells whether the stream filter capabilities can be used
*
* @return bool
*/
public function isActiveStreamFilter()
{
return is_string($this->stream_uri);
}
/**
* stream filter mode Setter
*
* Set the new Stream Filter mode and remove all
* previously attached stream filters
*
* @param int $mode
*
* @throws OutOfBoundsException If the mode is invalid
*
* @return $this
*/
public function setStreamFilterMode($mode)
{
$this->assertStreamable();
if (!in_array($mode, [STREAM_FILTER_ALL, STREAM_FILTER_READ, STREAM_FILTER_WRITE])) {
throw new OutOfBoundsException('the $mode should be a valid `STREAM_FILTER_*` constant');
}
$this->stream_filter_mode = $mode;
$this->stream_filters = [];
return $this;
}
/**
* stream filter mode getter
*
* @return int
*/
public function getStreamFilterMode()
{
$this->assertStreamable();
return $this->stream_filter_mode;
}
/**
* append a stream filter
*
* @param string $filter_name a string or an object that implements the '__toString' method
*
* @return $this
*/
public function appendStreamFilter($filter_name)
{
$this->assertStreamable();
$this->stream_filters[] = $this->sanitizeStreamFilter($filter_name);
return $this;
}
/**
* prepend a stream filter
*
* @param string $filter_name a string or an object that implements the '__toString' method
*
* @return $this
*/
public function prependStreamFilter($filter_name)
{
$this->assertStreamable();
array_unshift($this->stream_filters, $this->sanitizeStreamFilter($filter_name));
return $this;
}
/**
* Sanitize the stream filter name
*
* @param string $filter_name the stream filter name
*
* @return string
*/
protected function sanitizeStreamFilter($filter_name)
{
return urldecode($this->validateString($filter_name));
}
/**
* @inheritdoc
*/
abstract public function validateString($str);
/**
* Detect if the stream filter is already present
*
* @param string $filter_name
*
* @return bool
*/
public function hasStreamFilter($filter_name)
{
$this->assertStreamable();
return false !== array_search(urldecode($filter_name), $this->stream_filters, true);
}
/**
* Remove a filter from the collection
*
* @param string $filter_name
*
* @return $this
*/
public function removeStreamFilter($filter_name)
{
$this->assertStreamable();
$res = array_search(urldecode($filter_name), $this->stream_filters, true);
if (false !== $res) {
unset($this->stream_filters[$res]);
}
return $this;
}
/**
* Remove all registered stream filter
*
* @return $this
*/
public function clearStreamFilter()
{
$this->assertStreamable();
$this->stream_filters = [];
return $this;
}
/**
* Return the filter path
*
* @return string
*/
protected function getStreamFilterPath()
{
$this->assertStreamable();
if (!$this->stream_filters) {
return $this->stream_uri;
}
return 'php://filter/'
.$this->getStreamFilterPrefix()
.implode('|', array_map('urlencode', $this->stream_filters))
.'/resource='.$this->stream_uri;
}
/**
* Return PHP stream filter prefix
*
* @return string
*/
protected function getStreamFilterPrefix()
{
if (STREAM_FILTER_READ == $this->stream_filter_mode) {
return 'read=';
}
if (STREAM_FILTER_WRITE == $this->stream_filter_mode) {
return 'write=';
}
return '';
}
}

View File

@@ -0,0 +1,334 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Modifier;
use InvalidArgumentException;
use Iterator;
use SplFileObject;
/**
* A Stream Iterator
*
* @package League.csv
* @since 8.2.0
* @internal used internally to iterate over a stream resource
*
*/
class StreamIterator implements Iterator
{
/**
* Stream pointer
*
* @var resource
*/
protected $stream;
/**
* Current iterator value
*
* @var mixed
*/
protected $current_line;
/**
* Current iterator key
*
* @var int
*/
protected $current_line_number;
/**
* Flags for the StreamIterator
*
* @var int
*/
protected $flags = 0;
/**
* the field delimiter (one character only)
*
* @var string
*/
protected $delimiter = ',';
/**
* the field enclosure character (one character only)
*
* @var string
*/
protected $enclosure = '"';
/**
* the field escape character (one character only)
*
* @var string
*/
protected $escape = '\\';
/**
* New instance
*
* @param resource $stream stream type resource
*/
public function __construct($stream)
{
if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new InvalidArgumentException(sprintf(
'Expected resource to be a stream, received %s instead',
is_object($stream) ? get_class($stream) : gettype($stream)
));
}
$data = stream_get_meta_data($stream);
if (!$data['seekable']) {
throw new InvalidArgumentException('The stream must be seekable');
}
$this->stream = $stream;
}
/**
* Set CSV control
*
* @see http://php.net/manual/en/splfileobject.setcsvcontrol.php
*
* @param string $delimiter
* @param string $enclosure
* @param string $escape
*/
public function setCsvControl($delimiter = ',', $enclosure = '"', $escape = '\\')
{
$this->delimiter = $this->filterControl($delimiter, 'delimiter');
$this->enclosure = $this->filterControl($enclosure, 'enclosure');
$this->escape = $this->filterControl($escape, 'escape');
}
/**
* Filter Csv control character
*
* @param string $char Csv control character
* @param string $type Csv control character type
*
* @throws InvalidArgumentException If the Csv control character is not one character only.
*
* @return string
*/
private function filterControl($char, $type)
{
if (1 == strlen($char)) {
return $char;
}
throw new InvalidArgumentException(sprintf('The %s character must be a single character', $type));
}
/**
* Set Flags
*
* @see http://php.net/manual/en/splfileobject.setflags.php
*
* @param int $flags
*/
public function setFlags($flags)
{
if (false === filter_var($flags, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
throw new InvalidArgumentException('The flags must be a positive integer');
}
$this->flags = $flags;
}
/**
* Write a field array as a CSV line
*
* @see http://php.net/manual/en/splfileobject.fputcsv.php
*
* @param array $fields
* @param string $delimiter
* @param string $enclosure
* @param string $escape
*
* @return int
*/
public function fputcsv(array $fields, $delimiter = ',', $enclosure = '"', $escape = '\\')
{
return fputcsv(
$this->stream,
$fields,
$this->filterControl($delimiter, 'delimiter'),
$this->filterControl($enclosure, 'enclosure'),
$this->filterControl($escape, 'escape')
);
}
/**
* Retrieves the current line of the file.
*
* @return mixed
*/
public function current()
{
if (false !== $this->current_line) {
return $this->current_line;
}
if (($this->flags & SplFileObject::READ_CSV) == SplFileObject::READ_CSV) {
$this->current_line = $this->getCurrentRecord();
return $this->current_line;
}
$this->current_line = $this->getCurrentLine();
return $this->current_line;
}
/**
* Retrieves the current line as a CSV Record
*
* @return array
*/
protected function getCurrentRecord()
{
do {
$ret = fgetcsv($this->stream, 0, $this->delimiter, $this->enclosure, $this->escape);
} while ($this->flags & SplFileObject::SKIP_EMPTY && $ret !== false && $ret[0] === null);
return $ret;
}
/**
* Retrieves the current line as a string
*
* @return string
*/
protected function getCurrentLine()
{
do {
$line = fgets($this->stream);
} while ($this->flags & SplFileObject::SKIP_EMPTY && $line !== false && rtrim($line, "\r\n") !== '');
return $line;
}
/**
* Get line number
*
* @return int
*/
public function key()
{
return $this->current_line_number;
}
/**
* Read next line
*/
public function next()
{
$this->current_line = false;
$this->current_line_number++;
}
/**
* Rewind the file to the first line
*/
public function rewind()
{
rewind($this->stream);
$this->current_line_number = 0;
$this->current_line = false;
if ($this->flags & SplFileObject::READ_AHEAD) {
$this->current();
}
}
/**
* Not at EOF
*
* @return bool
*/
public function valid()
{
if ($this->flags & SplFileObject::READ_AHEAD) {
return $this->current() !== false;
}
return !feof($this->stream);
}
/**
* Gets line from file
*
* @see http://php.net/manual/en/splfileobject.fgets.php
*
* @return string
*/
public function fgets()
{
if (false !== $this->current_line) {
$this->next();
}
return $this->current_line = $this->getCurrentLine();
}
/**
* Output all remaining data on a file pointer
*
* @see http://php.net/manual/en/splfileobject.fpatssthru.php
*
* @return int
*/
public function fpassthru()
{
return fpassthru($this->stream);
}
/**
* Seek to a position
*
* @see http://php.net/manual/en/splfileobject.fseek.php
*
* @param int $offset
* @param int $whence
*
* @return int
*/
public function fseek($offset, $whence = SEEK_SET)
{
return fseek($this->stream, $offset, $whence);
}
/**
* Write to stream
*
* @see http://php.net/manual/en/splfileobject.fwrite.php
*
* @param string $str
* @param int $length
*
* @return int
*/
public function fwrite($str, $length = 0)
{
return fwrite($this->stream, $str, $length);
}
/**
* close the file pointer
*/
public function __destruct()
{
$this->stream = null;
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Plugin;
use InvalidArgumentException;
/**
* A class to manage column consistency on data insertion into a CSV
*
* @package League.csv
* @since 7.0.0
*
*/
class ColumnConsistencyValidator
{
/**
* The number of column per row
*
* @var int
*/
private $columns_count = -1;
/**
* should the class detect the column count based the inserted row
*
* @var bool
*/
private $detect_columns_count = false;
/**
* Set Inserted row column count
*
* @param int $value
*
* @throws InvalidArgumentException If $value is lesser than -1
*
*/
public function setColumnsCount($value)
{
if (false === filter_var($value, FILTER_VALIDATE_INT, ['options' => ['min_range' => -1]])) {
throw new InvalidArgumentException('the column count must an integer greater or equals to -1');
}
$this->detect_columns_count = false;
$this->columns_count = $value;
}
/**
* Column count getter
*
* @return int
*/
public function getColumnsCount()
{
return $this->columns_count;
}
/**
* The method will set the $columns_count property according to the next inserted row
* and therefore will also validate the next line whatever length it has no matter
* the current $columns_count property value.
*
*/
public function autodetectColumnsCount()
{
$this->detect_columns_count = true;
}
/**
* Is the submitted row valid
*
* @param array $row
*
* @return bool
*/
public function __invoke(array $row)
{
if ($this->detect_columns_count) {
$this->columns_count = count($row);
$this->detect_columns_count = false;
return true;
}
if (-1 == $this->columns_count) {
return true;
}
return count($row) === $this->columns_count;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Plugin;
/**
* A class to validate null value handling on data insertion into a CSV
*
* @package League.csv
* @since 7.0.0
*
*/
class ForbiddenNullValuesValidator
{
/**
* Is the submitted row valid
*
* @param array $row
*
* @return bool
*/
public function __invoke(array $row)
{
$res = array_filter($row, function ($value) {
return null === $value;
});
return !$res;
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv\Plugin;
/**
* A class to remove null value from data before insertion into a CSV
*
* @package League.csv
* @since 7.0.0
*
*/
class SkipNullValuesFormatter
{
/**
* remove null value form the submitted array
*
* @param array $row
*
* @return array
*/
public function __invoke(array $row)
{
return array_filter($row, function ($value) {
return null !== $value;
});
}
}

362
vendor/league/csv/src/Reader.php vendored Normal file
View File

@@ -0,0 +1,362 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv;
use Generator;
use InvalidArgumentException;
use Iterator;
use League\Csv\Modifier\MapIterator;
use LimitIterator;
/**
* A class to manage extracting and filtering a CSV
*
* @package League.csv
* @since 3.0.0
*
*/
class Reader extends AbstractCsv
{
/**
* @inheritdoc
*/
protected $stream_filter_mode = STREAM_FILTER_READ;
/**
* Returns a sequential array of all CSV lines
*
* The callable function will be applied to each Iterator item
*
* @param callable|null $callable a callable function
*
* @return array
*/
public function fetchAll(callable $callable = null)
{
return iterator_to_array($this->applyCallable($this->getQueryIterator(), $callable), false);
}
/**
* Fetch the next row from a result set
*
* @param callable|null $callable a callable function to be applied to each Iterator item
*
* @return Iterator
*/
public function fetch(callable $callable = null)
{
return $this->applyCallable($this->getQueryIterator(), $callable);
}
/**
* Apply The callable function
*
* @param Iterator $iterator
* @param callable|null $callable
*
* @return Iterator
*/
protected function applyCallable(Iterator $iterator, callable $callable = null)
{
if (null !== $callable) {
return new MapIterator($iterator, $callable);
}
return $iterator;
}
/**
* Applies a callback function on the CSV
*
* The callback function must return TRUE in order to continue
* iterating over the iterator.
*
* @param callable $callable a callable function to apply to each selected CSV rows
*
* @return int the iteration count
*/
public function each(callable $callable)
{
$index = 0;
$iterator = $this->getQueryIterator();
$iterator->rewind();
while ($iterator->valid() && true === call_user_func(
$callable,
$iterator->current(),
$iterator->key(),
$iterator
)) {
++$index;
$iterator->next();
}
return $index;
}
/**
* Returns a single row from the CSV
*
* By default if no offset is provided the first row of the CSV is selected
*
* @param int $offset the CSV row offset
*
* @return array
*/
public function fetchOne($offset = 0)
{
$this->setOffset($offset);
$this->setLimit(1);
$iterator = $this->getQueryIterator();
$iterator->rewind();
return (array) $iterator->current();
}
/**
* Returns the next value from a single CSV column
*
* The callable function will be applied to each value to be return
*
* By default if no column index is provided the first column of the CSV is selected
*
* @param int $column_index CSV column index
* @param callable|null $callable A callable to be applied to each of the value to be returned.
*
* @return Iterator
*/
public function fetchColumn($column_index = 0, callable $callable = null)
{
$column_index = $this->validateInteger($column_index, 0, 'the column index must be a positive integer or 0');
$filter_column = function ($row) use ($column_index) {
return isset($row[$column_index]);
};
$select_column = function ($row) use ($column_index) {
return $row[$column_index];
};
$this->addFilter($filter_column);
return $this->applyCallable(new MapIterator($this->getQueryIterator(), $select_column), $callable);
}
/**
* Retrieve CSV data as pairs
*
* DEPRECATION WARNING! This method will be removed in the next major point release
*
* @deprecated deprecated since version 8.2
* @see Reader::fetchPairs
*
* Fetches an associative array of all rows as key-value pairs (first
* column is the key, second column is the value).
*
* By default if no column index is provided:
* - the first CSV column is used to provide the keys
* - the second CSV column is used to provide the value
*
* If the value from the column key index is duplicated its corresponding value will
* be overwritten
*
* @param int $offset_index The column index to serve as offset
* @param int $value_index The column index to serve as value
* @param callable|null $callable A callable to be applied to each of the rows to be returned.
*
* @return array
*/
public function fetchPairsWithoutDuplicates($offset_index = 0, $value_index = 1, callable $callable = null)
{
return iterator_to_array($this->fetchPairs($offset_index, $value_index, $callable), true);
}
/**
* Fetches the next key-value pairs from a result set (first
* column is the key, second column is the value).
*
* By default if no column index is provided:
* - the first CSV column is used to provide the keys
* - the second CSV column is used to provide the value
*
* @param int $offset_index The column index to serve as offset
* @param int $value_index The column index to serve as value
* @param callable|null $callable A callable to be applied to each of the rows to be returned.
*
* @return Generator
*/
public function fetchPairs($offset_index = 0, $value_index = 1, callable $callable = null)
{
$offset_index = $this->validateInteger($offset_index, 0, 'the offset column index must be a positive integer or 0');
$value_index = $this->validateInteger($value_index, 0, 'the value column index must be a positive integer or 0');
$filter_pairs = function ($row) use ($offset_index) {
return isset($row[$offset_index]);
};
$select_pairs = function ($row) use ($offset_index, $value_index) {
return [
$row[$offset_index],
isset($row[$value_index]) ? $row[$value_index] : null,
];
};
$this->addFilter($filter_pairs);
$iterator = $this->applyCallable(new MapIterator($this->getQueryIterator(), $select_pairs), $callable);
foreach ($iterator as $row) {
yield $row[0] => $row[1];
}
}
/**
* Fetch the next row from a result set
*
* The rows are presented as associated arrays
* The callable function will be applied to each row
*
* @param int|array $offset_or_keys the name for each key member OR the row Index to be
* used as the associated named keys
*
* @param callable $callable A callable to be applied to each of the rows to be returned.
*
* @throws InvalidArgumentException If the submitted keys are invalid
*
* @return Iterator
*/
public function fetchAssoc($offset_or_keys = 0, callable $callable = null)
{
$keys = $this->getAssocKeys($offset_or_keys);
$keys_count = count($keys);
$combine_array = function (array $row) use ($keys, $keys_count) {
if ($keys_count != count($row)) {
$row = array_slice(array_pad($row, $keys_count, null), 0, $keys_count);
}
return array_combine($keys, $row);
};
return $this->applyCallable(new MapIterator($this->getQueryIterator(), $combine_array), $callable);
}
/**
* Selects the array to be used as key for the fetchAssoc method
*
* @param int|array $offset_or_keys the assoc key OR the row Index to be used
* as the key index
*
* @throws InvalidArgumentException If the row index and/or the resulting array is invalid
*
* @return array
*/
protected function getAssocKeys($offset_or_keys)
{
if (is_array($offset_or_keys)) {
return $this->validateKeys($offset_or_keys);
}
$offset_or_keys = $this->validateInteger(
$offset_or_keys,
0,
'the row index must be a positive integer, 0 or a non empty array'
);
$keys = $this->validateKeys($this->getRow($offset_or_keys));
$filterOutRow = function ($row, $rowIndex) use ($offset_or_keys) {
return $rowIndex != $offset_or_keys;
};
$this->addFilter($filterOutRow);
return $keys;
}
/**
* Validates the array to be used by the fetchAssoc method
*
* @param array $keys
*
* @throws InvalidArgumentException If the submitted array fails the assertion
*
* @return array
*/
protected function validateKeys(array $keys)
{
if (empty($keys) || $keys !== array_unique(array_filter($keys, [$this, 'isValidKey']))) {
throw new InvalidArgumentException('Use a flat array with unique string values');
}
return $keys;
}
/**
* Returns whether the submitted value can be used as string
*
* @param mixed $value
*
* @return bool
*/
protected function isValidKey($value)
{
return is_scalar($value) || (is_object($value) && method_exists($value, '__toString'));
}
/**
* Returns a single row from the CSV without filtering
*
* @param int $offset
*
* @throws InvalidArgumentException If the $offset is not valid or the row does not exist
*
* @return array
*/
protected function getRow($offset)
{
$row = $this->seekRow($offset);
if (empty($row)) {
throw new InvalidArgumentException('the specified row does not exist or is empty');
}
if (0 !== $offset || !$this->isBomStrippable()) {
return $row;
}
$bom_length = mb_strlen($this->getInputBOM());
$row[0] = mb_substr($row[0], $bom_length);
if ($this->enclosure == mb_substr($row[0], 0, 1) && $this->enclosure == mb_substr($row[0], -1, 1)) {
$row[0] = mb_substr($row[0], 1, -1);
}
return $row;
}
/**
* Returns the row at a given offset
*
* @param int $offset
*
* @return mixed
*/
protected function seekRow($offset)
{
$stream = $this->getIterator();
$stream->rewind();
//Workaround for SplFileObject::seek bug in PHP7.2+ see https://bugs.php.net/bug.php?id=75917
if (PHP_VERSION_ID > 70200 && !$stream instanceof StreamIterator) {
while ($offset !== $stream->key() && $stream->valid()) {
$stream->next();
}
return $stream->current();
}
$iterator = new LimitIterator($stream, $offset, 1);
$iterator->rewind();
return $iterator->current();
}
}

170
vendor/league/csv/src/Writer.php vendored Normal file
View File

@@ -0,0 +1,170 @@
<?php
/**
* This file is part of the League.csv library
*
* @license http://opensource.org/licenses/MIT
* @link https://github.com/thephpleague/csv/
* @version 8.2.3
* @package League.csv
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace League\Csv;
use InvalidArgumentException;
use League\Csv\Modifier\RowFilter;
use League\Csv\Modifier\StreamIterator;
use ReflectionMethod;
use RuntimeException;
use SplFileObject;
use Traversable;
/**
* A class to manage data insertion into a CSV
*
* @package League.csv
* @since 4.0.0
*
*/
class Writer extends AbstractCsv
{
use RowFilter;
/**
* @inheritdoc
*/
protected $stream_filter_mode = STREAM_FILTER_WRITE;
/**
* The CSV object holder
*
* @var SplFileObject|StreamIterator
*/
protected $csv;
/**
* fputcsv method from SplFileObject or StreamIterator
*
* @var ReflectionMethod
*/
protected $fputcsv;
/**
* Nb parameters for SplFileObject::fputcsv method
*
* @var integer
*/
protected $fputcsv_param_count;
/**
* Adds multiple lines to the CSV document
*
* a simple wrapper method around insertOne
*
* @param Traversable|array $rows a multidimensional array or a Traversable object
*
* @throws InvalidArgumentException If the given rows format is invalid
*
* @return static
*/
public function insertAll($rows)
{
if (!is_array($rows) && !$rows instanceof Traversable) {
throw new InvalidArgumentException(
'the provided data must be an array OR a `Traversable` object'
);
}
foreach ($rows as $row) {
$this->insertOne($row);
}
return $this;
}
/**
* Adds a single line to a CSV document
*
* @param string[]|string $row a string, an array or an object implementing to '__toString' method
*
* @return static
*/
public function insertOne($row)
{
if (!is_array($row)) {
$row = str_getcsv($row, $this->delimiter, $this->enclosure, $this->escape);
}
$row = $this->formatRow($row);
$this->validateRow($row);
$this->addRow($row);
return $this;
}
/**
* Add new record to the CSV document
*
* @param array $row record to add
*/
protected function addRow(array $row)
{
$this->initCsv();
if (!$this->fputcsv->invokeArgs($this->csv, $this->getFputcsvParameters($row))) {
throw new RuntimeException('Unable to write record to the CSV document.');
}
if ("\n" !== $this->newline) {
$this->csv->fseek(-1, SEEK_CUR);
$this->csv->fwrite($this->newline, strlen($this->newline));
}
}
/**
* Initialize the CSV object and settings
*/
protected function initCsv()
{
if (null !== $this->csv) {
return;
}
$this->csv = $this->getIterator();
$this->fputcsv = new ReflectionMethod(get_class($this->csv), 'fputcsv');
$this->fputcsv_param_count = $this->fputcsv->getNumberOfParameters();
}
/**
* returns the parameters for SplFileObject::fputcsv
*
* @param array $fields The fields to be add
*
* @return array
*/
protected function getFputcsvParameters(array $fields)
{
$parameters = [$fields, $this->delimiter, $this->enclosure];
if (4 == $this->fputcsv_param_count) {
$parameters[] = $this->escape;
}
return $parameters;
}
/**
* {@inheritdoc}
*/
public function isActiveStreamFilter()
{
return parent::isActiveStreamFilter() && null === $this->csv;
}
/**
* {@inheritdoc}
*/
public function __destruct()
{
$this->csv = null;
parent::__destruct();
}
}