‪TYPO3CMS  ‪main
CsvUtility.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
21 
26 {
30  public const ‪TYPE_PASSTHROUGH = 0;
31 
35  public const ‪TYPE_REMOVE_CONTROLS = 1;
36 
41  public const ‪TYPE_PREFIX_CONTROLS = 2;
42 
53  public static function ‪csvToArray(string $input, string $fieldDelimiter = ',', string $fieldEnclosure = '"', int $maximumColumns = 0): array
54  {
55  $multiArray = [];
56  $maximumCellCount = 0;
57 
58  if (($handle = fopen('php://memory', 'r+')) !== false) {
59  fwrite($handle, $input);
60  rewind($handle);
61  while (($cells = fgetcsv($handle, 0, $fieldDelimiter, $fieldEnclosure)) !== false) {
62  $maximumCellCount = max(count($cells), $maximumCellCount);
63  $multiArray[] = preg_replace('|<br */?>|i', LF, $cells);
64  }
65  fclose($handle);
66  }
67 
68  if ($maximumColumns > $maximumCellCount) {
69  $maximumCellCount = $maximumColumns;
70  }
71 
72  foreach ($multiArray as &$row) {
73  for ($key = 0; $key < $maximumCellCount; $key++) {
74  if (
75  $maximumColumns > 0
76  && $maximumColumns < $maximumCellCount
77  && $key >= $maximumColumns
78  ) {
79  if (isset($row[$key])) {
80  unset($row[$key]);
81  }
82  } elseif (!isset($row[$key])) {
83  $row[$key] = '';
84  }
85  }
86  }
87 
88  return $multiArray;
89  }
90 
100  public static function ‪csvValues(array $row, string $delim = ',', string $quote = '"', int $type = self::TYPE_REMOVE_CONTROLS): string
101  {
102  $resource = fopen('php://temp', 'w');
103  if (!is_resource($resource)) {
104  throw new \RuntimeException('Cannot open temporary data stream for writing', 1625556521);
105  }
106  $modifier = ‪CsvStreamFilter::applyStreamFilter($resource, false);
107  array_map(self::assertCellValueType(...), $row);
108  if ($type === self::TYPE_REMOVE_CONTROLS) {
109  $row = array_map(self::removeControlLiterals(...), $row);
110  } elseif ($type === self::TYPE_PREFIX_CONTROLS) {
111  $row = array_map(self::prefixControlLiterals(...), $row);
112  }
113  fputcsv($resource, $modifier($row), $delim, $quote);
114  fseek($resource, 0);
115  return stream_get_contents($resource);
116  }
117 
123  protected static function ‪prefixControlLiterals(bool|int|float|string|null $cellValue): bool|int|float|string|null
124  {
125  if (!self::shallFilterValue($cellValue)) {
126  return $cellValue;
127  }
128  $cellValue = (string)$cellValue;
129  return preg_replace('#^([\t\v=+*%/@-])#', '\'${1}', $cellValue);
130  }
131 
137  protected static function removeControlLiterals(bool|int|float|string|null $cellValue): bool|int|float|string|null
138  {
139  if (!self::shallFilterValue($cellValue)) {
140  return $cellValue;
141  }
142  $cellValue = (string)$cellValue;
143  return preg_replace('#^([\t\v=+*%/@-]+)+#', '', $cellValue);
144  }
145 
149  protected static function assertCellValueType(mixed $cellValue): void
150  {
151  // int, float, string, bool, null
152  if ($cellValue === null || is_scalar($cellValue)) {
153  return;
154  }
155  throw new \RuntimeException(
156  sprintf('Unexpected type %s for cell value', gettype($cellValue)),
157  1625562833
158  );
159  }
160 
167  protected static function shallFilterValue(bool|int|float|string|null $cellValue): bool
168  {
169  return $cellValue !== null
170  && !is_bool($cellValue)
171  && !is_numeric($cellValue)
172  && !MathUtility::canBeInterpretedAsInteger($cellValue)
173  && !MathUtility::canBeInterpretedAsFloat($cellValue);
174  }
175 }
‪TYPO3\CMS\Core\Utility\CsvUtility\TYPE_PREFIX_CONTROLS
‪const TYPE_PREFIX_CONTROLS
Definition: CsvUtility.php:41
‪TYPO3\CMS\Core\Utility\CsvUtility\csvToArray
‪static csvToArray(string $input, string $fieldDelimiter=',', string $fieldEnclosure='"', int $maximumColumns = 0)
Definition: CsvUtility.php:53
‪TYPO3\CMS\Core\Utility\CsvUtility\prefixControlLiterals
‪static prefixControlLiterals(bool|int|float|string|null $cellValue)
Definition: CsvUtility.php:123
‪TYPO3\CMS\Core\Utility
Definition: ArrayUtility.php:18
‪TYPO3\CMS\Core\Utility\CsvUtility\TYPE_REMOVE_CONTROLS
‪const TYPE_REMOVE_CONTROLS
Definition: CsvUtility.php:35
‪TYPO3\CMS\Core\IO\CsvStreamFilter\applyStreamFilter
‪static applyStreamFilter($stream, bool $LF=true)
Definition: CsvStreamFilter.php:70
‪TYPO3\CMS\Core\Utility\CsvUtility\TYPE_PASSTHROUGH
‪const TYPE_PASSTHROUGH
Definition: CsvUtility.php:30
‪TYPO3\CMS\Core\Utility\CsvUtility
Definition: CsvUtility.php:26
‪TYPO3\CMS\Core\IO\CsvStreamFilter
Definition: CsvStreamFilter.php:27
‪TYPO3\CMS\Core\Utility\CsvUtility\csvValues
‪static string csvValues(array $row, string $delim=',', string $quote='"', int $type = self::TYPE_REMOVE_CONTROLS)
Definition: CsvUtility.php:100