PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.14.6
Independent Analytics – WordPress Analytics Plugin v2.14.6
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 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
Polyfill 10 months ago AbstractCsv.php 10 months ago ByteSequence.php 10 months ago CannotInsertRecord.php 10 months ago CharsetConverter.php 10 months ago ColumnConsistency.php 10 months ago EncloseField.php 10 months ago EscapeFormula.php 10 months ago Exception.php 10 months ago HTMLConverter.php 10 months ago Info.php 10 months ago InvalidArgument.php 10 months ago MapIterator.php 10 months ago RFC4180Field.php 10 months ago Reader.php 10 months ago ResultSet.php 10 months ago Statement.php 10 months ago Stream.php 10 months ago SyntaxError.php 10 months ago TabularDataReader.php 10 months ago UnableToProcessCsv.php 10 months ago UnavailableFeature.php 10 months ago UnavailableStream.php 10 months ago Writer.php 10 months ago XMLConverter.php 10 months ago functions.php 10 months ago functions_include.php 10 months ago
AbstractCsv.php
473 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 /**
36 * collection of stream filters.
37 *
38 * @var bool[]
39 */
40 protected $stream_filters = [];
41 /**
42 * The CSV document BOM sequence.
43 *
44 * @var string|null
45 */
46 protected $input_bom = null;
47 /**
48 * The Output file BOM character.
49 *
50 * @var string
51 */
52 protected $output_bom = '';
53 /**
54 * the field delimiter (one character only).
55 *
56 * @var string
57 */
58 protected $delimiter = ',';
59 /**
60 * the field enclosure character (one character only).
61 *
62 * @var string
63 */
64 protected $enclosure = '"';
65 /**
66 * the field escape character (one character only).
67 *
68 * @var string
69 */
70 protected $escape = '\\';
71 /**
72 * The CSV document.
73 *
74 * @var SplFileObject|Stream
75 */
76 protected $document;
77 /**
78 * Tells whether the Input BOM must be included or skipped.
79 *
80 * @var bool
81 */
82 protected $is_input_bom_included = \false;
83 /**
84 * New instance.
85 *
86 * @param SplFileObject|Stream $document The CSV Object instance
87 */
88 protected function __construct($document)
89 {
90 $this->document = $document;
91 [$this->delimiter, $this->enclosure, $this->escape] = $this->document->getCsvControl();
92 $this->resetProperties();
93 }
94 /**
95 * Reset dynamic object properties to improve performance.
96 */
97 protected abstract function resetProperties() : void;
98 /**
99 * {@inheritdoc}
100 */
101 public function __destruct()
102 {
103 unset($this->document);
104 }
105 /**
106 * {@inheritdoc}
107 */
108 public function __clone()
109 {
110 throw UnavailableStream::dueToForbiddenCloning(static::class);
111 }
112 /**
113 * Return a new instance from a SplFileObject.
114 *
115 * @return static
116 */
117 public static function createFromFileObject(SplFileObject $file)
118 {
119 return new static($file);
120 }
121 /**
122 * Return a new instance from a PHP resource stream.
123 *
124 * @param resource $stream
125 *
126 * @return static
127 */
128 public static function createFromStream($stream)
129 {
130 return new static(new Stream($stream));
131 }
132 /**
133 * Return a new instance from a string.
134 *
135 * @return static
136 */
137 public static function createFromString(string $content = '')
138 {
139 return new static(Stream::createFromString($content));
140 }
141 /**
142 * Return a new instance from a file path.
143 *
144 * @param resource|null $context the resource context
145 *
146 * @return static
147 */
148 public static function createFromPath(string $path, string $open_mode = 'r+', $context = null)
149 {
150 return new static(Stream::createFromPath($path, $open_mode, $context));
151 }
152 /**
153 * Returns the current field delimiter.
154 */
155 public function getDelimiter() : string
156 {
157 return $this->delimiter;
158 }
159 /**
160 * Returns the current field enclosure.
161 */
162 public function getEnclosure() : string
163 {
164 return $this->enclosure;
165 }
166 /**
167 * Returns the pathname of the underlying document.
168 */
169 public function getPathname() : string
170 {
171 return $this->document->getPathname();
172 }
173 /**
174 * Returns the current field escape character.
175 */
176 public function getEscape() : string
177 {
178 return $this->escape;
179 }
180 /**
181 * Returns the BOM sequence in use on Output methods.
182 */
183 public function getOutputBOM() : string
184 {
185 return $this->output_bom;
186 }
187 /**
188 * Returns the BOM sequence of the given CSV.
189 */
190 public function getInputBOM() : string
191 {
192 if (null !== $this->input_bom) {
193 return $this->input_bom;
194 }
195 $this->document->setFlags(SplFileObject::READ_CSV);
196 $this->document->rewind();
197 $this->input_bom = Info::fetchBOMSequence((string) $this->document->fread(4)) ?? '';
198 return $this->input_bom;
199 }
200 /**
201 * DEPRECATION WARNING! This method will be removed in the next major point release.
202 *
203 * @deprecated since version 9.7.0
204 * @see AbstractCsv::supportsStreamFilterOnRead
205 * @see AbstractCsv::supportsStreamFilterOnWrite
206 *
207 * Returns the stream filter mode.
208 */
209 public function getStreamFilterMode() : int
210 {
211 return static::STREAM_FILTER_MODE;
212 }
213 /**
214 * DEPRECATION WARNING! This method will be removed in the next major point release.
215 *
216 * @deprecated since version 9.7.0
217 * @see AbstractCsv::supportsStreamFilterOnRead
218 * @see AbstractCsv::supportsStreamFilterOnWrite
219 *
220 * Tells whether the stream filter capabilities can be used.
221 */
222 public function supportsStreamFilter() : bool
223 {
224 return $this->document instanceof Stream;
225 }
226 /**
227 * Tells whether the stream filter read capabilities can be used.
228 */
229 public function supportsStreamFilterOnRead() : bool
230 {
231 return $this->document instanceof Stream && (static::STREAM_FILTER_MODE & \STREAM_FILTER_READ) === \STREAM_FILTER_READ;
232 }
233 /**
234 * Tells whether the stream filter write capabilities can be used.
235 */
236 public function supportsStreamFilterOnWrite() : bool
237 {
238 return $this->document instanceof Stream && (static::STREAM_FILTER_MODE & \STREAM_FILTER_WRITE) === \STREAM_FILTER_WRITE;
239 }
240 /**
241 * Tell whether the specify stream filter is attach to the current stream.
242 */
243 public function hasStreamFilter(string $filtername) : bool
244 {
245 return $this->stream_filters[$filtername] ?? \false;
246 }
247 /**
248 * Tells whether the BOM can be stripped if presents.
249 */
250 public function isInputBOMIncluded() : bool
251 {
252 return $this->is_input_bom_included;
253 }
254 /**
255 * Returns the CSV document as a Generator of string chunk.
256 *
257 * @param int $length number of bytes read
258 *
259 * @throws Exception if the number of bytes is lesser than 1
260 */
261 public function chunk(int $length) : Generator
262 {
263 if ($length < 1) {
264 throw InvalidArgument::dueToInvalidChunkSize($length, __METHOD__);
265 }
266 $input_bom = $this->getInputBOM();
267 $this->document->rewind();
268 $this->document->setFlags(0);
269 $this->document->fseek(strlen($input_bom));
270 /** @var array<int, string> $chunks */
271 $chunks = str_split($this->output_bom . $this->document->fread($length), $length);
272 foreach ($chunks as $chunk) {
273 (yield $chunk);
274 }
275 while ($this->document->valid()) {
276 (yield $this->document->fread($length));
277 }
278 }
279 /**
280 * DEPRECATION WARNING! This method will be removed in the next major point release.
281 *
282 * @deprecated since version 9.1.0
283 * @see AbstractCsv::toString
284 *
285 * Retrieves the CSV content
286 */
287 public function __toString() : string
288 {
289 return $this->toString();
290 }
291 /**
292 * Retrieves the CSV content.
293 *
294 * DEPRECATION WARNING! This method will be removed in the next major point release
295 *
296 * @deprecated since version 9.7.0
297 * @see AbstractCsv::toString
298 */
299 public function getContent() : string
300 {
301 return $this->toString();
302 }
303 /**
304 * Retrieves the CSV content.
305 *
306 * @throws Exception If the string representation can not be returned
307 */
308 public function toString() : string
309 {
310 $raw = '';
311 foreach ($this->chunk(8192) as $chunk) {
312 $raw .= $chunk;
313 }
314 return $raw;
315 }
316 /**
317 * Outputs all data on the CSV file.
318 *
319 * @return int Returns the number of characters read from the handle
320 * and passed through to the output.
321 */
322 public function output(string $filename = null) : int
323 {
324 if (null !== $filename) {
325 $this->sendHeaders($filename);
326 }
327 $this->document->rewind();
328 if (!$this->is_input_bom_included) {
329 $this->document->fseek(strlen($this->getInputBOM()));
330 }
331 echo $this->output_bom;
332 return strlen($this->output_bom) + (int) $this->document->fpassthru();
333 }
334 /**
335 * Send the CSV headers.
336 *
337 * Adapted from Symfony\Component\HttpFoundation\ResponseHeaderBag::makeDisposition
338 *
339 * @throws Exception if the submitted header is invalid according to RFC 6266
340 *
341 * @see https://tools.ietf.org/html/rfc6266#section-4.3
342 */
343 protected function sendHeaders(string $filename) : void
344 {
345 if (strlen($filename) != strcspn($filename, '\\/')) {
346 throw InvalidArgument::dueToInvalidHeaderFilename($filename);
347 }
348 $flag = FILTER_FLAG_STRIP_LOW;
349 if (strlen($filename) !== mb_strlen($filename)) {
350 $flag |= FILTER_FLAG_STRIP_HIGH;
351 }
352 /** @var string $filtered_name */
353 $filtered_name = filter_var($filename, FILTER_UNSAFE_RAW, $flag);
354 $filename_fallback = str_replace('%', '', $filtered_name);
355 $disposition = sprintf('attachment; filename="%s"', str_replace('"', '\\"', $filename_fallback));
356 if ($filename !== $filename_fallback) {
357 $disposition .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
358 }
359 \header('Content-Type: text/csv');
360 \header('Content-Transfer-Encoding: binary');
361 \header('Content-Description: File Transfer');
362 \header('Content-Disposition: ' . $disposition);
363 }
364 /**
365 * Sets the field delimiter.
366 *
367 * @throws InvalidArgument If the Csv control character is not one character only.
368 *
369 * @return static
370 */
371 public function setDelimiter(string $delimiter) : self
372 {
373 if ($delimiter === $this->delimiter) {
374 return $this;
375 }
376 if (1 !== strlen($delimiter)) {
377 throw InvalidArgument::dueToInvalidDelimiterCharacter($delimiter, __METHOD__);
378 }
379 $this->delimiter = $delimiter;
380 $this->resetProperties();
381 return $this;
382 }
383 /**
384 * Sets the field enclosure.
385 *
386 * @throws InvalidArgument If the Csv control character is not one character only.
387 *
388 * @return static
389 */
390 public function setEnclosure(string $enclosure) : self
391 {
392 if ($enclosure === $this->enclosure) {
393 return $this;
394 }
395 if (1 !== strlen($enclosure)) {
396 throw InvalidArgument::dueToInvalidEnclosureCharacter($enclosure, __METHOD__);
397 }
398 $this->enclosure = $enclosure;
399 $this->resetProperties();
400 return $this;
401 }
402 /**
403 * Sets the field escape character.
404 *
405 * @throws InvalidArgument If the Csv control character is not one character only.
406 *
407 * @return static
408 */
409 public function setEscape(string $escape) : self
410 {
411 if ($escape === $this->escape) {
412 return $this;
413 }
414 if ('' !== $escape && 1 !== strlen($escape)) {
415 throw InvalidArgument::dueToInvalidEscapeCharacter($escape, __METHOD__);
416 }
417 $this->escape = $escape;
418 $this->resetProperties();
419 return $this;
420 }
421 /**
422 * Enables BOM Stripping.
423 *
424 * @return static
425 */
426 public function skipInputBOM() : self
427 {
428 $this->is_input_bom_included = \false;
429 return $this;
430 }
431 /**
432 * Disables skipping Input BOM.
433 *
434 * @return static
435 */
436 public function includeInputBOM() : self
437 {
438 $this->is_input_bom_included = \true;
439 return $this;
440 }
441 /**
442 * Sets the BOM sequence to prepend the CSV on output.
443 *
444 * @return static
445 */
446 public function setOutputBOM(string $str) : self
447 {
448 $this->output_bom = $str;
449 return $this;
450 }
451 /**
452 * append a stream filter.
453 *
454 * @param null|array $params
455 *
456 * @throws InvalidArgument If the stream filter API can not be appended
457 * @throws UnavailableFeature If the stream filter API can not be used
458 *
459 * @return static
460 */
461 public function addStreamFilter(string $filtername, $params = null) : self
462 {
463 if (!$this->document instanceof Stream) {
464 throw UnavailableFeature::dueToUnsupportedStreamFilterApi(get_class($this->document));
465 }
466 $this->document->appendFilter($filtername, static::STREAM_FILTER_MODE, $params);
467 $this->stream_filters[$filtername] = \true;
468 $this->resetProperties();
469 $this->input_bom = null;
470 return $this;
471 }
472 }
473