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 / Writer.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
Writer.php
283 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 function array_reduce;
15 use function implode;
16 use function preg_match;
17 use function preg_quote;
18 use function str_replace;
19 use function strlen;
20 use const PHP_VERSION_ID;
21 use const SEEK_CUR;
22 use const STREAM_FILTER_WRITE;
23 /**
24 * A class to insert records into a CSV Document.
25 * @internal
26 */
27 class Writer extends AbstractCsv
28 {
29 protected const STREAM_FILTER_MODE = STREAM_FILTER_WRITE;
30 /**
31 * callable collection to format the record before insertion.
32 *
33 * @var array<callable>
34 */
35 protected $formatters = [];
36 /**
37 * callable collection to validate the record before insertion.
38 *
39 * @var array<callable>
40 */
41 protected $validators = [];
42 /**
43 * newline character.
44 *
45 * @var string
46 */
47 protected $newline = "\n";
48 /**
49 * Insert records count for flushing.
50 *
51 * @var int
52 */
53 protected $flush_counter = 0;
54 /**
55 * Buffer flush threshold.
56 *
57 * @var int|null
58 */
59 protected $flush_threshold;
60 /**
61 * Regular expression used to detect if RFC4180 formatting is necessary.
62 *
63 * @var string
64 */
65 protected $rfc4180_regexp;
66 /**
67 * double enclosure for RFC4180 compliance.
68 *
69 * @var string
70 */
71 protected $rfc4180_enclosure;
72 /**
73 * {@inheritdoc}
74 */
75 protected function resetProperties() : void
76 {
77 $characters = preg_quote($this->delimiter, '/') . '|' . preg_quote($this->enclosure, '/');
78 $this->rfc4180_regexp = '/[\\s|' . $characters . ']/x';
79 $this->rfc4180_enclosure = $this->enclosure . $this->enclosure;
80 }
81 /**
82 * Returns the current newline sequence characters.
83 */
84 public function getNewline() : string
85 {
86 return $this->newline;
87 }
88 /**
89 * Get the flush threshold.
90 *
91 */
92 public function getFlushThreshold() : ?int
93 {
94 return $this->flush_threshold;
95 }
96 /**
97 * Adds multiple records to the CSV document.
98 *
99 * @see Writer::insertOne
100 */
101 public function insertAll(iterable $records) : int
102 {
103 $bytes = 0;
104 foreach ($records as $record) {
105 $bytes += $this->insertOne($record);
106 }
107 $this->flush_counter = 0;
108 $this->document->fflush();
109 return $bytes;
110 }
111 /**
112 * Adds a single record to a CSV document.
113 *
114 * A record is an array that can contains scalar types values, NULL values
115 * or objects implementing the __toString method.
116 *
117 * @throws CannotInsertRecord If the record can not be inserted
118 */
119 public function insertOne(array $record) : int
120 {
121 $method = 'addRecord';
122 if (70400 > PHP_VERSION_ID && '' === $this->escape) {
123 $method = 'addRFC4180CompliantRecord';
124 }
125 $record = array_reduce($this->formatters, [$this, 'formatRecord'], $record);
126 $this->validateRecord($record);
127 $bytes = $this->{$method}($record);
128 if (\false === $bytes || 0 >= $bytes) {
129 throw CannotInsertRecord::triggerOnInsertion($record);
130 }
131 return $bytes + $this->consolidate();
132 }
133 /**
134 * Adds a single record to a CSV Document using PHP algorithm.
135 *
136 * @see https://php.net/manual/en/function.fputcsv.php
137 *
138 * @return int|false
139 */
140 protected function addRecord(array $record)
141 {
142 if (PHP_VERSION_ID < 80100) {
143 return $this->document->fputcsv($record, $this->delimiter, $this->enclosure, $this->escape);
144 }
145 return $this->document->fputcsv($record, $this->delimiter, $this->enclosure, $this->escape, $this->newline);
146 }
147 /**
148 * Adds a single record to a CSV Document using RFC4180 algorithm.
149 *
150 * @see https://php.net/manual/en/function.fputcsv.php
151 * @see https://php.net/manual/en/function.fwrite.php
152 * @see https://tools.ietf.org/html/rfc4180
153 * @see http://edoceo.com/utilitas/csv-file-format
154 *
155 * String conversion is done without any check like fputcsv.
156 *
157 * - Emits E_NOTICE on Array conversion (returns the 'Array' string)
158 * - Throws catchable fatal error on objects that can not be converted
159 * - Returns resource id without notice or error (returns 'Resource id #2')
160 * - Converts boolean true to '1', boolean false to the empty string
161 * - Converts null value to the empty string
162 *
163 * Fields must be delimited with enclosures if they contains :
164 *
165 * - Embedded whitespaces
166 * - Embedded delimiters
167 * - Embedded line-breaks
168 * - Embedded enclosures.
169 *
170 * Embedded enclosures must be doubled.
171 *
172 * The LF character is added at the end of each record to mimic fputcsv behavior
173 *
174 * @return int|false
175 */
176 protected function addRFC4180CompliantRecord(array $record)
177 {
178 foreach ($record as &$field) {
179 $field = (string) $field;
180 if (1 === preg_match($this->rfc4180_regexp, $field)) {
181 $field = $this->enclosure . str_replace($this->enclosure, $this->rfc4180_enclosure, $field) . $this->enclosure;
182 }
183 }
184 unset($field);
185 $newline = $this->newline;
186 if (PHP_VERSION_ID < 80100) {
187 $newline = "\n";
188 }
189 return $this->document->fwrite(implode($this->delimiter, $record) . $newline);
190 }
191 /**
192 * Format a record.
193 *
194 * The returned array must contain
195 * - scalar types values,
196 * - NULL values,
197 * - or objects implementing the __toString() method.
198 */
199 protected function formatRecord(array $record, callable $formatter) : array
200 {
201 return $formatter($record);
202 }
203 /**
204 * Validate a record.
205 *
206 * @throws CannotInsertRecord If the validation failed
207 */
208 protected function validateRecord(array $record) : void
209 {
210 foreach ($this->validators as $name => $validator) {
211 if (\true !== $validator($record)) {
212 throw CannotInsertRecord::triggerOnValidation($name, $record);
213 }
214 }
215 }
216 /**
217 * Apply post insertion actions.
218 */
219 protected function consolidate() : int
220 {
221 $bytes = 0;
222 if (80100 > PHP_VERSION_ID && "\n" !== $this->newline) {
223 $this->document->fseek(-1, SEEK_CUR);
224 /** @var int $newlineBytes */
225 $newlineBytes = $this->document->fwrite($this->newline, strlen($this->newline));
226 $bytes = $newlineBytes - 1;
227 }
228 if (null === $this->flush_threshold) {
229 return $bytes;
230 }
231 ++$this->flush_counter;
232 if (0 === $this->flush_counter % $this->flush_threshold) {
233 $this->flush_counter = 0;
234 $this->document->fflush();
235 }
236 return $bytes;
237 }
238 /**
239 * Adds a record formatter.
240 */
241 public function addFormatter(callable $formatter) : self
242 {
243 $this->formatters[] = $formatter;
244 return $this;
245 }
246 /**
247 * Adds a record validator.
248 */
249 public function addValidator(callable $validator, string $validator_name) : self
250 {
251 $this->validators[$validator_name] = $validator;
252 return $this;
253 }
254 /**
255 * Sets the newline sequence.
256 */
257 public function setNewline(string $newline) : self
258 {
259 $this->newline = $newline;
260 return $this;
261 }
262 /**
263 * Set the flush threshold.
264 *
265 * @param ?int $threshold
266 *
267 * @throws InvalidArgument if the threshold is a integer lesser than 1
268 */
269 public function setFlushThreshold(?int $threshold) : self
270 {
271 if ($threshold === $this->flush_threshold) {
272 return $this;
273 }
274 if (null !== $threshold && 1 > $threshold) {
275 throw InvalidArgument::dueToInvalidThreshold($threshold, __METHOD__);
276 }
277 $this->flush_threshold = $threshold;
278 $this->flush_counter = 0;
279 $this->document->fflush();
280 return $this;
281 }
282 }
283