[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package phpBB3 5 * @version $Id$ 6 * @copyright (c) 2007 phpBB Group 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * @ignore 13 */ 14 if (!defined('IN_PHPBB')) 15 { 16 exit; 17 } 18 19 /** 20 * 21 * Jabber class from Flyspray project 22 * 23 * @version class.jabber2.php 1595 2008-09-19 (0.9.9) 24 * @copyright 2006 Flyspray.org 25 * @author Florian Schmitz (floele) 26 * 27 * Only slightly modified by Acyd Burn 28 * 29 * @package phpBB3 30 */ 31 class jabber 32 { 33 var $connection = null; 34 var $session = array(); 35 var $timeout = 10; 36 37 var $server; 38 var $connect_server; 39 var $port; 40 var $username; 41 var $password; 42 var $use_ssl; 43 var $resource = 'functions_jabber.phpbb.php'; 44 45 var $enable_logging; 46 var $log_array; 47 48 var $features = array(); 49 50 /** 51 */ 52 function jabber($server, $port, $username, $password, $use_ssl = false) 53 { 54 $this->connect_server = ($server) ? $server : 'localhost'; 55 $this->port = ($port) ? $port : 5222; 56 57 // Get the server and the username 58 if (strpos($username, '@') === false) 59 { 60 $this->server = $this->connect_server; 61 $this->username = $username; 62 } 63 else 64 { 65 $jid = explode('@', $username, 2); 66 67 $this->username = $jid[0]; 68 $this->server = $jid[1]; 69 } 70 71 $this->password = $password; 72 $this->use_ssl = ($use_ssl && $this->can_use_ssl()) ? true : false; 73 74 // Change port if we use SSL 75 if ($this->port == 5222 && $this->use_ssl) 76 { 77 $this->port = 5223; 78 } 79 80 $this->enable_logging = true; 81 $this->log_array = array(); 82 } 83 84 /** 85 * Able to use the SSL functionality? 86 */ 87 function can_use_ssl() 88 { 89 // Will not work with PHP >= 5.2.1 or < 5.2.3RC2 until timeout problem with ssl hasn't been fixed (http://bugs.php.net/41236) 90 return ((version_compare(PHP_VERSION, '5.2.1', '<') || version_compare(PHP_VERSION, '5.2.3RC2', '>=')) && @extension_loaded('openssl')) ? true : false; 91 } 92 93 /** 94 * Able to use TLS? 95 */ 96 function can_use_tls() 97 { 98 if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers')) 99 { 100 return false; 101 } 102 103 /** 104 * Make sure the encryption stream is supported 105 * Also seem to work without the crypto stream if correctly compiled 106 107 $streams = stream_get_wrappers(); 108 109 if (!in_array('streams.crypto', $streams)) 110 { 111 return false; 112 } 113 */ 114 115 return true; 116 } 117 118 /** 119 * Sets the resource which is used. No validation is done here, only escaping. 120 * @param string $name 121 * @access public 122 */ 123 function set_resource($name) 124 { 125 $this->resource = $name; 126 } 127 128 /** 129 * Connect 130 */ 131 function connect() 132 { 133 /* if (!$this->check_jid($this->username . '@' . $this->server)) 134 { 135 $this->add_to_log('Error: Jabber ID is not valid: ' . $this->username . '@' . $this->server); 136 return false; 137 }*/ 138 139 $this->session['ssl'] = $this->use_ssl; 140 141 if ($this->open_socket($this->connect_server, $this->port, $this->use_ssl)) 142 { 143 $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); 144 $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); 145 } 146 else 147 { 148 $this->add_to_log('Error: connect() #2'); 149 return false; 150 } 151 152 // Now we listen what the server has to say...and give appropriate responses 153 $this->response($this->listen()); 154 return true; 155 } 156 157 /** 158 * Disconnect 159 */ 160 function disconnect() 161 { 162 if ($this->connected()) 163 { 164 // disconnect gracefully 165 if (isset($this->session['sent_presence'])) 166 { 167 $this->send_presence('offline', '', true); 168 } 169 170 $this->send('</stream:stream>'); 171 $this->session = array(); 172 return fclose($this->connection); 173 } 174 175 return false; 176 } 177 178 /** 179 * Connected? 180 */ 181 function connected() 182 { 183 return (is_resource($this->connection) && !feof($this->connection)) ? true : false; 184 } 185 186 187 /** 188 * Initiates login (using data from contructor, after calling connect()) 189 * @access public 190 * @return bool 191 */ 192 function login() 193 { 194 if (!sizeof($this->features)) 195 { 196 $this->add_to_log('Error: No feature information from server available.'); 197 return false; 198 } 199 200 return $this->response($this->features); 201 } 202 203 /** 204 * Send data to the Jabber server 205 * @param string $xml 206 * @access public 207 * @return bool 208 */ 209 function send($xml) 210 { 211 if ($this->connected()) 212 { 213 $xml = trim($xml); 214 $this->add_to_log('SEND: '. $xml); 215 return fwrite($this->connection, $xml); 216 } 217 else 218 { 219 $this->add_to_log('Error: Could not send, connection lost (flood?).'); 220 return false; 221 } 222 } 223 224 /** 225 * OpenSocket 226 * @param string $server host to connect to 227 * @param int $port port number 228 * @param bool $use_ssl use ssl or not 229 * @access public 230 * @return bool 231 */ 232 function open_socket($server, $port, $use_ssl = false) 233 { 234 if (@function_exists('dns_get_record')) 235 { 236 $record = @dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); 237 if (!empty($record) && !empty($record[0]['target'])) 238 { 239 $server = $record[0]['target']; 240 } 241 } 242 243 $server = $use_ssl ? 'ssl://' . $server : $server; 244 245 if ($this->connection = @fsockopen($server, $port, $errorno, $errorstr, $this->timeout)) 246 { 247 socket_set_blocking($this->connection, 0); 248 socket_set_timeout($this->connection, 60); 249 250 return true; 251 } 252 253 // Apparently an error occurred... 254 $this->add_to_log('Error: open_socket() - ' . $errorstr); 255 return false; 256 } 257 258 /** 259 * Return log 260 */ 261 function get_log() 262 { 263 if ($this->enable_logging && sizeof($this->log_array)) 264 { 265 return implode("<br /><br />", $this->log_array); 266 } 267 268 return ''; 269 } 270 271 /** 272 * Add information to log 273 */ 274 function add_to_log($string) 275 { 276 if ($this->enable_logging) 277 { 278 $this->log_array[] = utf8_htmlspecialchars($string); 279 } 280 } 281 282 /** 283 * Listens to the connection until it gets data or the timeout is reached. 284 * Thus, it should only be called if data is expected to be received. 285 * @access public 286 * @return mixed either false for timeout or an array with the received data 287 */ 288 function listen($timeout = 10, $wait = false) 289 { 290 if (!$this->connected()) 291 { 292 return false; 293 } 294 295 // Wait for a response until timeout is reached 296 $start = time(); 297 $data = ''; 298 299 do 300 { 301 $read = trim(fread($this->connection, 4096)); 302 $data .= $read; 303 } 304 while (time() <= $start + $timeout && !feof($this->connection) && ($wait || $data == '' || $read != '' || (substr(rtrim($data), -1) != '>'))); 305 306 if ($data != '') 307 { 308 $this->add_to_log('RECV: '. $data); 309 return $this->xmlize($data); 310 } 311 else 312 { 313 $this->add_to_log('Timeout, no response from server.'); 314 return false; 315 } 316 } 317 318 /** 319 * Initiates account registration (based on data used for contructor) 320 * @access public 321 * @return bool 322 */ 323 function register() 324 { 325 if (!isset($this->session['id']) || isset($this->session['jid'])) 326 { 327 $this->add_to_log('Error: Cannot initiate registration.'); 328 return false; 329 } 330 331 $this->send("<iq type='get' id='reg_1'><query xmlns='jabber:iq:register'/></iq>"); 332 return $this->response($this->listen()); 333 } 334 335 /** 336 * Sets account presence. No additional info required (default is "online" status) 337 * @param $message online, offline... 338 * @param $type dnd, away, chat, xa or nothing 339 * @param $unavailable set this to true if you want to become unavailable 340 * @access public 341 * @return bool 342 */ 343 function send_presence($message = '', $type = '', $unavailable = false) 344 { 345 if (!isset($this->session['jid'])) 346 { 347 $this->add_to_log('ERROR: send_presence() - Cannot set presence at this point, no jid given.'); 348 return false; 349 } 350 351 $type = strtolower($type); 352 $type = (in_array($type, array('dnd', 'away', 'chat', 'xa'))) ? '<show>'. $type .'</show>' : ''; 353 354 $unavailable = ($unavailable) ? " type='unavailable'" : ''; 355 $message = ($message) ? '<status>' . utf8_htmlspecialchars($message) .'</status>' : ''; 356 357 $this->session['sent_presence'] = !$unavailable; 358 359 return $this->send("<presence$unavailable>" . $type . $message . '</presence>'); 360 } 361 362 /** 363 * This handles all the different XML elements 364 * @param array $xml 365 * @access public 366 * @return bool 367 */ 368 function response($xml) 369 { 370 if (!is_array($xml) || !sizeof($xml)) 371 { 372 return false; 373 } 374 375 // did we get multiple elements? do one after another 376 // array('message' => ..., 'presence' => ...) 377 if (sizeof($xml) > 1) 378 { 379 foreach ($xml as $key => $value) 380 { 381 $this->response(array($key => $value)); 382 } 383 return; 384 } 385 else 386 { 387 // or even multiple elements of the same type? 388 // array('message' => array(0 => ..., 1 => ...)) 389 if (sizeof(reset($xml)) > 1) 390 { 391 foreach (reset($xml) as $value) 392 { 393 $this->response(array(key($xml) => array(0 => $value))); 394 } 395 return; 396 } 397 } 398 399 switch (key($xml)) 400 { 401 case 'stream:stream': 402 // Connection initialised (or after authentication). Not much to do here... 403 404 if (isset($xml['stream:stream'][0]['#']['stream:features'])) 405 { 406 // we already got all info we need 407 $this->features = $xml['stream:stream'][0]['#']; 408 } 409 else 410 { 411 $this->features = $this->listen(); 412 } 413 414 $second_time = isset($this->session['id']); 415 $this->session['id'] = $xml['stream:stream'][0]['@']['id']; 416 417 if ($second_time) 418 { 419 // If we are here for the second time after TLS, we need to continue logging in 420 return $this->login(); 421 } 422 423 // go on with authentication? 424 if (isset($this->features['stream:features'][0]['#']['bind']) || !empty($this->session['tls'])) 425 { 426 return $this->response($this->features); 427 } 428 break; 429 430 case 'stream:features': 431 // Resource binding after successful authentication 432 if (isset($this->session['authenticated'])) 433 { 434 // session required? 435 $this->session['sess_required'] = isset($xml['stream:features'][0]['#']['session']); 436 437 $this->send("<iq type='set' id='bind_1'> 438 <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> 439 <resource>" . utf8_htmlspecialchars($this->resource) . '</resource> 440 </bind> 441 </iq>'); 442 return $this->response($this->listen()); 443 } 444 445 // Let's use TLS if SSL is not enabled and we can actually use it 446 if (!$this->session['ssl'] && $this->can_use_tls() && $this->can_use_ssl() && isset($xml['stream:features'][0]['#']['starttls'])) 447 { 448 $this->add_to_log('Switching to TLS.'); 449 $this->send("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); 450 return $this->response($this->listen()); 451 } 452 453 // Does the server support SASL authentication? 454 455 // I hope so, because we do (and no other method). 456 if (isset($xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns']) && $xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-sasl') 457 { 458 // Now decide on method 459 $methods = array(); 460 461 foreach ($xml['stream:features'][0]['#']['mechanisms'][0]['#']['mechanism'] as $value) 462 { 463 $methods[] = $value['#']; 464 } 465 466 // we prefer DIGEST-MD5 467 // we don't want to use plain authentication (neither does the server usually) if no encryption is in place 468 469 // http://www.xmpp.org/extensions/attic/jep-0078-1.7.html 470 // The plaintext mechanism SHOULD NOT be used unless the underlying stream is encrypted (using SSL or TLS) 471 // and the client has verified that the server certificate is signed by a trusted certificate authority. 472 473 if (in_array('DIGEST-MD5', $methods)) 474 { 475 $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>"); 476 } 477 else if (in_array('PLAIN', $methods) && ($this->session['ssl'] || !empty($this->session['tls']))) 478 { 479 // http://www.ietf.org/rfc/rfc4616.txt (PLAIN SASL Mechanism) 480 $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" 481 . base64_encode($this->username . '@' . $this->server . chr(0) . $this->username . chr(0) . $this->password) . 482 '</auth>'); 483 } 484 else if (in_array('ANONYMOUS', $methods)) 485 { 486 $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>"); 487 } 488 else 489 { 490 // not good... 491 $this->add_to_log('Error: No authentication method supported.'); 492 $this->disconnect(); 493 return false; 494 } 495 496 return $this->response($this->listen()); 497 } 498 else 499 { 500 // ok, this is it. bye. 501 $this->add_to_log('Error: Server does not offer SASL authentication.'); 502 $this->disconnect(); 503 return false; 504 } 505 break; 506 507 case 'challenge': 508 // continue with authentication...a challenge literally -_- 509 $decoded = base64_decode($xml['challenge'][0]['#']); 510 $decoded = $this->parse_data($decoded); 511 512 if (!isset($decoded['digest-uri'])) 513 { 514 $decoded['digest-uri'] = 'xmpp/'. $this->server; 515 } 516 517 // better generate a cnonce, maybe it's needed 518 $decoded['cnonce'] = base64_encode(md5(uniqid(mt_rand(), true))); 519 520 // second challenge? 521 if (isset($decoded['rspauth'])) 522 { 523 $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"); 524 } 525 else 526 { 527 // Make sure we only use 'auth' for qop (relevant for $this->encrypt_password()) 528 // If the <response> is choking up on the changed parameter we may need to adjust encrypt_password() directly 529 if (isset($decoded['qop']) && $decoded['qop'] != 'auth' && strpos($decoded['qop'], 'auth') !== false) 530 { 531 $decoded['qop'] = 'auth'; 532 } 533 534 $response = array( 535 'username' => $this->username, 536 'response' => $this->encrypt_password(array_merge($decoded, array('nc' => '00000001'))), 537 'charset' => 'utf-8', 538 'nc' => '00000001', 539 'qop' => 'auth', // only auth being supported 540 ); 541 542 foreach (array('nonce', 'digest-uri', 'realm', 'cnonce') as $key) 543 { 544 if (isset($decoded[$key])) 545 { 546 $response[$key] = $decoded[$key]; 547 } 548 } 549 550 $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" . base64_encode($this->implode_data($response)) . '</response>'); 551 } 552 553 return $this->response($this->listen()); 554 break; 555 556 case 'failure': 557 $this->add_to_log('Error: Server sent "failure".'); 558 $this->disconnect(); 559 return false; 560 break; 561 562 case 'proceed': 563 // continue switching to TLS 564 $meta = stream_get_meta_data($this->connection); 565 socket_set_blocking($this->connection, 1); 566 567 if (!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) 568 { 569 $this->add_to_log('Error: TLS mode change failed.'); 570 return false; 571 } 572 573 socket_set_blocking($this->connection, $meta['blocked']); 574 $this->session['tls'] = true; 575 576 // new stream 577 $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); 578 $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); 579 580 return $this->response($this->listen()); 581 break; 582 583 case 'success': 584 // Yay, authentication successful. 585 $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); 586 $this->session['authenticated'] = true; 587 588 // we have to wait for another response 589 return $this->response($this->listen()); 590 break; 591 592 case 'iq': 593 // we are not interested in IQs we did not expect 594 if (!isset($xml['iq'][0]['@']['id'])) 595 { 596 return false; 597 } 598 599 // multiple possibilities here 600 switch ($xml['iq'][0]['@']['id']) 601 { 602 case 'bind_1': 603 $this->session['jid'] = $xml['iq'][0]['#']['bind'][0]['#']['jid'][0]['#']; 604 605 // and (maybe) yet another request to be able to send messages *finally* 606 if ($this->session['sess_required']) 607 { 608 $this->send("<iq to='{$this->server}' type='set' id='sess_1'> 609 <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/> 610 </iq>"); 611 return $this->response($this->listen()); 612 } 613 614 return true; 615 break; 616 617 case 'sess_1': 618 return true; 619 break; 620 621 case 'reg_1': 622 $this->send("<iq type='set' id='reg_2'> 623 <query xmlns='jabber:iq:register'> 624 <username>" . utf8_htmlspecialchars($this->username) . "</username> 625 <password>" . utf8_htmlspecialchars($this->password) . "</password> 626 </query> 627 </iq>"); 628 return $this->response($this->listen()); 629 break; 630 631 case 'reg_2': 632 // registration end 633 if (isset($xml['iq'][0]['#']['error'])) 634 { 635 $this->add_to_log('Warning: Registration failed.'); 636 return false; 637 } 638 return true; 639 break; 640 641 case 'unreg_1': 642 return true; 643 break; 644 645 default: 646 $this->add_to_log('Notice: Received unexpected IQ.'); 647 return false; 648 break; 649 } 650 break; 651 652 case 'message': 653 // we are only interested in content... 654 if (!isset($xml['message'][0]['#']['body'])) 655 { 656 return false; 657 } 658 659 $message['body'] = $xml['message'][0]['#']['body'][0]['#']; 660 $message['from'] = $xml['message'][0]['@']['from']; 661 662 if (isset($xml['message'][0]['#']['subject'])) 663 { 664 $message['subject'] = $xml['message'][0]['#']['subject'][0]['#']; 665 } 666 $this->session['messages'][] = $message; 667 break; 668 669 default: 670 // hm...don't know this response 671 $this->add_to_log('Notice: Unknown server response (' . key($xml) . ')'); 672 return false; 673 break; 674 } 675 } 676 677 function send_message($to, $text, $subject = '', $type = 'normal') 678 { 679 if (!isset($this->session['jid'])) 680 { 681 return false; 682 } 683 684 if (!in_array($type, array('chat', 'normal', 'error', 'groupchat', 'headline'))) 685 { 686 $type = 'normal'; 687 } 688 689 return $this->send("<message from='" . utf8_htmlspecialchars($this->session['jid']) . "' to='" . utf8_htmlspecialchars($to) . "' type='$type' id='" . uniqid('msg') . "'> 690 <subject>" . utf8_htmlspecialchars($subject) . "</subject> 691 <body>" . utf8_htmlspecialchars($text) . "</body> 692 </message>" 693 ); 694 } 695 696 /** 697 * Encrypts a password as in RFC 2831 698 * @param array $data Needs data from the client-server connection 699 * @access public 700 * @return string 701 */ 702 function encrypt_password($data) 703 { 704 // let's me think about <challenge> again... 705 foreach (array('realm', 'cnonce', 'digest-uri') as $key) 706 { 707 if (!isset($data[$key])) 708 { 709 $data[$key] = ''; 710 } 711 } 712 713 $pack = md5($this->username . ':' . $data['realm'] . ':' . $this->password); 714 715 if (isset($data['authzid'])) 716 { 717 $a1 = pack('H32', $pack) . sprintf(':%s:%s:%s', $data['nonce'], $data['cnonce'], $data['authzid']); 718 } 719 else 720 { 721 $a1 = pack('H32', $pack) . sprintf(':%s:%s', $data['nonce'], $data['cnonce']); 722 } 723 724 // should be: qop = auth 725 $a2 = 'AUTHENTICATE:'. $data['digest-uri']; 726 727 return md5(sprintf('%s:%s:%s:%s:%s:%s', md5($a1), $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'], md5($a2))); 728 } 729 730 /** 731 * parse_data like a="b",c="d",... or like a="a, b", c, d="e", f=g,... 732 * @param string $data 733 * @access public 734 * @return array a => b ... 735 */ 736 function parse_data($data) 737 { 738 $data = explode(',', $data); 739 $pairs = array(); 740 $key = false; 741 742 foreach ($data as $pair) 743 { 744 $dd = strpos($pair, '='); 745 746 if ($dd) 747 { 748 $key = trim(substr($pair, 0, $dd)); 749 $pairs[$key] = trim(trim(substr($pair, $dd + 1)), '"'); 750 } 751 else if (strpos(strrev(trim($pair)), '"') === 0 && $key) 752 { 753 // We are actually having something left from "a, b" values, add it to the last one we handled. 754 $pairs[$key] .= ',' . trim(trim($pair), '"'); 755 continue; 756 } 757 } 758 759 return $pairs; 760 } 761 762 /** 763 * opposite of jabber::parse_data() 764 * @param array $data 765 * @access public 766 * @return string 767 */ 768 function implode_data($data) 769 { 770 $return = array(); 771 foreach ($data as $key => $value) 772 { 773 $return[] = $key . '="' . $value . '"'; 774 } 775 return implode(',', $return); 776 } 777 778 /** 779 * xmlize() 780 * @author Hans Anderson 781 * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ 782 */ 783 function xmlize($data, $skip_white = 1, $encoding = 'UTF-8') 784 { 785 $data = trim($data); 786 787 if (substr($data, 0, 5) != '<?xml') 788 { 789 // mod 790 $data = '<root>'. $data . '</root>'; 791 } 792 793 $vals = $index = $array = array(); 794 $parser = xml_parser_create($encoding); 795 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 796 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, $skip_white); 797 xml_parse_into_struct($parser, $data, $vals, $index); 798 xml_parser_free($parser); 799 800 $i = 0; 801 $tagname = $vals[$i]['tag']; 802 803 $array[$tagname][0]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); 804 $array[$tagname][0]['#'] = $this->_xml_depth($vals, $i); 805 806 if (substr($data, 0, 5) != '<?xml') 807 { 808 $array = $array['root'][0]['#']; 809 } 810 811 return $array; 812 } 813 814 /** 815 * _xml_depth() 816 * @author Hans Anderson 817 * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ 818 */ 819 function _xml_depth($vals, &$i) 820 { 821 $children = array(); 822 823 if (isset($vals[$i]['value'])) 824 { 825 array_push($children, $vals[$i]['value']); 826 } 827 828 while (++$i < sizeof($vals)) 829 { 830 switch ($vals[$i]['type']) 831 { 832 case 'open': 833 834 $tagname = (isset($vals[$i]['tag'])) ? $vals[$i]['tag'] : ''; 835 $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0; 836 837 if (isset($vals[$i]['attributes'])) 838 { 839 $children[$tagname][$size]['@'] = $vals[$i]['attributes']; 840 } 841 842 $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); 843 844 break; 845 846 case 'cdata': 847 array_push($children, $vals[$i]['value']); 848 break; 849 850 case 'complete': 851 852 $tagname = $vals[$i]['tag']; 853 $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0; 854 $children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? $vals[$i]['value'] : array(); 855 856 if (isset($vals[$i]['attributes'])) 857 { 858 $children[$tagname][$size]['@'] = $vals[$i]['attributes']; 859 } 860 861 break; 862 863 case 'close': 864 return $children; 865 break; 866 } 867 } 868 869 return $children; 870 } 871 } 872 873 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Oct 2 15:03:47 2013 | Cross-referenced by PHPXref 0.7.1 |