1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
cml2.php
См. документацию.
1<?php
2
5
6/*
7This class is used to parse and load an xml file into database table.
8*/
10{
11 public const UNPACK_STATUS_ERROR = -1;
12 public const UNPACK_STATUS_CONTINUE = 1;
13 public const UNPACK_STATUS_FINAL = 2;
14 var $_table_name = "";
15 var $_sessid = "";
16
17 var $charset = false;
20
21 var $read_size = 10240;
22 var $buf = "";
24 var $buf_len = 0;
25
26 function __construct($table_name = "b_xml_tree")
27 {
28 $this->_table_name = strtolower($table_name);
29 }
30
31 function StartSession($sess_id)
32 {
33 global $DB;
34
35 if(!$DB->TableExists($this->_table_name))
36 {
37 $res = $this->CreateTemporaryTables(true);
38 if($res)
39 $res = $this->IndexTemporaryTables(true);
40 }
41 else
42 {
43 $res = true;
44 }
45
46 if($res)
47 {
48 $this->_sessid = substr($sess_id, 0, 32);
49
50 $rs = $this->GetList(array(), array("PARENT_ID" => -1), array("ID", "NAME"));
51 if(!$rs->Fetch())
52 {
53 $this->Add(array(
54 "PARENT_ID" => -1,
55 "LEFT_MARGIN" => 0,
56 "NAME" => "SESS_ID",
57 "VALUE" => ConvertDateTime(ConvertTimeStamp(false, "FULL"), "YYYY-MM-DD HH:MI:SS"),
58 ));
59 }
60 }
61
62 return $res;
63 }
64
65 function GetSessionRoot()
66 {
67 global $DB;
68 $rs = $DB->Query("SELECT ID MID from ".$this->_table_name." WHERE SESS_ID = '".$DB->ForSQL($this->_sessid)."' AND PARENT_ID = 0");
69 $ar = $rs->Fetch();
70 return $ar["MID"];
71 }
72
73 function EndSession()
74 {
75 global $DB;
76
77 //Delete "expired" sessions
78 $expired = ConvertDateTime(ConvertTimeStamp(time()-3600, "FULL"), "YYYY-MM-DD HH:MI:SS");
79
80 $rs = $DB->Query("select ID, SESS_ID, VALUE from ".$this->_table_name." where PARENT_ID = -1 AND NAME = 'SESS_ID' ORDER BY ID");
81 while($ar = $rs->Fetch())
82 {
83 if($ar["SESS_ID"] == $this->_sessid || $ar["VALUE"] < $expired)
84 {
85 $DB->Query("DELETE from ".$this->_table_name." WHERE SESS_ID = '".$DB->ForSQL($ar["SESS_ID"])."'");
86 }
87 }
88 return true;
89 }
90
91 public function GetRoot()
92 {
93 global $DB;
94 $rs = $DB->Query("SELECT ID MID from ".$this->_table_name." WHERE PARENT_ID = 0");
95 $ar = $rs->Fetch();
96 return $ar["MID"];
97 }
98
99 public function initializeTemporaryTables(): bool
100 {
101 $initResult = true;
102 $isNeedCreate = false;
103
104 if ($this->IsExistTemporaryTable())
105 {
106 if ($this->isTableStructureCorrect())
107 {
109 }
110 else
111 {
112 $this->DropTemporaryTables();
113 $isNeedCreate = true;
114 }
115 }
116 else
117 {
118 $isNeedCreate = true;
119 }
120
121 if ($isNeedCreate)
122 {
123 $initResult = $this->CreateTemporaryTables();
124 }
125
126 return $initResult;
127 }
128
129 public function truncateTemporaryTables(): bool
130 {
132
133 if ($connection->isTableExists($this->_table_name))
134 {
135 $connection->truncateTable($this->_table_name);
136 }
137
138 return true;
139 }
140
141 /*
142 This function have to called once at the import start.
143
144 return : result of the CDatabase::Query method
145 We use drop due to mysql innodb slow truncate bug.
146 */
147 public function DropTemporaryTables()
148 {
150
151 if ($connection->isTableExists($this->_table_name))
152 {
153 $connection->dropTable($this->_table_name);
154 }
155
156 return true;
157 }
158
159 public function CreateTemporaryTables($with_sess_id = false)
160 {
162
163 if ($connection->isTableExists($this->_table_name))
164 {
165 return false;
166 }
167
168 if (
169 $connection instanceof Main\DB\MysqlCommonConnection
170 && defined('MYSQL_TABLE_TYPE')
171 && MYSQL_TABLE_TYPE !== ''
172 )
173 {
174 // TODO: remove try-catch when mysql 8.0 will be minimal system requirement
175 try
176 {
177 $connection->query('SET default_storage_engine = \'' . MYSQL_TABLE_TYPE . '\'');
178 }
179 catch (SqlQueryException)
180 {
181 try
182 {
183 $connection->query('SET storage_engine = \''.MYSQL_TABLE_TYPE.'\'');
184 }
185 catch (SqlQueryException)
186 {
187
188 }
189 }
190 }
191
192 $fields = [
193 'ID' => (new Main\ORM\Fields\IntegerField('ID'))->configureSize(8),
194 'SESS_ID' => (new Main\ORM\Fields\StringField('SESS_ID'))->configureSize(8),
195 'PARENT_ID' => (new Main\ORM\Fields\IntegerField('PARENT_ID'))->configureSize(8)->configureNullable(),
196 'LEFT_MARGIN' => (new Main\ORM\Fields\IntegerField('LEFT_MARGIN'))->configureNullable(),
197 'RIGHT_MARGIN' => (new Main\ORM\Fields\IntegerField('RIGHT_MARGIN'))->configureNullable(),
198 'DEPTH_LEVEL' => (new Main\ORM\Fields\IntegerField('DEPTH_LEVEL'))->configureNullable(),
199 'NAME' => (new Main\ORM\Fields\StringField('NAME'))->configureSize(255)->configureNullable(),
200 'VALUE' => (new Main\ORM\Fields\TextField('VALUE'))->configureLong()->configureNullable(),
201 'ATTRIBUTES' => (new Main\ORM\Fields\TextField('ATTRIBUTES'))->configureNullable(),
202 ];
203 if (!$with_sess_id)
204 {
205 unset($fields['SESS_ID']);
206 }
207
208 $connection->createTable($this->_table_name, $fields, ['ID'] ,['ID']);
209
210 if (defined('BX_XML_CREATE_INDEXES_IMMEDIATELY'))
211 {
212 $this->IndexTemporaryTables($with_sess_id);
213 }
214
215 return true;
216 }
217
219 {
220 if (!isset($this) || !is_object($this) || $this->_table_name == '')
221 {
222 $ob = new CIBlockXMLFile;
223
224 return $ob->IsExistTemporaryTable();
225 }
226 else
227 {
229
230 return $connection->isTableExists($this->_table_name);
231 }
232 }
233
234 public function isTableStructureCorrect($withSessId = false): bool
235 {
237
238 $tableFields = $connection->getTableFields($this->_table_name);
239
240 if (
241 empty($tableFields['ID'])
242 || ($withSessId && empty($tableFields['SESS_ID']))
243 || empty($tableFields['PARENT_ID'])
244 || empty($tableFields['LEFT_MARGIN'])
245 || empty($tableFields['RIGHT_MARGIN'])
246 || empty($tableFields['DEPTH_LEVEL'])
247 || empty($tableFields['NAME'])
248 || empty($tableFields['VALUE'])
249 || empty($tableFields['ATTRIBUTES'])
250 )
251 {
252 return false;
253 }
254
255 return true;
256 }
257
258 function GetCountItemsWithParent($parentID)
259 {
260 global $DB;
261
262 $parentID = (int)$parentID;
263
264 if (!isset($this) || !is_object($this) || $this->_table_name == '')
265 {
266 $ob = new CIBlockXMLFile;
267 return $ob->GetCountItemsWithParent($parentID);
268 }
269 else
270 {
271 $parentID = (int)$parentID;
272 $rs = $DB->Query("select count(*) C from ".$this->_table_name." where PARENT_ID = ".$parentID);
273 $ar = $rs->Fetch();
274 return $ar['C'];
275 }
276 }
277
278 /*
279 This function indexes contents of the loaded data for future lookups.
280 May be called after tables creation and loading will perform slowly.
281 But it is recommented to call this function after all data load.
282 This is much faster.
283
284 return : result of the CDatabase::Query method
285 */
286 public function IndexTemporaryTables($with_sess_id = false)
287 {
289
290 if($with_sess_id)
291 {
292 if (!$connection->isIndexExists($this->_table_name, ['SESS_ID', 'PARENT_ID']))
293 {
294 $connection->createIndex($this->_table_name, 'ix_' . $this->_table_name . '_parent', ['SESS_ID', 'PARENT_ID']);
295 }
296
297 if (!$connection->isIndexExists($this->_table_name, ['SESS_ID', 'LEFT_MARGIN']))
298 {
299 $connection->createIndex($this->_table_name, 'ix_' . $this->_table_name . '_left', ['SESS_ID', 'LEFT_MARGIN']);
300 }
301 }
302 else
303 {
304 if (!$connection->isIndexExists($this->_table_name, ['PARENT_ID']))
305 {
306 $connection->createIndex($this->_table_name, 'ix_' . $this->_table_name . '_parent', ['PARENT_ID']);
307 }
308
309 if (!$connection->isIndexExists($this->_table_name, ['LEFT_MARGIN']))
310 {
311 $connection->createIndex($this->_table_name, 'ix_' . $this->_table_name . '_left', ['LEFT_MARGIN']);
312 }
313 }
314
315 return true;
316 }
317
318 function Add($arFields)
319 {
320 global $DB;
321
322 $strSql1 = "PARENT_ID, LEFT_MARGIN, RIGHT_MARGIN, DEPTH_LEVEL, NAME";
323 $strSql2 = (int)$arFields["PARENT_ID"] .", "
324 . (int)$arFields["LEFT_MARGIN"] . ", "
325 . (int)($arFields["RIGHT_MARGIN"] ?? 0) . ", "
326 . (int)($arFields["DEPTH_LEVEL"] ?? 0) .", '"
327 . $DB->ForSQL($arFields["NAME"] ?? '', 255)
328 ."'"
329 ;
330
331 if (isset($arFields["ATTRIBUTES"]))
332 {
333 $strSql1 .= ", ATTRIBUTES";
334 $strSql2 .= ", '".$DB->ForSQL($arFields["ATTRIBUTES"])."'";
335 }
336
337 if (isset($arFields["VALUE"]))
338 {
339 $strSql1 .= ", VALUE";
340 $strSql2 .= ", '".$DB->ForSQL($arFields["VALUE"])."'";
341 }
342
343 if($this->_sessid)
344 {
345 $strSql1 .= ", SESS_ID";
346 $strSql2 .= ", '".$DB->ForSQL($this->_sessid)."'";
347 }
348
349 $strSql = "INSERT INTO ".$this->_table_name." (".$strSql1.") VALUES (".$strSql2.")";
350
351 $DB->Query($strSql);
352
353 return $DB->LastID();
354 }
355
357 {
359 }
360
361 /*
362 Reads portion of xml data.
363
364 hFile - file handle opened with fopen function for reading
365 NS - will be populated with to members
366 charset parameter is used to recode file contents if needed.
367 element_stack parameters save parsing stack of xml tree parents.
368 file_position parameters marks current file position.
369 time_limit - duration of one step in seconds.
370
371 NS have to be preserved between steps.
372 They automatically extracted from xml file and should not be modified!
373 */
374 function ReadXMLToDatabase($fp, &$NS, $time_limit=0, $read_size = 1024)
375 {
376 //Initialize object
377 if(!array_key_exists("charset", $NS))
378 $NS["charset"] = false;
379 $this->charset = &$NS["charset"];
380
381 if(!array_key_exists("element_stack", $NS))
382 $NS["element_stack"] = array();
383 $this->element_stack = &$NS["element_stack"];
384
385 if(!array_key_exists("file_position", $NS))
386 $NS["file_position"] = 0;
387 $this->file_position = &$NS["file_position"];
388
389 $this->read_size = $read_size;
390 $this->buf = "";
391 $this->buf_position = 0;
392 $this->buf_len = 0;
393
394 //This is an optimization. We assume than no step can take more than one year.
395 if($time_limit > 0)
396 $end_time = time() + $time_limit;
397 else
398 $end_time = time() + 365*24*3600; // One year
399
400 $cs = $this->charset;
401 fseek($fp, $this->file_position);
402 while(($xmlChunk = $this->_get_xml_chunk($fp)) !== false)
403 {
404 if($cs)
405 {
406 $xmlChunk = Main\Text\Encoding::convertEncoding($xmlChunk, $cs, LANG_CHARSET);
407 }
408
409 if($xmlChunk[0] == "/")
410 {
411 $this->_end_element($xmlChunk);
412 if(time() > $end_time)
413 break;
414 }
415 elseif($xmlChunk[0] == "!" || $xmlChunk[0] == "?")
416 {
417 if(strncmp($xmlChunk, "?xml", 4) === 0)
418 {
419 if(preg_match('#encoding[\s]*=[\s]*"(.*?)"#i', $xmlChunk, $arMatch))
420 {
421 $this->charset = $arMatch[1];
422 if(strtoupper($this->charset) === strtoupper(LANG_CHARSET))
423 $this->charset = false;
424 $cs = $this->charset;
425 }
426 }
427 }
428 else
429 {
430 $this->_start_element($xmlChunk);
431 }
432
433 }
434
435 return feof($fp);
436 }
437
445 function _get_xml_chunk($fp)
446 {
447 if($this->buf_position >= $this->buf_len)
448 {
449 if(!feof($fp))
450 {
451 $this->buf = fread($fp, $this->read_size);
452 $this->buf_position = 0;
453 $this->buf_len = strlen($this->buf);
454 }
455 else
456 return false;
457 }
458
459 //Skip line delimiters (ltrim)
460 $xml_position = strpos($this->buf, "<", $this->buf_position);
461 while($xml_position === $this->buf_position)
462 {
463 $this->buf_position++;
464 $this->file_position++;
465 //Buffer ended with white space so we can refill it
466 if($this->buf_position >= $this->buf_len)
467 {
468 if(!feof($fp))
469 {
470 $this->buf = fread($fp, $this->read_size);
471 $this->buf_position = 0;
472 $this->buf_len = strlen($this->buf);
473 }
474 else
475 return false;
476 }
477 $xml_position = strpos($this->buf, "<", $this->buf_position);
478 }
479
480 //Let's find next line delimiter
481 while($xml_position===false)
482 {
483 $next_search = $this->buf_len;
484 //Delimiter not in buffer so try to add more data to it
485 if(!feof($fp))
486 {
487 $this->buf .= fread($fp, $this->read_size);
488 $this->buf_len = strlen($this->buf);
489 }
490 else
491 break;
492
493 //Let's find xml tag start
494 $xml_position = strpos($this->buf, "<", $next_search);
495 }
496 if($xml_position===false)
497 $xml_position = $this->buf_len+1;
498
499 $len = $xml_position-$this->buf_position;
500 $this->file_position += $len;
501 $result = substr($this->buf, $this->buf_position, $len);
502 $this->buf_position = $xml_position;
503
504 return $result;
505 }
506
516 {
517 if($this->buf_position >= $this->buf_len)
518 {
519 if(!feof($fp))
520 {
521 $this->buf = fread($fp, $this->read_size);
522 $this->buf_position = 0;
523 $this->buf_len = mb_orig_strlen($this->buf);
524 }
525 else
526 return false;
527 }
528
529 //Skip line delimiters (ltrim)
530 $xml_position = mb_orig_strpos($this->buf, "<", $this->buf_position);
531 while($xml_position === $this->buf_position)
532 {
533 $this->buf_position++;
534 $this->file_position++;
535 //Buffer ended with white space so we can refill it
536 if($this->buf_position >= $this->buf_len)
537 {
538 if(!feof($fp))
539 {
540 $this->buf = fread($fp, $this->read_size);
541 $this->buf_position = 0;
542 $this->buf_len = mb_orig_strlen($this->buf);
543 }
544 else
545 return false;
546 }
547 $xml_position = mb_orig_strpos($this->buf, "<", $this->buf_position);
548 }
549
550 //Let's find next line delimiter
551 while($xml_position===false)
552 {
553 $next_search = $this->buf_len;
554 //Delimiter not in buffer so try to add more data to it
555 if(!feof($fp))
556 {
557 $this->buf .= fread($fp, $this->read_size);
558 $this->buf_len = mb_orig_strlen($this->buf);
559 }
560 else
561 break;
562
563 //Let's find xml tag start
564 $xml_position = mb_orig_strpos($this->buf, "<", $next_search);
565 }
566 if($xml_position===false)
567 $xml_position = $this->buf_len+1;
568
569 $len = $xml_position-$this->buf_position;
570 $this->file_position += $len;
571 $result = mb_orig_substr($this->buf, $this->buf_position, $len);
572 $this->buf_position = $xml_position;
573
574 return $result;
575 }
576
585 function _get_xml_chunk_mb($fp)
586 {
587 if($this->buf_position >= $this->buf_len)
588 {
589 if(!feof($fp))
590 {
591 $this->buf = fread($fp, $this->read_size);
592 $this->buf_position = 0;
593 $this->buf_len = strlen($this->buf);
594 }
595 else
596 return false;
597 }
598
599 //Skip line delimiters (ltrim)
600 $xml_position = strpos($this->buf, "<", $this->buf_position);
601 while($xml_position === $this->buf_position)
602 {
603 $this->buf_position++;
604 $this->file_position++;
605 //Buffer ended with white space so we can refill it
606 if($this->buf_position >= $this->buf_len)
607 {
608 if(!feof($fp))
609 {
610 $this->buf = fread($fp, $this->read_size);
611 $this->buf_position = 0;
612 $this->buf_len = strlen($this->buf);
613 }
614 else
615 return false;
616 }
617 $xml_position = strpos($this->buf, "<", $this->buf_position);
618 }
619
620 //Let's find next line delimiter
621 while($xml_position===false)
622 {
623 $next_search = $this->buf_len;
624 //Delimiter not in buffer so try to add more data to it
625 if(!feof($fp))
626 {
627 $this->buf .= fread($fp, $this->read_size);
628 $this->buf_len = strlen($this->buf);
629 }
630 else
631 break;
632
633 //Let's find xml tag start
634 $xml_position = strpos($this->buf, "<", $next_search);
635 }
636 if($xml_position===false)
637 $xml_position = $this->buf_len+1;
638
639 $len = $xml_position-$this->buf_position;
640 $this->file_position += $len;
641 $result = substr($this->buf, $this->buf_position, $len);
642 $this->buf_position = $xml_position;
643
644 return $result;
645 }
646
647 /*
648 Internal function.
649 Stores an element into xml database tree.
650 */
651 function _start_element($xmlChunk)
652 {
653 static $search = array(
654 "'&(quot|#34);'i",
655 "'&(lt|#60);'i",
656 "'&(gt|#62);'i",
657 "'&(amp|#38);'i",
658 );
659
660 static $replace = array(
661 "\"",
662 "<",
663 ">",
664 "&",
665 );
666
667 $p = strpos($xmlChunk, ">");
668 if($p !== false)
669 {
670 if(substr($xmlChunk, $p - 1, 1) == "/")
671 {
672 $bHaveChildren = false;
673 $elementName = substr($xmlChunk, 0, $p - 1);
674 $DBelementValue = false;
675 }
676 else
677 {
678 $bHaveChildren = true;
679 $elementName = substr($xmlChunk, 0, $p);
680 $elementValue = substr($xmlChunk, $p + 1);
681 if(preg_match("/^\s*$/", $elementValue))
682 $DBelementValue = false;
683 elseif(strpos($elementValue, "&") === false)
684 $DBelementValue = $elementValue;
685 else
686 $DBelementValue = preg_replace($search, $replace, $elementValue);
687 }
688
689 if(($ps = strpos($elementName, " "))!==false)
690 {
691 //Let's handle attributes
692 $elementAttrs = substr($elementName, $ps + 1);
693 $elementName = substr($elementName, 0, $ps);
694 preg_match_all("/(\\S+)\\s*=\\s*[\"](.*?)[\"]/su", $elementAttrs, $attrs_tmp);
695 $attrs = array();
696 if(!str_contains($elementAttrs, "&"))
697 {
698 foreach($attrs_tmp[1] as $i=>$attrs_tmp_1)
699 $attrs[$attrs_tmp_1] = $attrs_tmp[2][$i];
700 }
701 else
702 {
703 foreach($attrs_tmp[1] as $i=>$attrs_tmp_1)
704 $attrs[$attrs_tmp_1] = preg_replace($search, $replace, $attrs_tmp[2][$i]);
705 }
706 $DBelementAttrs = serialize($attrs);
707 }
708 else
709 $DBelementAttrs = false;
710
711 if($c = count($this->element_stack))
712 $parent = $this->element_stack[$c-1];
713 else
714 $parent = array("ID"=>"NULL", "L"=>0, "R"=>1);
715
716 $left = $parent["R"];
717 $right = $left+1;
718
720 "PARENT_ID" => $parent["ID"],
721 "LEFT_MARGIN" => $left,
722 "RIGHT_MARGIN" => $right,
723 "DEPTH_LEVEL" => $c,
724 "NAME" => $elementName,
725 );
726 if($DBelementValue !== false)
727 {
728 $arFields["VALUE"] = $DBelementValue;
729 }
730 if($DBelementAttrs !== false)
731 {
732 $arFields["ATTRIBUTES"] = $DBelementAttrs;
733 }
734
735 $ID = $this->Add($arFields);
736
737 if($bHaveChildren)
738 $this->element_stack[] = array("ID"=>$ID, "L"=>$left, "R"=>$right, "RO"=>$right);
739 else
740 $this->element_stack[$c-1]["R"] = $right+1;
741 }
742 }
743
744 /*
745 Internal function.
746 Winds tree stack back. Modifies (if neccessary) internal tree structure.
747 */
748 function _end_element($xmlChunk)
749 {
750 global $DB;
751
752 $child = array_pop($this->element_stack);
753 $this->element_stack[count($this->element_stack)-1]["R"] = $child["R"]+1;
754 if($child["R"] != $child["RO"])
755 $DB->Query("UPDATE ".$this->_table_name." SET RIGHT_MARGIN = ".(int)$child["R"]." WHERE ID = ".(int)$child["ID"]);
756 }
757
758 /*
759 Returns an associative array of the part of xml tree.
760 Elements with same name on the same level gets an additional suffix.
761 For example
762 <a>
763 <b>123</b>
764 <b>456</b>
765 <a>
766 will return
767 array(
768 "a => array(
769 "b" => "123",
770 "b1" => "456",
771 ),
772 );
773 */
774 function GetAllChildrenArray($arParent, $handleAttributes = false)
775 {
776 //We will return
777 $arResult = array();
778
779 //So we get not parent itself but xml_id
780 if(!is_array($arParent))
781 {
782 $rs = $this->GetList(
783 array(),
784 array("ID" => $arParent),
785 array("ID", "LEFT_MARGIN", "RIGHT_MARGIN"),
786 $handleAttributes
787 );
788 $arParent = $rs->Fetch();
789 if(!$arParent)
790 return $arResult;
791 }
792
793 //Array of the references to the arResult array members with xml_id as index.
794 $arSalt = array();
795 $arIndex = array();
796 $rs = $this->GetList(
797 array("ID" => "asc"),
798 array("><LEFT_MARGIN" => array($arParent["LEFT_MARGIN"]+1, $arParent["RIGHT_MARGIN"]-1)),
799 array(),
800 $handleAttributes
801 );
802 while($ar = $rs->Fetch())
803 {
804 if (
805 (int)$ar['PARENT_ID'] === 0
806 && (int)$ar['RIGHT_MARGIN'] === 0
807 && (int)$ar['DEPTH_LEVEL'] === 0
808 && $ar['NAME'] === ''
809 )
810 {
811 continue;
812 }
813 if(isset($ar["VALUE_CLOB"]))
814 $ar["VALUE"] = $ar["VALUE_CLOB"];
815
816 if(isset($arSalt[$ar["PARENT_ID"]][$ar["NAME"]]))
817 {
818 $salt = ++$arSalt[$ar["PARENT_ID"]][$ar["NAME"]];
819 $ar["NAME"] .= $salt;
820 }
821 else
822 {
823 $arSalt[$ar["PARENT_ID"]][$ar["NAME"]] = 0;
824 }
825
826 if($ar["PARENT_ID"] == $arParent["ID"])
827 {
828 $arResult[$ar["NAME"]] = $ar["VALUE"];
829 $arIndex[$ar["ID"]] = &$arResult[$ar["NAME"]];
830 }
831 else
832 {
833 $parent_id = $ar["PARENT_ID"];
834 if (!is_array($arIndex[$parent_id]))
835 {
836 $arIndex[$parent_id] = [];
837 }
838 $arIndex[$parent_id][$ar["NAME"]] = $ar["VALUE"];
839 $arIndex[$ar["ID"]] = &$arIndex[$parent_id][$ar["NAME"]];
840 }
841 }
842 unset($ar);
843 unset($rs);
844 unset($arIndex);
845 unset($arSalt);
846
847 return $arResult;
848 }
849
850 function GetList($arOrder = array(), $arFilter = array(), $arSelect = array(), $handleAttributes = false)
851 {
852 global $DB;
853
854 static $arFields = array(
855 "ID" => "ID",
856 "ATTRIBUTES" => "ATTRIBUTES",
857 "LEFT_MARGIN" => "LEFT_MARGIN",
858 "RIGHT_MARGIN" => "RIGHT_MARGIN",
859 "NAME" => "NAME",
860 "VALUE" => "VALUE",
861 );
862 foreach($arSelect as $i => $field)
863 {
864 if (!isset($arFields[$field]))
865 {
866 unset($arSelect[$i]);
867 }
868 }
869 if (empty($arSelect))
870 {
871 $arSelect[] = "*";
872 }
873
874 $arSQLWhere = array();
875 foreach($arFilter as $field => $value)
876 {
877 if($field == "ID" && is_array($value) && !empty($value))
878 {
880 if (!empty($value))
881 {
882 $arSQLWhere[$field] = $field . " in (" . implode(",", $value) . ")";
883 }
884 }
885 elseif($field == "ID" || $field == "LEFT_MARGIN")
886 $arSQLWhere[$field] = $field." = ".(int)$value;
887 elseif($field == "PARENT_ID" || $field == "PARENT_ID+0")
888 $arSQLWhere[$field] = $field." = ".(int)$value;
889 elseif($field == ">ID")
890 $arSQLWhere[$field] = "ID > ".(int)$value;
891 elseif($field == "><LEFT_MARGIN")
892 $arSQLWhere[$field] = "LEFT_MARGIN between ".(int)$value[0]." AND ".(int)$value[1];
893 elseif($field == "NAME")
894 $arSQLWhere[$field] = $field." = "."'".$DB->ForSQL($value)."'";
895 }
896 if($this->_sessid)
897 $arSQLWhere[] = "SESS_ID = '".$DB->ForSQL($this->_sessid)."'";
898
899 foreach($arOrder as $field => $by)
900 {
901 if(!isset($arFields[$field]))
902 {
903 unset($arSelect[$field]);
904 }
905 else
906 {
907 $arOrder[$field] = $field . " " . ($by == "desc" ? "desc" : "asc");
908 }
909 }
910
911 $strSql = "
912 select
913 ".implode(", ", $arSelect)."
914 from
915 ".$this->_table_name."
916 ".(count($arSQLWhere)? "where (".implode(") and (", $arSQLWhere).")": "")."
917 ".(count($arOrder)? "order by ".implode(", ", $arOrder): "")."
918 ";
919
920 if ($handleAttributes)
921 {
922 $result = new CCMLResult($DB->Query($strSql));
923 }
924 else
925 {
926 $result = $DB->Query($strSql);
927 }
928 return $result;
929 }
930
931 function Delete($ID)
932 {
933 global $DB;
934 return $DB->Query("delete from ".$this->_table_name." where ID = ".(int)$ID);
935 }
936
943 public static function safeUnZip(string $fileName, ?int $lastIndex = null, int $interval = 0): array
944 {
945 $result = [
946 'STATUS' => self::UNPACK_STATUS_FINAL,
947 'DATA' => []
948 ];
949
950 $startTime = time();
951
953
954 $dirName = mb_substr($fileName, 0, mb_strrpos($fileName, '/') + 1);
955 if (mb_strlen($dirName) <= mb_strlen($_SERVER['DOCUMENT_ROOT']))
956 {
957 $result['STATUS'] = self::UNPACK_STATUS_ERROR;
958
959 return $result;
960 }
961
963 $archiver = CBXArchive::GetArchive($fileName, 'ZIP');
964 if (!($archiver instanceof IBXArchive))
965 {
966 $result['STATUS'] = self::UNPACK_STATUS_ERROR;
967
968 return $result;
969 }
970
971 if ($lastIndex !== null && $lastIndex < 0)
972 {
973 $lastIndex = null;
974 }
975
976 $archiveProperties = $archiver->GetProperties();
977 if (!is_array($archiveProperties))
978 {
979 $result['STATUS'] = self::UNPACK_STATUS_ERROR;
980
981 return $result;
982 }
983 if (!isset($archiveProperties['nb']))
984 {
985 $result['STATUS'] = self::UNPACK_STATUS_ERROR;
986
987 return $result;
988 }
989 $entries = (int)$archiveProperties['nb'];
990 for ($index = 0; $index < $entries; $index++)
991 {
992 if ($lastIndex !== null)
993 {
994 if ($lastIndex >= $index)
995 {
996 continue;
997 }
998 }
999
1000 $archiver->SetOptions([
1001 'RULE' => [
1002 'by_index' => [
1003 [
1004 'start' => $index,
1005 'end' => $index,
1006 ]
1007 ]
1008 ]
1009 ]);
1010
1011 $stepResult = $archiver->Unpack($dirName);
1012 if ($stepResult === true)
1013 {
1014 return $result;
1015 }
1016 if ($stepResult === false)
1017 {
1018 $result['STATUS'] = self::UNPACK_STATUS_ERROR;
1019
1020 return $result;
1021 }
1022
1023 if ($interval > 0 && (time() - $startTime) > $interval)
1024 {
1025 $result['STATUS'] = self::UNPACK_STATUS_CONTINUE;
1026 $result['DATA']['LAST_INDEX'] = $index;
1027
1028 return $result;
1029 }
1030 }
1031
1032 return $result;
1033 }
1034
1045 public static function UnZip($file_name, $last_zip_entry = "", $start_time = 0, $interval = 0)
1046 {
1047 $last_zip_entry = (string)$last_zip_entry;
1048 if ($last_zip_entry === '')
1049 {
1050 $last_zip_entry = null;
1051 }
1052 else
1053 {
1054 $last_zip_entry = (int)$last_zip_entry;
1055 }
1056
1057 $internalResult = static::safeUnZip((string)$file_name, $last_zip_entry, (int)$interval);
1058
1059 switch ($internalResult['STATUS'])
1060 {
1061 case self::UNPACK_STATUS_ERROR:
1062 $result = false;
1063 break;
1064 case self::UNPACK_STATUS_CONTINUE:
1065 $result = $internalResult['DATA']['LAST_INDEX'];
1066 break;
1067 case self::UNPACK_STATUS_FINAL:
1068 default:
1069 $result = true;
1070 break;
1071 }
1072
1073 return $result;
1074 }
1075}
$connection
Определения actionsdefinitions.php:38
$arResult
Определения generate_coupon.php:16
static getConnection($name="")
Определения application.php:638
static normalize($path)
Определения path.php:22
static convertEncoding($data, $charsetFrom, $charsetTo)
Определения encoding.php:17
static normalizeArrayValuesByInt(&$map, $sorted=true)
Определения collection.php:150
static GetArchive($strArcName, $strType="")
Определения archive.php:26
Определения cmlresult.php:4
Определения cml2.php:10
Delete($ID)
Определения cml2.php:931
$_sessid
Определения cml2.php:15
const UNPACK_STATUS_CONTINUE
Определения cml2.php:12
IndexTemporaryTables($with_sess_id=false)
Определения cml2.php:286
GetList($arOrder=array(), $arFilter=array(), $arSelect=array(), $handleAttributes=false)
Определения cml2.php:850
GetFilePosition()
Определения cml2.php:356
isTableStructureCorrect($withSessId=false)
Определения cml2.php:234
$element_stack
Определения cml2.php:18
_get_xml_chunk_mb_orig($fp)
Определения cml2.php:515
GetCountItemsWithParent($parentID)
Определения cml2.php:258
const UNPACK_STATUS_FINAL
Определения cml2.php:13
GetRoot()
Определения cml2.php:91
static UnZip($file_name, $last_zip_entry="", $start_time=0, $interval=0)
Определения cml2.php:1045
GetAllChildrenArray($arParent, $handleAttributes=false)
Определения cml2.php:774
$file_position
Определения cml2.php:19
_get_xml_chunk($fp)
Определения cml2.php:445
$_table_name
Определения cml2.php:14
DropTemporaryTables()
Определения cml2.php:147
IsExistTemporaryTable()
Определения cml2.php:218
_end_element($xmlChunk)
Определения cml2.php:748
$buf_len
Определения cml2.php:24
StartSession($sess_id)
Определения cml2.php:31
EndSession()
Определения cml2.php:73
CreateTemporaryTables($with_sess_id=false)
Определения cml2.php:159
$buf_position
Определения cml2.php:23
$read_size
Определения cml2.php:21
__construct($table_name="b_xml_tree")
Определения cml2.php:26
truncateTemporaryTables()
Определения cml2.php:129
_start_element($xmlChunk)
Определения cml2.php:651
Add($arFields)
Определения cml2.php:318
ReadXMLToDatabase($fp, &$NS, $time_limit=0, $read_size=1024)
Определения cml2.php:374
_get_xml_chunk_mb($fp)
Определения cml2.php:585
const UNPACK_STATUS_ERROR
Определения cml2.php:11
$buf
Определения cml2.php:22
initializeTemporaryTables()
Определения cml2.php:99
GetSessionRoot()
Определения cml2.php:65
$charset
Определения cml2.php:17
$start_time
Определения clock_selector.php:9
$startTime
Определения sync.php:69
$right
Определения options.php:8
$arFields
Определения dblapprove.php:5
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
if($ajaxMode) $ID
Определения get_user.php:27
$p
Определения group_list_element_edit.php:23
$_SERVER["DOCUMENT_ROOT"]
Определения cron_frame.php:9
global $DB
Определения cron_frame.php:29
const LANG_CHARSET
Определения include.php:65
if(!defined('NOT_CHECK_PERMISSIONS')) $NS
Определения backup.php:24
ConvertDateTime($datetime, $to_format=false, $from_site=false, $bSearchInSitesOnly=false)
Определения tools.php:724
Определения arrayresult.php:2
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$ar
Определения options.php:199
$fileName
Определения quickway.php:305
$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
$rs
Определения action.php:82
$arFilter
Определения user_search.php:106
$fields
Определения yandex_run.php:501