[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Custom XML parser for signed and/or encrypted XML Docs 4 * 5 * @author Donal McMullan [email protected] 6 * @version 0.0.1 7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 8 * @package mnet 9 */ 10 11 /** 12 * Custom XML parser class for signed and/or encrypted XML Docs 13 */ 14 class mnet_encxml_parser { 15 /** 16 * Constructor creates and initialises parser resource and calls initialise 17 * 18 * @return bool True 19 */ 20 function mnet_encxml_parser() { 21 return $this->initialise(); 22 } 23 24 /** 25 * Set default element handlers and initialise properties to empty. 26 * 27 * @return bool True 28 */ 29 function initialise() { 30 $this->parser = xml_parser_create(); 31 xml_set_object($this->parser, $this); 32 33 xml_set_element_handler($this->parser, "start_element", "end_element"); 34 xml_set_character_data_handler($this->parser, "discard_data"); 35 36 $this->tag_number = 0; // Just a unique ID for each tag 37 $this->digest = ''; 38 $this->remote_timestamp = ''; 39 $this->remote_wwwroot = ''; 40 $this->signature = ''; 41 $this->data_object = ''; 42 $this->key_URI = ''; 43 $this->payload_encrypted = false; 44 $this->cipher = array(); 45 $this->error = array(); 46 $this->remoteerror = null; 47 $this->errorstarted = false; 48 return true; 49 } 50 51 /** 52 * Parse a block of XML text 53 * 54 * The XML Text will be an XML-RPC request which is wrapped in an XML doc 55 * with a signature from the sender. This envelope may be encrypted and 56 * delivered within another XML envelope with a symmetric key. The parser 57 * should first decrypt this XML, and then place the XML-RPC request into 58 * the data_object property, and the signature into the signature property. 59 * 60 * See the W3C's {@link http://www.w3.org/TR/xmlenc-core/ XML Encryption Syntax and Processing} 61 * and {@link http://www.w3.org/TR/2001/PR-xmldsig-core-20010820/ XML-Signature Syntax and Processing} 62 * guidelines for more detail on the XML. 63 * 64 * -----XML-Envelope--------------------------------- 65 * | | 66 * | Symmetric-key-------------------------- | 67 * | |_____________________________________| | 68 * | | 69 * | Encrypted data------------------------- | 70 * | | | | 71 * | | -XML-Envelope------------------ | | 72 * | | | | | | 73 * | | | --Signature------------- | | | 74 * | | | |______________________| | | | 75 * | | | | | | 76 * | | | --Signed-Payload-------- | | | 77 * | | | | | | | | 78 * | | | | XML-RPC Request | | | | 79 * | | | |______________________| | | | 80 * | | | | | | 81 * | | |_____________________________| | | 82 * | |_____________________________________| | 83 * | | 84 * |________________________________________________| 85 * 86 * @param string $data The XML that you want to parse 87 * @return bool True on success - false on failure 88 */ 89 function parse($data) { 90 $p = xml_parse($this->parser, $data); 91 92 if ($p == 0) { 93 // Parse failed 94 $errcode = xml_get_error_code($this->parser); 95 $errstring = xml_error_string($errcode); 96 $lineno = xml_get_current_line_number($this->parser); 97 if ($lineno !== false) { 98 $error = array('lineno' => $lineno); 99 $lineno--; // Line numbering starts at 1. 100 while ($lineno > 0) { 101 $data = strstr($data, "\n"); 102 $lineno--; 103 } 104 $data .= "\n"; // In case there's only one line (no newline) 105 $line = substr($data, 0, strpos($data, "\n")); 106 $error['code'] = $errcode; 107 $error['string'] = $errstring; 108 $error['line'] = $line; 109 $this->error[] = $error; 110 } else { 111 $this->error[] = array('code' => $errcode, 'string' => $errstring); 112 } 113 } 114 115 if (!empty($this->remoteerror)) { 116 return false; 117 } 118 119 if (count($this->cipher) > 0) { 120 $this->cipher = array_values($this->cipher); 121 $this->payload_encrypted = true; 122 } 123 124 return (bool)$p; 125 } 126 127 /** 128 * Destroy the parser and free up any related resource. 129 */ 130 function free_resource() { 131 $free = xml_parser_free($this->parser); 132 } 133 134 /** 135 * Set the character-data handler to the right function for each element 136 * 137 * For each tag (element) name, this function switches the character-data 138 * handler to the function that handles that element. Note that character 139 * data is referred to the handler in blocks of 1024 bytes. 140 * 141 * @param mixed $parser The XML parser 142 * @param string $name The name of the tag, e.g. method_call 143 * @param array $attrs The tag's attributes (if any exist). 144 * @return bool True 145 */ 146 function start_element($parser, $name, $attrs) { 147 $this->tag_number++; 148 $handler = 'discard_data'; 149 switch(strtoupper($name)) { 150 case 'DIGESTVALUE': 151 $handler = 'parse_digest'; 152 break; 153 case 'SIGNATUREVALUE': 154 $handler = 'parse_signature'; 155 break; 156 case 'OBJECT': 157 $handler = 'parse_object'; 158 break; 159 case 'RETRIEVALMETHOD': 160 $this->key_URI = $attrs['URI']; 161 break; 162 case 'TIMESTAMP': 163 $handler = 'parse_timestamp'; 164 break; 165 case 'WWWROOT': 166 $handler = 'parse_wwwroot'; 167 break; 168 case 'CIPHERVALUE': 169 $this->cipher[$this->tag_number] = ''; 170 $handler = 'parse_cipher'; 171 break; 172 case 'FAULT': 173 $handler = 'parse_fault'; 174 default: 175 break; 176 } 177 xml_set_character_data_handler($this->parser, $handler); 178 return true; 179 } 180 181 /** 182 * Add the next chunk of character data to the remote_timestamp string 183 * 184 * @param mixed $parser The XML parser 185 * @param string $data The content of the current tag (1024 byte chunk) 186 * @return bool True 187 */ 188 function parse_timestamp($parser, $data) { 189 $this->remote_timestamp .= $data; 190 return true; 191 } 192 193 /** 194 * Add the next chunk of character data to the cipher string for that tag 195 * 196 * The XML parser calls the character-data handler with 1024-character 197 * chunks of data. This means that the handler may be called several times 198 * for a single tag, so we use the concatenate operator (.) to build the 199 * tag content into a string. 200 * We should not encounter more than one of each tag type, except for the 201 * cipher tag. We will often see two of those. We prevent the content of 202 * these two tags being concatenated together by counting each tag, and 203 * using its 'number' as the key to an array of ciphers. 204 * 205 * @param mixed $parser The XML parser 206 * @param string $data The content of the current tag (1024 byte chunk) 207 * @return bool True 208 */ 209 function parse_cipher($parser, $data) { 210 $this->cipher[$this->tag_number] .= $data; 211 return true; 212 } 213 214 /** 215 * Add the next chunk of character data to the remote_wwwroot string 216 * 217 * @param mixed $parser The XML parser 218 * @param string $data The content of the current tag (1024 byte chunk) 219 * @return bool True 220 */ 221 function parse_wwwroot($parser, $data) { 222 $this->remote_wwwroot .= $data; 223 return true; 224 } 225 226 /** 227 * Add the next chunk of character data to the digest string 228 * 229 * @param mixed $parser The XML parser 230 * @param string $data The content of the current tag (1024 byte chunk) 231 * @return bool True 232 */ 233 function parse_digest($parser, $data) { 234 $this->digest .= $data; 235 return true; 236 } 237 238 /** 239 * Add the next chunk of character data to the signature string 240 * 241 * @param mixed $parser The XML parser 242 * @param string $data The content of the current tag (1024 byte chunk) 243 * @return bool True 244 */ 245 function parse_signature($parser, $data) { 246 $this->signature .= $data; 247 return true; 248 } 249 250 /** 251 * Add the next chunk of character data to the data_object string 252 * 253 * @param mixed $parser The XML parser 254 * @param string $data The content of the current tag (1024 byte chunk) 255 * @return bool True 256 */ 257 function parse_object($parser, $data) { 258 $this->data_object .= $data; 259 return true; 260 } 261 262 /** 263 * Discard the next chunk of character data 264 * 265 * This is used for tags that we're not interested in. 266 * 267 * @param mixed $parser The XML parser 268 * @param string $data The content of the current tag (1024 byte chunk) 269 * @return bool True 270 */ 271 function discard_data($parser, $data) { 272 if (!$this->errorstarted) { 273 // Not interested 274 return true; 275 } 276 $data = trim($data); 277 if (isset($this->errorstarted->faultstringstarted) && !empty($data)) { 278 $this->remoteerror .= ', message: ' . $data; 279 } else if (isset($this->errorstarted->faultcodestarted)) { 280 $this->remoteerror = 'code: ' . $data; 281 unset($this->errorstarted->faultcodestarted); 282 } else if ($data == 'faultCode') { 283 $this->errorstarted->faultcodestarted = true; 284 } else if ($data == 'faultString') { 285 $this->errorstarted->faultstringstarted = true; 286 } 287 return true; 288 289 } 290 291 function parse_fault($parser, $data) { 292 $this->errorstarted = new StdClass; 293 return true; 294 } 295 296 /** 297 * Switch the character-data handler to ignore the next chunk of data 298 * 299 * @param mixed $parser The XML parser 300 * @param string $name The name of the tag, e.g. method_call 301 * @return bool True 302 */ 303 function end_element($parser, $name) { 304 $ok = xml_set_character_data_handler($this->parser, "discard_data"); 305 return true; 306 } 307 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |