PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/freetrix/modules/iblock/classes/mysql/cml2.php

https://github.com/ivanbogomoloff/open_bx
PHP | 829 lines | 704 code | 61 blank | 64 comment | 65 complexity | 3dbde0810d1b86036eabd03c6ad09cf3 MD5 | raw file
  1. <?
  2. /*
  3. This class is used to parse and load an xml file into database table.
  4. */
  5. class CIBlockXMLFile
  6. {
  7. var $_table_name = "";
  8. var $_sessid = "";
  9. var $charset = false;
  10. var $element_stack = false;
  11. var $file_position = 0;
  12. var $read_size = 10240;
  13. var $buf = "";
  14. var $buf_position = 0;
  15. var $buf_len = 0;
  16. private $_get_xml_chunk_function = "_get_xml_chunk";
  17. function __construct($table_name = "b_xml_tree")
  18. {
  19. $this->_table_name = strtolower($table_name);
  20. if (defined("FX_UTF"))
  21. {
  22. if (function_exists("mb_orig_strpos") && function_exists("mb_orig_strlen") && function_exists("mb_orig_substr"))
  23. $this->_get_xml_chunk_function = "_get_xml_chunk_mb_orig";
  24. else
  25. $this->_get_xml_chunk_function = "_get_xml_chunk_mb";
  26. }
  27. else
  28. {
  29. $this->_get_xml_chunk_function = "_get_xml_chunk";
  30. }
  31. }
  32. function StartSession($sess_id)
  33. {
  34. global $DB;
  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. if($res)
  46. {
  47. $this->_sessid = substr($sess_id, 0, 32);
  48. $rs = $this->GetList(array(), array("PARENT_ID" => -1), array("ID", "NAME"));
  49. if(!$rs->Fetch())
  50. {
  51. $this->Add(array(
  52. "PARENT_ID" => -1,
  53. "LEFT_MARGIN" => 0,
  54. "NAME" => "SESS_ID",
  55. "VALUE" => ConvertDateTime(ConvertTimeStamp(false, "FULL"), "YYYY-MM-DD HH:MI:SS"),
  56. ));
  57. }
  58. }
  59. return $res;
  60. }
  61. function GetSessionRoot()
  62. {
  63. global $DB;
  64. $rs = $DB->Query("SELECT ID MID from ".$this->_table_name." WHERE SESS_ID = '".$DB->ForSQL($this->_sessid)."' AND PARENT_ID = 0");
  65. $ar = $rs->Fetch();
  66. return $ar["MID"];
  67. }
  68. function EndSession()
  69. {
  70. global $DB;
  71. //Delete "expired" sessions
  72. $expired = ConvertDateTime(ConvertTimeStamp(time()-3600, "FULL"), "YYYY-MM-DD HH:MI:SS");
  73. $rs = $DB->Query("select ID, SESS_ID, VALUE from ".$this->_table_name." where PARENT_ID = -1 AND NAME = 'SESS_ID' ORDER BY ID");
  74. while($ar = $rs->Fetch())
  75. {
  76. if($ar["SESS_ID"] == $this->_sessid || $ar["VALUE"] < $expired)
  77. {
  78. $DB->Query("DELETE from ".$this->_table_name." WHERE SESS_ID = '".$DB->ForSQL($ar["SESS_ID"])."'");
  79. }
  80. }
  81. return true;
  82. }
  83. /*
  84. This function have to called once at the import start.
  85. return : result of the CDatabase::Query method
  86. We use drop due to mysql innodb slow truncate bug.
  87. */
  88. function DropTemporaryTables()
  89. {
  90. if(!isset($this) || !is_object($this) || strlen($this->_table_name) <= 0)
  91. {
  92. $ob = new CIBlockXMLFile;
  93. return $ob->DropTemporaryTables();
  94. }
  95. else
  96. {
  97. global $DB;
  98. if($DB->TableExists($this->_table_name))
  99. return $DB->Query("drop table ".$this->_table_name);
  100. else
  101. return true;
  102. }
  103. }
  104. function CreateTemporaryTables($with_sess_id = false)
  105. {
  106. if(!is_object($this) || strlen($this->_table_name) <= 0)
  107. {
  108. $ob = new CIBlockXMLFile;
  109. return $ob->CreateTemporaryTables();
  110. }
  111. else
  112. {
  113. global $DB;
  114. if(defined("MYSQL_TABLE_TYPE") && strlen(MYSQL_TABLE_TYPE) > 0)
  115. $DB->Query("SET storage_engine = '".MYSQL_TABLE_TYPE."'", true);
  116. $res = $DB->Query("create table ".$this->_table_name."
  117. (
  118. ID int(11) not null auto_increment,
  119. ".($with_sess_id? "SESS_ID varchar(32),": "")."
  120. PARENT_ID int(11),
  121. LEFT_MARGIN int(11),
  122. RIGHT_MARGIN int(11),
  123. DEPTH_LEVEL int(11),
  124. NAME varchar(255),
  125. VALUE longtext,
  126. ATTRIBUTES text,
  127. PRIMARY KEY (ID)
  128. )
  129. ");
  130. if ($res && defined("FX_XML_CREATE_INDEXES_IMMEDIATELY"))
  131. $res = $this->IndexTemporaryTables($with_sess_id);
  132. return $res;
  133. }
  134. }
  135. /*
  136. This function indexes contents of the loaded data for future lookups.
  137. May be called after tables creation and loading will perform slowly.
  138. But it is recommented to call this function after all data load.
  139. This is much faster.
  140. return : result of the CDatabase::Query method
  141. */
  142. function IndexTemporaryTables($with_sess_id = false)
  143. {
  144. if(!is_object($this) || strlen($this->_table_name) <= 0)
  145. {
  146. $ob = new CIBlockXMLFile;
  147. return $ob->IndexTemporaryTables();
  148. }
  149. else
  150. {
  151. global $DB;
  152. $res = true;
  153. if($with_sess_id)
  154. {
  155. if(!$DB->IndexExists($this->_table_name, array("SESS_ID", "PARENT_ID")))
  156. $res = $DB->Query("CREATE INDEX ix_".$this->_table_name."_parent on ".$this->_table_name."(SESS_ID, PARENT_ID)");
  157. if($res && !$DB->IndexExists($this->_table_name, array("SESS_ID", "LEFT_MARGIN")))
  158. $res = $DB->Query("CREATE INDEX ix_".$this->_table_name."_left on ".$this->_table_name."(SESS_ID, LEFT_MARGIN)");
  159. }
  160. else
  161. {
  162. if(!$DB->IndexExists($this->_table_name, array("PARENT_ID")))
  163. $res = $DB->Query("CREATE INDEX ix_".$this->_table_name."_parent on ".$this->_table_name."(PARENT_ID)");
  164. if($res && !$DB->IndexExists($this->_table_name, array("LEFT_MARGIN")))
  165. $res = $DB->Query("CREATE INDEX ix_".$this->_table_name."_left on ".$this->_table_name."(LEFT_MARGIN)");
  166. }
  167. return $res;
  168. }
  169. }
  170. function Add($arFields)
  171. {
  172. global $DB;
  173. $strSql1 = "PARENT_ID, LEFT_MARGIN, RIGHT_MARGIN, DEPTH_LEVEL, NAME";
  174. $strSql2 = intval($arFields["PARENT_ID"]).", ".intval($arFields["LEFT_MARGIN"]).", ".intval($arFields["RIGHT_MARGIN"]).", ".intval($arFields["DEPTH_LEVEL"]).", '".$DB->ForSQL($arFields["NAME"], 255)."'";
  175. if(array_key_exists("ATTRIBUTES", $arFields))
  176. {
  177. $strSql1 .= ", ATTRIBUTES";
  178. $strSql2 .= ", '".$DB->ForSQL($arFields["ATTRIBUTES"])."'";
  179. }
  180. if(array_key_exists("VALUE", $arFields))
  181. {
  182. $strSql1 .= ", VALUE";
  183. $strSql2 .= ", '".$DB->ForSQL($arFields["VALUE"])."'";
  184. }
  185. if($this->_sessid)
  186. {
  187. $strSql1 .= ", SESS_ID";
  188. $strSql2 .= ", '".$DB->ForSQL($this->_sessid)."'";
  189. }
  190. $strSql = "INSERT INTO ".$this->_table_name." (".$strSql1.") VALUES (".$strSql2.")";
  191. $rs = $DB->Query($strSql);
  192. return $DB->LastID();
  193. }
  194. function GetFilePosition()
  195. {
  196. return $this->file_position;
  197. }
  198. /*
  199. Reads portion of xml data.
  200. hFile - file handle opened with fopen function for reading
  201. NS - will be populated with to members
  202. charset parameter is used to recode file contents if needed.
  203. element_stack parameters save parsing stack of xml tree parents.
  204. file_position parameters marks current file position.
  205. time_limit - duration of one step in seconds.
  206. NS have to be preserved between steps.
  207. They automatically extracted from xml file and should not be modified!
  208. */
  209. function ReadXMLToDatabase($fp, &$NS, $time_limit=0, $read_size = 1024)
  210. {
  211. global $APPLICATION;
  212. //Initialize object
  213. if(!array_key_exists("charset", $NS))
  214. $NS["charset"] = false;
  215. $this->charset = &$NS["charset"];
  216. if(!array_key_exists("element_stack", $NS))
  217. $NS["element_stack"] = array();
  218. $this->element_stack = &$NS["element_stack"];
  219. if(!array_key_exists("file_position", $NS))
  220. $NS["file_position"] = 0;
  221. $this->file_position = &$NS["file_position"];
  222. $this->read_size = $read_size;
  223. $this->buf = "";
  224. $this->buf_position = 0;
  225. $this->buf_len = 0;
  226. //This is an optimization. We assume than no step can take more than one year.
  227. if($time_limit > 0)
  228. $end_time = time() + $time_limit;
  229. else
  230. $end_time = time() + 365*24*3600; // One year
  231. $cs = $this->charset;
  232. $_get_xml_chunk = array($this, $this->_get_xml_chunk_function);
  233. fseek($fp, $this->file_position);
  234. while(($xmlChunk = call_user_func_array($_get_xml_chunk, array($fp))) !== false)
  235. {
  236. if($cs)
  237. {
  238. $xmlChunk = $APPLICATION->ConvertCharset($xmlChunk, $cs, LANG_CHARSET);
  239. }
  240. if($xmlChunk[0] == "/")
  241. {
  242. $this->_end_element($xmlChunk);
  243. if(time() > $end_time)
  244. break;
  245. }
  246. elseif($xmlChunk[0] == "!" || $xmlChunk[0] == "?")
  247. {
  248. if(substr($xmlChunk, 0, 4) === "?xml")
  249. {
  250. if(preg_match('#encoding[\s]*=[\s]*"(.*?)"#i', $xmlChunk, $arMatch))
  251. {
  252. $this->charset = $arMatch[1];
  253. if(strtoupper($this->charset) === strtoupper(LANG_CHARSET))
  254. $this->charset = false;
  255. $cs = $this->charset;
  256. }
  257. }
  258. }
  259. else
  260. {
  261. $this->_start_element($xmlChunk);
  262. }
  263. }
  264. return feof($fp);
  265. }
  266. /*
  267. Internal function.
  268. Used to read an xml by chunks started with "<" and endex with "<"
  269. */
  270. function _get_xml_chunk($fp)
  271. {
  272. if($this->buf_position >= $this->buf_len)
  273. {
  274. if(!feof($fp))
  275. {
  276. $this->buf = fread($fp, $this->read_size);
  277. $this->buf_position = 0;
  278. $this->buf_len = strlen($this->buf);
  279. }
  280. else
  281. return false;
  282. }
  283. //Skip line delimiters (ltrim)
  284. $xml_position = strpos($this->buf, "<", $this->buf_position);
  285. while($xml_position === $this->buf_position)
  286. {
  287. $this->buf_position++;
  288. $this->file_position++;
  289. //Buffer ended with white space so we can refill it
  290. if($this->buf_position >= $this->buf_len)
  291. {
  292. if(!feof($fp))
  293. {
  294. $this->buf = fread($fp, $this->read_size);
  295. $this->buf_position = 0;
  296. $this->buf_len = strlen($this->buf);
  297. }
  298. else
  299. return false;
  300. }
  301. $xml_position = strpos($this->buf, "<", $this->buf_position);
  302. }
  303. //Let's find next line delimiter
  304. while($xml_position===false)
  305. {
  306. $next_search = $this->buf_len;
  307. //Delimiter not in buffer so try to add more data to it
  308. if(!feof($fp))
  309. {
  310. $this->buf .= fread($fp, $this->read_size);
  311. $this->buf_len = strlen($this->buf);
  312. }
  313. else
  314. break;
  315. //Let's find xml tag start
  316. $xml_position = strpos($this->buf, "<", $next_search);
  317. }
  318. if($xml_position===false)
  319. $xml_position = $this->buf_len+1;
  320. $len = $xml_position-$this->buf_position;
  321. $this->file_position += $len;
  322. $result = substr($this->buf, $this->buf_position, $len);
  323. $this->buf_position = $xml_position;
  324. return $result;
  325. }
  326. /*
  327. Internal function.
  328. Used to read an xml by chunks started with "<" and endex with "<"
  329. */
  330. function _get_xml_chunk_mb_orig($fp)
  331. {
  332. if($this->buf_position >= $this->buf_len)
  333. {
  334. if(!feof($fp))
  335. {
  336. $this->buf = fread($fp, $this->read_size);
  337. $this->buf_position = 0;
  338. $this->buf_len = mb_orig_strlen($this->buf);
  339. }
  340. else
  341. return false;
  342. }
  343. //Skip line delimiters (ltrim)
  344. $xml_position = mb_orig_strpos($this->buf, "<", $this->buf_position);
  345. while($xml_position === $this->buf_position)
  346. {
  347. $this->buf_position++;
  348. $this->file_position++;
  349. //Buffer ended with white space so we can refill it
  350. if($this->buf_position >= $this->buf_len)
  351. {
  352. if(!feof($fp))
  353. {
  354. $this->buf = fread($fp, $this->read_size);
  355. $this->buf_position = 0;
  356. $this->buf_len = mb_orig_strlen($this->buf);
  357. }
  358. else
  359. return false;
  360. }
  361. $xml_position = mb_orig_strpos($this->buf, "<", $this->buf_position);
  362. }
  363. //Let's find next line delimiter
  364. while($xml_position===false)
  365. {
  366. $next_search = $this->buf_len;
  367. //Delimiter not in buffer so try to add more data to it
  368. if(!feof($fp))
  369. {
  370. $this->buf .= fread($fp, $this->read_size);
  371. $this->buf_len = mb_orig_strlen($this->buf);
  372. }
  373. else
  374. break;
  375. //Let's find xml tag start
  376. $xml_position = mb_orig_strpos($this->buf, "<", $next_search);
  377. }
  378. if($xml_position===false)
  379. $xml_position = $this->buf_len+1;
  380. $len = $xml_position-$this->buf_position;
  381. $this->file_position += $len;
  382. $result = mb_orig_substr($this->buf, $this->buf_position, $len);
  383. $this->buf_position = $xml_position;
  384. return $result;
  385. }
  386. /*
  387. Internal function.
  388. Used to read an xml by chunks started with "<" and endex with "<"
  389. */
  390. function _get_xml_chunk_mb($fp)
  391. {
  392. if($this->buf_position >= $this->buf_len)
  393. {
  394. if(!feof($fp))
  395. {
  396. $this->buf = fread($fp, $this->read_size);
  397. $this->buf_position = 0;
  398. $this->buf_len = mb_strlen($this->buf);
  399. }
  400. else
  401. return false;
  402. }
  403. //Skip line delimiters (ltrim)
  404. $xml_position = mb_strpos($this->buf, "<", $this->buf_position);
  405. while($xml_position === $this->buf_position)
  406. {
  407. $this->buf_position++;
  408. $this->file_position++;
  409. //Buffer ended with white space so we can refill it
  410. if($this->buf_position >= $this->buf_len)
  411. {
  412. if(!feof($fp))
  413. {
  414. $this->buf = fread($fp, $this->read_size);
  415. $this->buf_position = 0;
  416. $this->buf_len = mb_strlen($this->buf);
  417. }
  418. else
  419. return false;
  420. }
  421. $xml_position = mb_strpos($this->buf, "<", $this->buf_position);
  422. }
  423. //Let's find next line delimiter
  424. while($xml_position===false)
  425. {
  426. $next_search = $this->buf_len;
  427. //Delimiter not in buffer so try to add more data to it
  428. if(!feof($fp))
  429. {
  430. $this->buf .= fread($fp, $this->read_size);
  431. $this->buf_len = mb_strlen($this->buf);
  432. }
  433. else
  434. break;
  435. //Let's find xml tag start
  436. $xml_position = mb_strpos($this->buf, "<", $next_search);
  437. }
  438. if($xml_position===false)
  439. $xml_position = $this->buf_len+1;
  440. $len = $xml_position-$this->buf_position;
  441. $this->file_position += $len;
  442. $result = mb_substr($this->buf, $this->buf_position, $len);
  443. $this->buf_position = $xml_position;
  444. return $result;
  445. }
  446. /*
  447. Internal function.
  448. Stores an element into xml database tree.
  449. */
  450. function _start_element($xmlChunk)
  451. {
  452. global $DB;
  453. static $search = array(
  454. "'&(quot|#34);'i",
  455. "'&(lt|#60);'i",
  456. "'&(gt|#62);'i",
  457. "'&(amp|#38);'i",
  458. );
  459. static $replace = array(
  460. "\"",
  461. "<",
  462. ">",
  463. "&",
  464. );
  465. $p = strpos($xmlChunk, ">");
  466. if($p !== false)
  467. {
  468. if(substr($xmlChunk, $p - 1, 1)=="/")
  469. {
  470. $bHaveChildren = false;
  471. $elementName = substr($xmlChunk, 0, $p-1);
  472. $DBelementValue = false;
  473. }
  474. else
  475. {
  476. $bHaveChildren = true;
  477. $elementName = substr($xmlChunk, 0, $p);
  478. $elementValue = substr($xmlChunk, $p+1);
  479. if(preg_match("/^\s*$/", $elementValue))
  480. $DBelementValue = false;
  481. elseif(strpos($elementValue, "&")===false)
  482. $DBelementValue = $elementValue;
  483. else
  484. $DBelementValue = preg_replace($search, $replace, $elementValue);
  485. }
  486. if(($ps = strpos($elementName, " "))!==false)
  487. {
  488. //Let's handle attributes
  489. $elementAttrs = substr($elementName, $ps+1);
  490. $elementName = substr($elementName, 0, $ps);
  491. preg_match_all("/(\\S+)\\s*=\\s*[\"](.*?)[\"]/s", $elementAttrs, $attrs_tmp);
  492. $attrs = array();
  493. if(strpos($elementAttrs, "&")===false)
  494. {
  495. foreach($attrs_tmp[1] as $i=>$attrs_tmp_1)
  496. $attrs[$attrs_tmp_1] = $attrs_tmp[2][$i];
  497. }
  498. else
  499. {
  500. foreach($attrs_tmp[1] as $i=>$attrs_tmp_1)
  501. $attrs[$attrs_tmp_1] = preg_replace($search, $replace, $attrs_tmp[2][$i]);
  502. }
  503. $DBelementAttrs = serialize($attrs);
  504. }
  505. else
  506. $DBelementAttrs = false;
  507. if($c = count($this->element_stack))
  508. $parent = $this->element_stack[$c-1];
  509. else
  510. $parent = array("ID"=>"NULL", "L"=>0, "R"=>1);
  511. $left = $parent["R"];
  512. $right = $left+1;
  513. $arFields = array(
  514. "PARENT_ID" => $parent["ID"],
  515. "LEFT_MARGIN" => $left,
  516. "RIGHT_MARGIN" => $right,
  517. "DEPTH_LEVEL" => $c,
  518. "NAME" => $elementName,
  519. );
  520. if($DBelementValue !== false)
  521. {
  522. $arFields["VALUE"] = $DBelementValue;
  523. }
  524. if($DBelementAttrs !== false)
  525. {
  526. $arFields["ATTRIBUTES"] = $DBelementAttrs;
  527. }
  528. $ID = $this->Add($arFields);
  529. if($bHaveChildren)
  530. $this->element_stack[] = array("ID"=>$ID, "L"=>$left, "R"=>$right, "RO"=>$right);
  531. else
  532. $this->element_stack[$c-1]["R"] = $right+1;
  533. }
  534. }
  535. /*
  536. Internal function.
  537. Winds tree stack back. Modifies (if neccessary) internal tree structure.
  538. */
  539. function _end_element($xmlChunk)
  540. {
  541. global $DB;
  542. $child = array_pop($this->element_stack);
  543. $this->element_stack[count($this->element_stack)-1]["R"] = $child["R"]+1;
  544. if($child["R"] != $child["RO"])
  545. $DB->Query("UPDATE ".$this->_table_name." SET RIGHT_MARGIN = ".intval($child["R"])." WHERE ID = ".intval($child["ID"]));
  546. }
  547. /*
  548. Returns an associative array of the part of xml tree.
  549. Elements with same name on the same level gets an additional suffix.
  550. For example
  551. <a>
  552. <b>123</b>
  553. <b>456</b>
  554. <a>
  555. will return
  556. array(
  557. "a => array(
  558. "b" => "123",
  559. "b1" => "456",
  560. ),
  561. );
  562. */
  563. function GetAllChildrenArray($arParent)
  564. {
  565. global $DB;
  566. //We will return
  567. $arResult = array();
  568. //So we get not parent itself but xml_id
  569. if(!is_array($arParent))
  570. {
  571. $rs = $this->GetList(
  572. array(),
  573. array("ID" => $arParent),
  574. array("ID", "LEFT_MARGIN", "RIGHT_MARGIN")
  575. );
  576. $arParent = $rs->Fetch();
  577. if(!$arParent)
  578. return $arResult;
  579. }
  580. //Array of the references to the arResult array members with xml_id as index.
  581. $arSalt = array();
  582. $arIndex = array();
  583. $rs = $this->GetList(
  584. array("ID" => "asc"),
  585. array("><LEFT_MARGIN" => array($arParent["LEFT_MARGIN"]+1, $arParent["RIGHT_MARGIN"]-1))
  586. );
  587. while($ar = $rs->Fetch())
  588. {
  589. if(isset($ar["VALUE_CLOB"]))
  590. $ar["VALUE"] = $ar["VALUE_CLOB"];
  591. if(isset($arSalt[$ar["PARENT_ID"]][$ar["NAME"]]))
  592. {
  593. $salt = ++$arSalt[$ar["PARENT_ID"]][$ar["NAME"]];
  594. $ar["NAME"] .= $salt;
  595. }
  596. else
  597. {
  598. $arSalt[$ar["PARENT_ID"]][$ar["NAME"]] = 0;
  599. }
  600. if($ar["PARENT_ID"] == $arParent["ID"])
  601. {
  602. $arResult[$ar["NAME"]] = $ar["VALUE"];
  603. $arIndex[$ar["ID"]] = &$arResult[$ar["NAME"]];
  604. }
  605. else
  606. {
  607. $parent_id = $ar["PARENT_ID"];
  608. if(!is_array($arIndex[$parent_id]))
  609. $arIndex[$parent_id] = array();
  610. $arIndex[$parent_id][$ar["NAME"]] = $ar["VALUE"];
  611. $arIndex[$ar["ID"]] = &$arIndex[$parent_id][$ar["NAME"]];
  612. }
  613. }
  614. return $arResult;
  615. }
  616. function GetList($arOrder = array(), $arFilter = array(), $arSelect = array())
  617. {
  618. global $DB;
  619. static $arFields = array(
  620. "ID" => "ID",
  621. "ATTRIBUTES" => "ATTRIBUTES",
  622. "LEFT_MARGIN" => "LEFT_MARGIN",
  623. "RIGHT_MARGIN" => "RIGHT_MARGIN",
  624. "NAME" => "NAME",
  625. "VALUE" => "VALUE",
  626. );
  627. foreach($arSelect as $i => $field)
  628. if(!array_key_exists($field, $arFields))
  629. unset($arSelect[$i]);
  630. if(count($arSelect) <= 0)
  631. $arSelect[] = "*";
  632. $arSQLWhere = array();
  633. foreach($arFilter as $field => $value)
  634. {
  635. if($field == "ID" || $field == "LEFT_MARGIN")
  636. $arSQLWhere[$field] = $field." = ".intval($value);
  637. elseif($field == "PARENT_ID" || $field == "PARENT_ID+0")
  638. $arSQLWhere[$field] = $field." = ".intval($value);
  639. elseif($field == ">ID")
  640. $arSQLWhere[$field] = "ID > ".intval($value);
  641. elseif($field == "><LEFT_MARGIN")
  642. $arSQLWhere[$field] = "LEFT_MARGIN between ".intval($value[0])." AND ".intval($value[1]);
  643. elseif($field == "NAME")
  644. $arSQLWhere[$field] = $field." = "."'".$DB->ForSQL($value)."'";
  645. }
  646. if($this->_sessid)
  647. $arSQLWhere[] = "SESS_ID = '".$DB->ForSQL($this->_sessid)."'";
  648. foreach($arOrder as $field => $by)
  649. {
  650. if(!array_key_exists($field, $arFields))
  651. unset($arSelect[$field]);
  652. else
  653. $arOrder[$field] = $field." ".($by=="desc"? "desc": "asc");
  654. }
  655. $strSql = "
  656. select
  657. ".implode(", ", $arSelect)."
  658. from
  659. ".$this->_table_name."
  660. ".(count($arSQLWhere)? "where (".implode(") and (", $arSQLWhere).")": "")."
  661. ".(count($arOrder)? "order by ".implode(", ", $arOrder): "")."
  662. ";
  663. return $DB->Query($strSql);
  664. }
  665. function Delete($ID)
  666. {
  667. global $DB;
  668. return $DB->Query("delete from ".$this->_table_name." where ID = ".intval($ID));
  669. }
  670. function UnZip($file_name, $last_zip_entry = "", $start_time = 0, $interval = 0)
  671. {
  672. global $APPLICATION;
  673. $io = CBXVirtualIo::GetInstance();
  674. //Function and securioty checks
  675. if(!function_exists("zip_open"))
  676. return false;
  677. $dir_name = substr($file_name, 0, strrpos($file_name, "/")+1);
  678. if(strlen($dir_name) <= strlen($_SERVER["DOCUMENT_ROOT"]))
  679. return false;
  680. $hZip = zip_open($file_name);
  681. if(!$hZip)
  682. return false;
  683. //Skip from last step
  684. if($last_zip_entry)
  685. {
  686. while($entry = zip_read($hZip))
  687. if(zip_entry_name($entry) == $last_zip_entry)
  688. break;
  689. }
  690. $io = CBXVirtualIo::GetInstance();
  691. //Continue unzip
  692. while($entry = zip_read($hZip))
  693. {
  694. $entry_name = zip_entry_name($entry);
  695. //Check for directory
  696. zip_entry_open($hZip, $entry);
  697. if(zip_entry_filesize($entry))
  698. {
  699. $file_name = trim(str_replace("\\", "/", trim($entry_name)), "/");
  700. $file_name = $APPLICATION->ConvertCharset($file_name, "cp866", LANG_CHARSET);
  701. $bBadFile = HasScriptExtension($file_name)
  702. || IsFileUnsafe($file_name)
  703. || !$io->ValidatePathString("/".$file_name)
  704. ;
  705. if(!$bBadFile)
  706. {
  707. $file_name = $io->GetPhysicalName($dir_name.rel2abs("/", $file_name));
  708. CheckDirPath($file_name);
  709. $fout = fopen($file_name, "wb");
  710. if(!$fout)
  711. return false;
  712. while($data = zip_entry_read($entry, 102400))
  713. {
  714. $data_len = function_exists('mb_strlen') ? mb_strlen($data, 'latin1') : strlen($data);
  715. $result = fwrite($fout, $data);
  716. if($result !== $data_len)
  717. return false;
  718. }
  719. }
  720. }
  721. zip_entry_close($entry);
  722. //Jump to next step
  723. if($interval > 0 && (time()-$start_time) > ($interval))
  724. {
  725. zip_close($hZip);
  726. return $entry_name;
  727. }
  728. }
  729. zip_close($hZip);
  730. return true;
  731. }
  732. }
  733. ?>