TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:09 +02:00
commit af8cc155b5
6818 changed files with 642608 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\IO;
/**
* Inspired by https://csv.thephpleague.com/9.0/interoperability/enclose-field/
*
* A unique sequence is added to relevant CSV field values in order to trigger enclosure in fputcsv.
* This stream filter is taking care of removing that sequence again when actually writing to stream.
*/
class CsvStreamFilter extends \php_user_filter
{
protected const NAME = 'csv.typo3';
/**
* Implicitly handles stream filter when writing CSV data - example:
*
* @example
*
* ```
* $resource = fopen('file.csv', 'w');
* $modifier = CsvUtility::applyStreamFilter($resource);
* fputcsv($resource, $modifier($fieldValues));
* fclose($resource);
* ```
*
* @param resource $in
* @param resource $out
* @param int $consumed
* @param bool $closing
* @param-out int $consumed
*/
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
// removes sequence boundary indicator
$bucket->data = str_replace(
$this->params['sequence'],
'',
$bucket->data
);
if ($this->params['LF'] === false) {
// remove line-feed added by `fputcsv` per default
$bucket->data = preg_replace('#\r?\n$#', '', $bucket->data);
}
$consumed += (int)$bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
/**
* @param resource $stream
* @param bool $LF whether to apply line-feed
*/
public static function applyStreamFilter($stream, bool $LF = true): \Closure
{
self::registerStreamFilter();
// must contain a spacing character to enforce enclosure
$sequence = "\t\x1d\x1e\x1f";
stream_filter_append(
$stream,
self::NAME,
STREAM_FILTER_WRITE,
['sequence' => $sequence, 'LF' => $LF]
);
return self::buildStreamFilterModifier($sequence);
}
/**
* Registers stream filter
*/
protected static function registerStreamFilter()
{
if (in_array(self::NAME, stream_get_filters(), true)) {
return;
}
stream_filter_register(
self::NAME,
static::class
);
}
protected static function buildStreamFilterModifier(string $sequence): \Closure
{
return static function ($element) use ($sequence) {
foreach ($element as &$value) {
if (is_numeric($value) || $value === '') {
continue;
}
$value = $sequence . $value;
}
unset($value); // de-reference
return $element;
};
}
}