Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_jabber.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 20.83 KiB


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