1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
csvfile.php
См. документацию.
1<?php
2
3namespace Bitrix\Translate\IO;
4
5use Bitrix\Main;
6use Bitrix\Translate;
7
8class CsvFile
10{
11 // fields type with delimiter,
12 public const FIELDS_TYPE_FIXED_WIDTH = 'F';
13 // fields type fixed width
14 public const FIELDS_TYPE_WITH_DELIMITER = 'R';
15
16 public const ERROR_32K_FIELD_LENGTH = '32k_field_length';
17
22 protected $fieldsType = self::FIELDS_TYPE_WITH_DELIMITER;
23
24 // field delimiter
25 public const DELIMITER_TAB = "\t";
26 public const DELIMITER_ZPT = ',';
27 public const DELIMITER_SPS = ' ';
28 public const DELIMITER_TZP = ';';
29
34 protected $fieldDelimiter = self::DELIMITER_TZP;
35
36 // UTF-8 Byte-Order Mark
37 public const BOM_TYPE_UTF8 = "\xEF\xBB\xBF";
38
43 protected $bomMark = self::BOM_TYPE_UTF8;
44
49 protected $hasBom = false;
50
51 public const LINE_DELIMITER_WIN = "\r\n";
52 public const LINE_DELIMITER_UNIX = "\r";
53
58 protected $rowDelimiter = self::LINE_DELIMITER_WIN;
59
64 protected $widthMap = [];
65
70 protected $firstHeader = false;
71
76 private $fileSize;
81 private $currentPosition = 0;
83 private $buffer = '';
85 private $bufferPosition = 0;
87 private $bufferSize = 0;
88
89
95 public function openLoad(): bool
96 {
97 if ($this->isExists())
98 {
99 $this->open(Main\IO\FileStreamOpenMode::READ);
100
101 $this->fileSize = $this->getSize();
102 $this->checkUtf8Bom();
103 }
104
105 return $this->isExists() && $this->isReadable();
106 }
107
116 public function openWrite(string $mode = Main\IO\FileStreamOpenMode::WRITE): bool
117 {
118 $this->open($mode);
119
120 if (\is_resource($this->filePointer))
121 {
122 if ($mode === Main\IO\FileStreamOpenMode::WRITE)
123 {
124 $this->fileSize = 0;
125 if ($this->hasBom)
126 {
127 $this->fileSize = $this->write($this->bomMark);
128 }
129 }
130 else
131 {
132 $this->fileSize = $this->getSize();
133 }
134
135 return true;
136 }
137
138 return false;
139 }
140
147 public function setUtf8Bom(string $mark = self::BOM_TYPE_UTF8): self
148 {
149 $this->bomMark = $mark;
150
151 return $this;
152 }
153
159 public function hasUtf8Bom(): bool
160 {
161 return $this->hasBom;
162 }
163
171 public function prefaceWithUtf8Bom(bool $exists = true): self
172 {
173 $this->hasBom = $exists;
174
175 return $this;
176 }
177
182 public function checkUtf8Bom(): bool
183 {
184 $this->seek(0);
185 $bom = $this->read(strlen($this->bomMark));
186 if($bom === $this->bomMark)
187 {
188 $this->hasBom = true;
189 }
190
191 if ($this->hasBom)
192 {
193 $this->seek(strlen($this->bomMark));
194 }
195 else
196 {
197 $this->seek(0);
198 }
199
200 return $this->hasBom;
201 }
202
209 public function setFieldsType(string $fieldsType = self::FIELDS_TYPE_WITH_DELIMITER): self
210 {
211 $this->fieldsType =
212 ($fieldsType === self::FIELDS_TYPE_FIXED_WIDTH ? self::FIELDS_TYPE_FIXED_WIDTH : self::FIELDS_TYPE_WITH_DELIMITER);
213
214 return $this;
215 }
216
224 public function setFieldDelimiter(string $fieldDelimiter = self::DELIMITER_TZP): self
225 {
226 $this->fieldDelimiter = (\mb_strlen($fieldDelimiter) > 1 ? \mb_substr($fieldDelimiter, 0, 1) : $fieldDelimiter);
227
228 return $this;
229 }
230
238 public function setRowDelimiter(string $rowDelimiter = self::LINE_DELIMITER_WIN): self
239 {
240 $this->rowDelimiter = $rowDelimiter;
241
242 return $this;
243 }
244
251 public function setFirstHeader(bool $firstHeader = false): self
252 {
253 $this->firstHeader = $firstHeader;
254
255 return $this;
256 }
257
263 public function getFirstHeader(): bool
264 {
265 return $this->firstHeader;
266 }
267
274 public function setWidthMap(array $mapFields): self
275 {
276 $this->widthMap = [];
277 for ($i = 0, $n = \count($mapFields); $i < $n; $i++)
278 {
279 $this->widthMap[$i] = (int)$mapFields[$i];
280 }
281
282 return $this;
283 }
284
290 protected function fetchDelimiter(): ?array
291 {
292 $isInside = false;
293 $str = '';
294 $result = [];
295 while ($this->currentPosition <= $this->fileSize)
296 {
297 $ch = $this->buffer[$this->bufferPosition];
298 if ($ch === "\r" || $ch === "\n")
299 {
300 if (!$isInside)
301 {
302 while ($this->currentPosition <= $this->fileSize)
303 {
305 $ch = $this->buffer[$this->bufferPosition];
306 if ($ch !== "\r" && $ch !== "\n")
307 {
308 break;
309 }
310 }
311 if ($this->firstHeader)
312 {
313 $this->firstHeader = false;
314 $result = [];
315 $str = '';
316 continue;
317 }
318
319 $result[] = $str;
320
321 return $result;
322 }
323 }
324 elseif ($ch === "\"")
325 {
326 if (!$isInside)
327 {
328 $isInside = true;
330 continue;
331 }
332
334 if ($this->buffer[$this->bufferPosition] !== "\"")
335 {
336 $isInside = false;
337 continue;
338 }
339 }
340 elseif ($ch === $this->fieldDelimiter)
341 {
342 if (!$isInside)
343 {
344 $result[] = $str;
345 $str = '';
347 continue;
348 }
349 }
350
351 //inline "call"
352 $this->currentPosition ++;
353 $this->bufferPosition ++;
354 if ($this->bufferPosition >= $this->bufferSize)
355 {
356 $this->buffer = $this->read(1024 * 1024);
357 $this->bufferSize = strlen($this->buffer);
358 $this->bufferPosition = 0;
359 }
360
361 $str .= $ch;
362 }
363
364 if ($str !== '')
365 {
366 $result[] = $str;
367 }
368
369 if ($result === [])
370 {
371 $result = null;
372 }
373
374 return $result;
375 }
376
382 protected function fetchWidth(): ?array
383 {
384 $str = '';
385 $ind = 1;
386 $jnd = 0;
387 $result = [];
388
389 while ($this->currentPosition <= $this->fileSize)
390 {
391 $ch = $this->buffer[$this->bufferPosition];
392 if ($ch === "\r" || $ch === "\n")
393 {
394 while ($this->currentPosition <= $this->fileSize)
395 {
397 $ch = $this->buffer[$this->bufferPosition];
398 if ($ch !== "\r" && $ch !== "\n")
399 {
400 break;
401 }
402 }
403 if ($this->firstHeader)
404 {
405 $this->firstHeader = false;
406 $result = [];
407 $ind = 1;
408 $str = '';
409 continue;
410 }
411
412 $result[] = $str;
413
414 return $result;
415 }
416 if ($ind === $this->widthMap[$jnd])
417 {
418 $result[] = $str. $ch;
419 $str = '';
421 $ind ++;
422 $jnd ++;
423 continue;
424 }
425
426 //inline "call"
427 $this->currentPosition ++;
428 $this->bufferPosition ++;
429 if($this->bufferPosition >= $this->bufferSize)
430 {
431 $this->buffer = $this->read( 1024 * 1024);
432 $this->bufferSize = strlen($this->buffer);
433 $this->bufferPosition = 0;
434 }
435
436 $ind ++;
437 $str .= $ch;
438 }
439
440 if ($str !== '')
441 {
442 $result[] = $str;
443 }
444
445 if ($result === [])
446 {
447 $result = null;
448 }
449
450 return $result;
451 }
452
458 public function fetch(): ?array
459 {
460 if ($this->fieldsType === self::FIELDS_TYPE_WITH_DELIMITER)
461 {
462 if ($this->fieldDelimiter === '')
463 {
464 return null;
465 }
466
467 return $this->fetchDelimiter();
468 }
469
470 if (empty($this->widthMap))
471 {
472 return null;
473 }
474
475 return $this->fetchWidth();
476 }
477
483 protected function incrementCurrentPosition(): void
484 {
485 $this->currentPosition ++;
486 $this->bufferPosition ++;
487 if ($this->bufferPosition >= $this->bufferSize)
488 {
489 $this->buffer = $this->read( 1024 * 1024);
490 $this->bufferSize = strlen($this->buffer);
491 $this->bufferPosition = 0;
492 }
493 }
494
500 public function moveFirst(): void
501 {
502 $this->setPos(0);
503 }
504
510 public function getPos(): int
511 {
512 return $this->currentPosition;
513 }
514
522 public function setPos(int $position = 0): void
523 {
524 if ($position <= $this->fileSize)
525 {
526 $this->currentPosition = $position;
527 }
528 else
529 {
530 $this->currentPosition = $this->fileSize;
531 }
532
533 $pos = $this->currentPosition;
534 if($this->hasBom)
535 {
536 $pos += 3;
537 }
538 $this->seek($pos);
539
540 $this->buffer = $this->read(1024 * 1024);
541
542 $this->bufferSize = strlen($this->buffer);
543 $this->bufferPosition = 0;
544 }
545
553 public function put(array $fields): bool
554 {
555 $length = false;
556 $throw32KWarning = false;
557 if ($this->fieldsType == self::FIELDS_TYPE_WITH_DELIMITER)
558 {
559 $content = '';
560 for ($i = 0, $n = \count($fields); $i < $n; $i++)
561 {
562 if ($i>0)
563 {
565 }
566 //$pos1 = strpos($fields[$i], $this->fieldDelimiter);
567 //$pos2 = $pos1 || strpos($fields[$i], "\"");
568 //$pos3 = $pos2 || strpos($fields[$i], "\n");
569 //$pos4 = $pos3 || strpos($fields[$i], "\r");
570 //if ($pos1 !== false || $pos2 !== false || $pos3 !== false || $pos4 !== false)
571 if ($fields[$i] === null)
572 {
573 $fields[$i] = '';
574 }
575 elseif (\preg_match("#[\"\n\r]+#u", $fields[$i]))
576 {
577 $fields[$i] = \str_replace("\"", "\"\"", $fields[$i]);
578 //$fields[$i] = str_replace("\\", "\\\\", $fields[$i]);
579 }
580 $content .= "\"";
581 $content .= $fields[$i];
582 $content .= "\"";
583
584 // ms excel las limitation with total number of characters that a cell can contain 32767 characters
585 if ($throw32KWarning !== true && strlen($fields[$i]) > 32767)
586 {
587 $throw32KWarning = true;
588 }
589 }
590 if ($content !== '')
591 {
593
594 $length = $this->write($content);
595 if ($length !== false)
596 {
597 $this->fileSize += $length;
598 }
599 }
600 }
601 // todo: $this->fieldsType == self::FIELDS_TYPE_FIXED_WIDTH
602
603 if ($throw32KWarning)
604 {
605 if (!$this->hasError(self::ERROR_32K_FIELD_LENGTH))
606 {
607 $this->addError(new Main\Error(
608 'Excel has limit when the total number of characters that a cell can contain is 32767 characters.',
609 self::ERROR_32K_FIELD_LENGTH
610 ));
611 }
612 }
613
614 return ($length !== false);
615 }
616}
setRowDelimiter(string $rowDelimiter=self::LINE_DELIMITER_WIN)
Определения csvfile.php:238
fetchDelimiter()
Определения csvfile.php:290
setFirstHeader(bool $firstHeader=false)
Определения csvfile.php:251
getFirstHeader()
Определения csvfile.php:263
prefaceWithUtf8Bom(bool $exists=true)
Определения csvfile.php:171
openWrite(string $mode=Main\IO\FileStreamOpenMode::WRITE)
Определения csvfile.php:116
put(array $fields)
Определения csvfile.php:553
const FIELDS_TYPE_FIXED_WIDTH
Определения csvfile.php:12
const FIELDS_TYPE_WITH_DELIMITER
Определения csvfile.php:14
setFieldsType(string $fieldsType=self::FIELDS_TYPE_WITH_DELIMITER)
Определения csvfile.php:209
const LINE_DELIMITER_WIN
Определения csvfile.php:51
const DELIMITER_ZPT
Определения csvfile.php:26
$fieldDelimiter
Определения csvfile.php:34
checkUtf8Bom()
Определения csvfile.php:182
const DELIMITER_TAB
Определения csvfile.php:25
const BOM_TYPE_UTF8
Определения csvfile.php:37
setUtf8Bom(string $mark=self::BOM_TYPE_UTF8)
Определения csvfile.php:147
setWidthMap(array $mapFields)
Определения csvfile.php:274
const ERROR_32K_FIELD_LENGTH
Определения csvfile.php:16
incrementCurrentPosition()
Определения csvfile.php:483
setPos(int $position=0)
Определения csvfile.php:522
setFieldDelimiter(string $fieldDelimiter=self::DELIMITER_TZP)
Определения csvfile.php:224
const DELIMITER_SPS
Определения csvfile.php:27
const LINE_DELIMITER_UNIX
Определения csvfile.php:52
const DELIMITER_TZP
Определения csvfile.php:28
$str
Определения commerceml2.php:63
$content
Определения commerceml.php:144
buffer
Определения ebay_mip_setup.php:303
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
else $ch
Определения group_list_element_edit.php:27
Определения Image.php:9
Определения directory.php:3
addError(Main\Error $error)
Определения error.php:22
trait Error
Определения error.php:11
hasError($code)
Определения error.php:146
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$n
Определения update_log.php:107
$fields
Определения yandex_run.php:501