[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * XML syntax and type checker. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 */ 22 23 class XmlTypeCheck { 24 /** 25 * Will be set to true or false to indicate whether the file is 26 * well-formed XML. Note that this doesn't check schema validity. 27 */ 28 public $wellFormed = false; 29 30 /** 31 * Will be set to true if the optional element filter returned 32 * a match at some point. 33 */ 34 public $filterMatch = false; 35 36 /** 37 * Name of the document's root element, including any namespace 38 * as an expanded URL. 39 */ 40 public $rootElement = ''; 41 42 /** 43 * A stack of strings containing the data of each xml element as it's processed. Append 44 * data to the top string of the stack, then pop off the string and process it when the 45 * element is closed. 46 */ 47 protected $elementData = array(); 48 49 /** 50 * A stack of element names and attributes, as we process them. 51 */ 52 protected $elementDataContext = array(); 53 54 /** 55 * Current depth of the data stack. 56 */ 57 protected $stackDepth = 0; 58 59 /** 60 * Additional parsing options 61 */ 62 private $parserOptions = array( 63 'processing_instruction_handler' => '', 64 ); 65 66 /** 67 * @param string $input a filename or string containing the XML element 68 * @param callable $filterCallback (optional) 69 * Function to call to do additional custom validity checks from the 70 * SAX element handler event. This gives you access to the element 71 * namespace, name, attributes, and text contents. 72 * Filter should return 'true' to toggle on $this->filterMatch 73 * @param boolean $isFile (optional) indicates if the first parameter is a 74 * filename (default, true) or if it is a string (false) 75 * @param array $options list of additional parsing options: 76 * processing_instruction_handler: Callback for xml_set_processing_instruction_handler 77 */ 78 function __construct( $input, $filterCallback = null, $isFile = true, $options = array() ) { 79 $this->filterCallback = $filterCallback; 80 $this->parserOptions = array_merge( $this->parserOptions, $options ); 81 82 if ( $isFile ) { 83 $this->validateFromFile( $input ); 84 } else { 85 $this->validateFromString( $input ); 86 } 87 } 88 89 /** 90 * Alternative constructor: from filename 91 * 92 * @param string $fname the filename of an XML document 93 * @param callable $filterCallback (optional) 94 * Function to call to do additional custom validity checks from the 95 * SAX element handler event. This gives you access to the element 96 * namespace, name, and attributes, but not to text contents. 97 * Filter should return 'true' to toggle on $this->filterMatch 98 * @return XmlTypeCheck 99 */ 100 public static function newFromFilename( $fname, $filterCallback = null ) { 101 return new self( $fname, $filterCallback, true ); 102 } 103 104 /** 105 * Alternative constructor: from string 106 * 107 * @param string $string a string containing an XML element 108 * @param callable $filterCallback (optional) 109 * Function to call to do additional custom validity checks from the 110 * SAX element handler event. This gives you access to the element 111 * namespace, name, and attributes, but not to text contents. 112 * Filter should return 'true' to toggle on $this->filterMatch 113 * @return XmlTypeCheck 114 */ 115 public static function newFromString( $string, $filterCallback = null ) { 116 return new self( $string, $filterCallback, false ); 117 } 118 119 /** 120 * Get the root element. Simple accessor to $rootElement 121 * 122 * @return string 123 */ 124 public function getRootElement() { 125 return $this->rootElement; 126 } 127 128 /** 129 * Get an XML parser with the root element handler. 130 * @see XmlTypeCheck::rootElementOpen() 131 * @return resource a resource handle for the XML parser 132 */ 133 private function getParser() { 134 $parser = xml_parser_create_ns( 'UTF-8' ); 135 // case folding violates XML standard, turn it off 136 xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false ); 137 xml_set_element_handler( $parser, array( $this, 'rootElementOpen' ), false ); 138 if ( $this->parserOptions['processing_instruction_handler'] ) { 139 xml_set_processing_instruction_handler( 140 $parser, 141 array( $this, 'processingInstructionHandler' ) 142 ); 143 } 144 return $parser; 145 } 146 147 /** 148 * @param string $fname the filename 149 */ 150 private function validateFromFile( $fname ) { 151 $parser = $this->getParser(); 152 153 if ( file_exists( $fname ) ) { 154 $file = fopen( $fname, "rb" ); 155 if ( $file ) { 156 do { 157 $chunk = fread( $file, 32768 ); 158 $ret = xml_parse( $parser, $chunk, feof( $file ) ); 159 if ( $ret == 0 ) { 160 $this->wellFormed = false; 161 fclose( $file ); 162 xml_parser_free( $parser ); 163 return; 164 } 165 } while ( !feof( $file ) ); 166 167 fclose( $file ); 168 } 169 } 170 $this->wellFormed = true; 171 172 xml_parser_free( $parser ); 173 } 174 175 /** 176 * 177 * @param string $string the XML-input-string to be checked. 178 */ 179 private function validateFromString( $string ) { 180 $parser = $this->getParser(); 181 $ret = xml_parse( $parser, $string, true ); 182 xml_parser_free( $parser ); 183 if ( $ret == 0 ) { 184 $this->wellFormed = false; 185 return; 186 } 187 $this->wellFormed = true; 188 } 189 190 /** 191 * @param $parser 192 * @param $name 193 * @param $attribs 194 */ 195 private function rootElementOpen( $parser, $name, $attribs ) { 196 $this->rootElement = $name; 197 198 if ( is_callable( $this->filterCallback ) ) { 199 xml_set_element_handler( 200 $parser, 201 array( $this, 'elementOpen' ), 202 array( $this, 'elementClose' ) 203 ); 204 xml_set_character_data_handler( $parser, array( $this, 'elementData' ) ); 205 $this->elementOpen( $parser, $name, $attribs ); 206 } else { 207 // We only need the first open element 208 xml_set_element_handler( $parser, false, false ); 209 } 210 } 211 212 /** 213 * @param $parser 214 * @param $name 215 * @param $attribs 216 */ 217 private function elementOpen( $parser, $name, $attribs ) { 218 $this->elementDataContext[] = array( $name, $attribs ); 219 $this->elementData[] = ''; 220 $this->stackDepth++; 221 } 222 223 /** 224 * @param $parser 225 * @param $name 226 */ 227 private function elementClose( $parser, $name ) { 228 list( $name, $attribs ) = array_pop( $this->elementDataContext ); 229 $data = array_pop( $this->elementData ); 230 $this->stackDepth--; 231 232 if ( call_user_func( 233 $this->filterCallback, 234 $name, 235 $attribs, 236 $data 237 ) ) { 238 // Filter hit! 239 $this->filterMatch = true; 240 } 241 } 242 243 /** 244 * @param $parser 245 * @param $data 246 */ 247 private function elementData( $parser, $data ) { 248 // xml_set_character_data_handler breaks the data on & characters, so 249 // we collect any data here, and we'll run the callback in elementClose 250 $this->elementData[ $this->stackDepth - 1 ] .= trim( $data ); 251 } 252 253 /** 254 * @param $parser 255 * @param $target 256 * @param $data 257 */ 258 private function processingInstructionHandler( $parser, $target, $data ) { 259 if ( call_user_func( $this->parserOptions['processing_instruction_handler'], $target, $data ) ) { 260 // Filter hit! 261 $this->filterMatch = true; 262 } 263 } 264 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |