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

20
vendor/league/csv/LICENSE vendored Normal file
View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013-2015 ignace nyamagana butera
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

21
vendor/league/csv/autoload.php vendored Normal file
View File

@@ -0,0 +1,21 @@
<?php
spl_autoload_register(function ($class) {
$prefix = 'League\Csv\\';
if (0 !== strpos($class, $prefix)) {
return;
}
$file = __DIR__
.DIRECTORY_SEPARATOR
.'src'
.DIRECTORY_SEPARATOR
.str_replace('\\', DIRECTORY_SEPARATOR, substr($class, strlen($prefix)))
.'.php';
if (!is_readable($file)) {
return;
}
require $file;
});

49
vendor/league/csv/composer.json vendored Normal file
View File

@@ -0,0 +1,49 @@
{
"name": "league/csv",
"type": "library",
"description" : "Csv data manipulation made easy in PHP",
"keywords": ["csv", "import", "export", "read", "write", "filter"],
"license": "MIT",
"homepage" : "http://csv.thephpleague.com",
"authors": [
{
"name" : "Ignace Nyamagana Butera",
"email" : "nyamsprod@gmail.com",
"homepage" : "https://github.com/nyamsprod/",
"role" : "Developer"
}
],
"support": {
"forum": "https://groups.google.com/forum/#!forum/thephpleague",
"issues": "https://github.com/thephpleague/csv/issues"
},
"require": {
"php" : ">=5.5.0",
"ext-mbstring" : "*"
},
"require-dev": {
"phpunit/phpunit" : "^4.0",
"friendsofphp/php-cs-fixer": "^1.9"
},
"autoload": {
"psr-4": {
"League\\Csv\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"League\\Csv\\Test\\": "test",
"lib\\": "examples\\lib"
}
},
"scripts": {
"test": "phpunit --coverage-text; php-cs-fixer fix -v --diff --dry-run;",
"phpunit": "phpunit --coverage-text",
"phpcs": "php-cs-fixer fix -v --diff --dry-run;"
},
"extra": {
"branch-alias": {
"dev-master": "8.2-dev"
}
}
}

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();
}
}