1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22class CXmlImportReader extends CImportReader { 23 24 /** 25 * Convert string with xml data to php array. 26 * 27 * @throws Exception 28 * 29 * @param string $string 30 * 31 * @return array 32 */ 33 public function read($string) { 34 if ($string === '') { 35 throw new Exception(_s('Cannot read XML: %1$s.', _('XML is empty'))); 36 } 37 38 libxml_use_internal_errors(true); 39 libxml_disable_entity_loader(true); 40 $result = simplexml_load_string($string, null, LIBXML_IMPORT_FLAGS); 41 if (!$result) { 42 $errors = libxml_get_errors(); 43 libxml_clear_errors(); 44 45 foreach ($errors as $error) { 46 throw new Exception(_s('Cannot read XML: %1$s.', _s('%1$s [Line: %2$s | Column: %3$s]', 47 '('.$error->code.') '.trim($error->message), $error->line, $error->column 48 ))); 49 } 50 } 51 52 $xml = new XMLReader(); 53 $xml->xml($string); 54 $data = $this->xml_to_array($xml); 55 $xml->close(); 56 return $data; 57 } 58 59 /** 60 * Method for recursive processing of xml dom nodes. 61 * 62 * @param XMLReader $xml 63 * @param string $path 64 * 65 * @return array|string 66 */ 67 protected function xml_to_array(XMLReader $xml, $path = '') { 68 $data = null; 69 70 while ($xml->read()) { 71 switch ($xml->nodeType) { 72 case XMLReader::ELEMENT: 73 if ($data === null) { 74 $data = []; 75 } 76 elseif (!is_array($data)) { 77 throw new Exception(_s('Invalid tag "%1$s": %2$s.', $path, 78 _s('unexpected text "%1$s"', trim($data)) 79 )); 80 } 81 82 $node_name = $xml->name; 83 $sub_path = $path.'/'.$node_name; 84 if (array_key_exists($node_name, $data)) { 85 $node_name .= count($data); 86 $sub_path .= '('.count($data).')'; 87 } 88 89 /* 90 * A special case for 1.8 import where attributes are still used attributes must be added to the 91 * array as if they where child elements. 92 */ 93 if ($xml->hasAttributes) { 94 while ($xml->moveToNextAttribute()) { 95 $data[$node_name][$xml->name] = $xml->value; 96 } 97 98 // it make $this->isEmptyElement valid after processing attributes 99 $xml->moveToElement(); 100 101 /* 102 * We assume that an element with attributes always contains child elements, not a text node 103 * works for 1.8 XML. 104 */ 105 if (!$xml->isEmptyElement) { 106 $child_data = $this->xml_to_array($xml, $sub_path); 107 if (is_array($child_data)) { 108 foreach ($child_data as $child_node_name => $child_node_value) { 109 if (array_key_exists($child_node_name, $data[$node_name])) { 110 $child_node_name .= count($data[$node_name]); 111 } 112 $data[$node_name][$child_node_name] = $child_node_value; 113 } 114 } 115 elseif ($child_data !== '') { 116 throw new Exception(_s('Invalid tag "%1$s": %2$s.', $sub_path, 117 _s('unexpected text "%1$s"', trim($child_data)) 118 )); 119 } 120 } 121 } 122 else { 123 $data[$node_name] = $xml->isEmptyElement ? '' : $this->xml_to_array($xml, $sub_path); 124 } 125 break; 126 127 case XMLReader::CDATA: 128 // falls through 129 case XMLReader::TEXT: 130 if ($data === null) { 131 $data = $xml->value; 132 } 133 elseif (is_array($data)) { 134 throw new Exception(_s('Invalid tag "%1$s": %2$s.', $path, 135 _s('unexpected text "%1$s"', trim($xml->value)) 136 )); 137 } 138 139 break; 140 141 case XMLReader::END_ELEMENT: 142 /* 143 * For tags with empty value: <dns></dns>. 144 */ 145 if ($data === null) { 146 $data = ''; 147 } 148 149 return $data; 150 } 151 } 152 153 return $data; 154 } 155} 156