PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.0
Independent Analytics – WordPress Analytics Plugin v2.15.0
2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / league / csv / src / AbstractCsv.php
independent-analytics / vendor / league / csv / src Last commit date
AbstractCsv.php 4 days ago ByteSequence.php 4 days ago CannotInsertRecord.php 4 days ago CharsetConverter.php 4 days ago ColumnConsistency.php 4 days ago EncloseField.php 4 days ago EscapeFormula.php 4 days ago Exception.php 9 months ago HTMLConverter.php 4 days ago Info.php 4 days ago InvalidArgument.php 9 months ago MapIterator.php 4 days ago RFC4180Field.php 4 days ago Reader.php 4 days ago ResultSet.php 4 days ago Statement.php 4 days ago Stream.php 4 days ago SyntaxError.php 4 days ago TabularDataReader.php 4 days ago UnableToProcessCsv.php 9 months ago UnavailableFeature.php 9 months ago UnavailableStream.php 9 months ago Writer.php 4 days ago XMLConverter.php 4 days ago functions.php 9 months ago functions_include.php 9 months ago
AbstractCsv.php
429 lines
1 <?php
2
3 /**
4 * League.Csv (https://csv.thephpleague.com)
5 *
6 * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 declare (strict_types=1);
12 namespace IAWPSCOPED\League\Csv;
13
14 use Generator;
15 use SplFileObject;
16 use function filter_var;
17 use function get_class;
18 use function mb_strlen;
19 use function rawurlencode;
20 use function sprintf;
21 use function str_replace;
22 use function str_split;
23 use function strcspn;
24 use function strlen;
25 use const FILTER_FLAG_STRIP_HIGH;
26 use const FILTER_FLAG_STRIP_LOW;
27 use const FILTER_UNSAFE_RAW;
28 /**
29 * An abstract class to enable CSV document loading.
30 * @internal
31 */
32 abstract class AbstractCsv implements ByteSequence
33 {
34 protected const STREAM_FILTER_MODE = \STREAM_FILTER_READ;
35 /** @var SplFileObject|Stream The CSV document. */
36 protected $document;
37 /** @var array<string, bool> collection of stream filters. */
38 protected array $stream_filters = [];
39 protected ?string $input_bom = null;
40 protected string $output_bom = '';
41 protected string $delimiter = ',';
42 protected string $enclosure = '"';
43 protected string $escape = '\\';
44 protected bool $is_input_bom_included = \false;
45 /**
46 * @final This method should not be overwritten in child classes
47 *
48 * @param SplFileObject|Stream $document The CSV Object instance
49 */
50 protected function __construct($document)
51 {
52 $this->document = $document;
53 [$this->delimiter, $this->enclosure, $this->escape] = $this->document->getCsvControl();
54 $this->resetProperties();
55 }
56 /**
57 * Reset dynamic object properties to improve performance.
58 */
59 protected abstract function resetProperties() : void;
60 public function __destruct()
61 {
62 unset($this->document);
63 }
64 public function __clone()
65 {
66 throw UnavailableStream::dueToForbiddenCloning(static::class);
67 }
68 /**
69 * Return a new instance from a SplFileObject.
70 *
71 * @return static
72 */
73 public static function createFromFileObject(SplFileObject $file)
74 {
75 return new static($file);
76 }
77 /**
78 * Return a new instance from a PHP resource stream.
79 *
80 * @param resource $stream
81 *
82 * @return static
83 */
84 public static function createFromStream($stream)
85 {
86 return new static(new Stream($stream));
87 }
88 /**
89 * Return a new instance from a string.
90 *
91 * @return static
92 */
93 public static function createFromString(string $content = '')
94 {
95 return new static(Stream::createFromString($content));
96 }
97 /**
98 * Return a new instance from a file path.
99 *
100 * @param resource|null $context the resource context
101 *
102 * @return static
103 */
104 public static function createFromPath(string $path, string $open_mode = 'r+', $context = null)
105 {
106 return new static(Stream::createFromPath($path, $open_mode, $context));
107 }
108 /**
109 * Returns the current field delimiter.
110 */
111 public function getDelimiter() : string
112 {
113 return $this->delimiter;
114 }
115 /**
116 * Returns the current field enclosure.
117 */
118 public function getEnclosure() : string
119 {
120 return $this->enclosure;
121 }
122 /**
123 * Returns the pathname of the underlying document.
124 */
125 public function getPathname() : string
126 {
127 return $this->document->getPathname();
128 }
129 /**
130 * Returns the current field escape character.
131 */
132 public function getEscape() : string
133 {
134 return $this->escape;
135 }
136 /**
137 * Returns the BOM sequence in use on Output methods.
138 */
139 public function getOutputBOM() : string
140 {
141 return $this->output_bom;
142 }
143 /**
144 * Returns the BOM sequence of the given CSV.
145 */
146 public function getInputBOM() : string
147 {
148 if (null !== $this->input_bom) {
149 return $this->input_bom;
150 }
151 $this->document->setFlags(SplFileObject::READ_CSV);
152 $this->document->rewind();
153 $this->input_bom = Info::fetchBOMSequence((string) $this->document->fread(4)) ?? '';
154 return $this->input_bom;
155 }
156 /**
157 * DEPRECATION WARNING! This method will be removed in the next major point release.
158 *
159 * @deprecated since version 9.7.0
160 * @see AbstractCsv::supportsStreamFilterOnRead
161 * @see AbstractCsv::supportsStreamFilterOnWrite
162 *
163 * Returns the stream filter mode.
164 */
165 public function getStreamFilterMode() : int
166 {
167 return static::STREAM_FILTER_MODE;
168 }
169 /**
170 * DEPRECATION WARNING! This method will be removed in the next major point release.
171 *
172 * @deprecated since version 9.7.0
173 * @see AbstractCsv::supportsStreamFilterOnRead
174 * @see AbstractCsv::supportsStreamFilterOnWrite
175 *
176 * Tells whether the stream filter capabilities can be used.
177 */
178 public function supportsStreamFilter() : bool
179 {
180 return $this->document instanceof Stream;
181 }
182 /**
183 * Tells whether the stream filter read capabilities can be used.
184 */
185 public function supportsStreamFilterOnRead() : bool
186 {
187 return $this->document instanceof Stream && (static::STREAM_FILTER_MODE & \STREAM_FILTER_READ) === \STREAM_FILTER_READ;
188 }
189 /**
190 * Tells whether the stream filter write capabilities can be used.
191 */
192 public function supportsStreamFilterOnWrite() : bool
193 {
194 return $this->document instanceof Stream && (static::STREAM_FILTER_MODE & \STREAM_FILTER_WRITE) === \STREAM_FILTER_WRITE;
195 }
196 /**
197 * Tell whether the specify stream filter is attach to the current stream.
198 */
199 public function hasStreamFilter(string $filtername) : bool
200 {
201 return $this->stream_filters[$filtername] ?? \false;
202 }
203 /**
204 * Tells whether the BOM can be stripped if presents.
205 */
206 public function isInputBOMIncluded() : bool
207 {
208 return $this->is_input_bom_included;
209 }
210 /**
211 * Returns the CSV document as a Generator of string chunk.
212 *
213 * @param int $length number of bytes read
214 *
215 * @throws Exception if the number of bytes is lesser than 1
216 */
217 public function chunk(int $length) : Generator
218 {
219 if ($length < 1) {
220 throw InvalidArgument::dueToInvalidChunkSize($length, __METHOD__);
221 }
222 $input_bom = $this->getInputBOM();
223 $this->document->rewind();
224 $this->document->setFlags(0);
225 $this->document->fseek(strlen($input_bom));
226 /** @var array<int, string> $chunks */
227 $chunks = str_split($this->output_bom . $this->document->fread($length), $length);
228 foreach ($chunks as $chunk) {
229 (yield $chunk);
230 }
231 while ($this->document->valid()) {
232 (yield $this->document->fread($length));
233 }
234 }
235 /**
236 * DEPRECATION WARNING! This method will be removed in the next major point release.
237 *
238 * @deprecated since version 9.1.0
239 * @see AbstractCsv::toString
240 *
241 * Retrieves the CSV content
242 */
243 public function __toString() : string
244 {
245 return $this->toString();
246 }
247 /**
248 * Retrieves the CSV content.
249 *
250 * DEPRECATION WARNING! This method will be removed in the next major point release
251 *
252 * @deprecated since version 9.7.0
253 * @see AbstractCsv::toString
254 */
255 public function getContent() : string
256 {
257 return $this->toString();
258 }
259 /**
260 * Retrieves the CSV content.
261 *
262 * @throws Exception If the string representation can not be returned
263 */
264 public function toString() : string
265 {
266 $raw = '';
267 foreach ($this->chunk(8192) as $chunk) {
268 $raw .= $chunk;
269 }
270 return $raw;
271 }
272 /**
273 * Outputs all data on the CSV file.
274 *
275 * @return int Returns the number of characters read from the handle
276 * and passed through to the output.
277 */
278 public function output(string $filename = null) : int
279 {
280 if (null !== $filename) {
281 $this->sendHeaders($filename);
282 }
283 $this->document->rewind();
284 if (!$this->is_input_bom_included) {
285 $this->document->fseek(strlen($this->getInputBOM()));
286 }
287 echo $this->output_bom;
288 return strlen($this->output_bom) + (int) $this->document->fpassthru();
289 }
290 /**
291 * Send the CSV headers.
292 *
293 * Adapted from Symfony\Component\HttpFoundation\ResponseHeaderBag::makeDisposition
294 *
295 * @throws Exception if the submitted header is invalid according to RFC 6266
296 *
297 * @see https://tools.ietf.org/html/rfc6266#section-4.3
298 */
299 protected function sendHeaders(string $filename) : void
300 {
301 if (strlen($filename) != strcspn($filename, '\\/')) {
302 throw InvalidArgument::dueToInvalidHeaderFilename($filename);
303 }
304 $flag = FILTER_FLAG_STRIP_LOW;
305 if (strlen($filename) !== mb_strlen($filename)) {
306 $flag |= FILTER_FLAG_STRIP_HIGH;
307 }
308 /** @var string $filtered_name */
309 $filtered_name = filter_var($filename, FILTER_UNSAFE_RAW, $flag);
310 $filename_fallback = str_replace('%', '', $filtered_name);
311 $disposition = sprintf('attachment; filename="%s"', str_replace('"', '\\"', $filename_fallback));
312 if ($filename !== $filename_fallback) {
313 $disposition .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
314 }
315 \header('Content-Type: text/csv');
316 \header('Content-Transfer-Encoding: binary');
317 \header('Content-Description: File Transfer');
318 \header('Content-Disposition: ' . $disposition);
319 }
320 /**
321 * Sets the field delimiter.
322 *
323 * @throws InvalidArgument If the Csv control character is not one character only.
324 *
325 * @return static
326 */
327 public function setDelimiter(string $delimiter) : self
328 {
329 if ($delimiter === $this->delimiter) {
330 return $this;
331 }
332 if (1 !== strlen($delimiter)) {
333 throw InvalidArgument::dueToInvalidDelimiterCharacter($delimiter, __METHOD__);
334 }
335 $this->delimiter = $delimiter;
336 $this->resetProperties();
337 return $this;
338 }
339 /**
340 * Sets the field enclosure.
341 *
342 * @throws InvalidArgument If the Csv control character is not one character only.
343 *
344 * @return static
345 */
346 public function setEnclosure(string $enclosure) : self
347 {
348 if ($enclosure === $this->enclosure) {
349 return $this;
350 }
351 if (1 !== strlen($enclosure)) {
352 throw InvalidArgument::dueToInvalidEnclosureCharacter($enclosure, __METHOD__);
353 }
354 $this->enclosure = $enclosure;
355 $this->resetProperties();
356 return $this;
357 }
358 /**
359 * Sets the field escape character.
360 *
361 * @throws InvalidArgument If the Csv control character is not one character only.
362 *
363 * @return static
364 */
365 public function setEscape(string $escape) : self
366 {
367 if ($escape === $this->escape) {
368 return $this;
369 }
370 if ('' !== $escape && 1 !== strlen($escape)) {
371 throw InvalidArgument::dueToInvalidEscapeCharacter($escape, __METHOD__);
372 }
373 $this->escape = $escape;
374 $this->resetProperties();
375 return $this;
376 }
377 /**
378 * Enables BOM Stripping.
379 *
380 * @return static
381 */
382 public function skipInputBOM() : self
383 {
384 $this->is_input_bom_included = \false;
385 return $this;
386 }
387 /**
388 * Disables skipping Input BOM.
389 *
390 * @return static
391 */
392 public function includeInputBOM() : self
393 {
394 $this->is_input_bom_included = \true;
395 return $this;
396 }
397 /**
398 * Sets the BOM sequence to prepend the CSV on output.
399 *
400 * @return static
401 */
402 public function setOutputBOM(string $str) : self
403 {
404 $this->output_bom = $str;
405 return $this;
406 }
407 /**
408 * append a stream filter.
409 *
410 * @param null|array $params
411 *
412 * @throws InvalidArgument If the stream filter API can not be appended
413 * @throws UnavailableFeature If the stream filter API can not be used
414 *
415 * @return static
416 */
417 public function addStreamFilter(string $filtername, $params = null) : self
418 {
419 if (!$this->document instanceof Stream) {
420 throw UnavailableFeature::dueToUnsupportedStreamFilterApi(get_class($this->document));
421 }
422 $this->document->appendFilter($filtername, static::STREAM_FILTER_MODE, $params);
423 $this->stream_filters[$filtername] = \true;
424 $this->resetProperties();
425 $this->input_bom = null;
426 return $this;
427 }
428 }
429