[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> atomlib.php (source)

   1  <?php
   2  /**
   3   * Atom Syndication Format PHP Library
   4   *
   5   * @package AtomLib
   6   * @link http://code.google.com/p/phpatomlib/
   7   *
   8   * @author Elias Torres <elias@torrez.us>
   9   * @version 0.4
  10   * @since 2.3.0
  11   */
  12  
  13  /**
  14   * Structure that store common Atom Feed Properties
  15   *
  16   * @package AtomLib
  17   */
  18  class AtomFeed {
  19      /**
  20       * Stores Links
  21       * @var array
  22       * @access public
  23       */
  24      var $links = array();
  25      /**
  26       * Stores Categories
  27       * @var array
  28       * @access public
  29       */
  30      var $categories = array();
  31      /**
  32       * Stores Entries
  33       *
  34       * @var array
  35       * @access public
  36       */
  37      var $entries = array();
  38  }
  39  
  40  /**
  41   * Structure that store Atom Entry Properties
  42   *
  43   * @package AtomLib
  44   */
  45  class AtomEntry {
  46      /**
  47       * Stores Links
  48       * @var array
  49       * @access public
  50       */
  51      var $links = array();
  52      /**
  53       * Stores Categories
  54       * @var array
  55       * @access public
  56       */
  57      var $categories = array();
  58  }
  59  
  60  /**
  61   * AtomLib Atom Parser API
  62   *
  63   * @package AtomLib
  64   */
  65  class AtomParser {
  66  
  67      var $NS = 'http://www.w3.org/2005/Atom';
  68      var $ATOM_CONTENT_ELEMENTS = array('content','summary','title','subtitle','rights');
  69      var $ATOM_SIMPLE_ELEMENTS = array('id','updated','published','draft');
  70  
  71      var $debug = false;
  72  
  73      var $depth = 0;
  74      var $indent = 2;
  75      var $in_content;
  76      var $ns_contexts = array();
  77      var $ns_decls = array();
  78      var $content_ns_decls = array();
  79      var $content_ns_contexts = array();
  80      var $is_xhtml = false;
  81      var $is_html = false;
  82      var $is_text = true;
  83      var $skipped_div = false;
  84  
  85      var $FILE = "php://input";
  86  
  87      var $feed;
  88      var $current;
  89  
  90      /**
  91       * PHP5 constructor.
  92       */
  93      function __construct() {
  94  
  95          $this->feed = new AtomFeed();
  96          $this->current = null;
  97          $this->map_attrs_func = array( __CLASS__, 'map_attrs' );
  98          $this->map_xmlns_func = array( __CLASS__, 'map_xmlns' );
  99      }
 100  
 101      /**
 102       * PHP4 constructor.
 103       */
 104  	public function AtomParser() {
 105          self::__construct();
 106      }
 107  
 108      /**
 109       * Map attributes to key="val"
 110       *
 111       * @param string $k Key
 112       * @param string $v Value
 113       * @return string
 114       */
 115  	public static function map_attrs($k, $v) {
 116          return "$k=\"$v\"";
 117      }
 118  
 119      /**
 120       * Map XML namespace to string.
 121       *
 122       * @param indexish $p XML Namespace element index
 123       * @param array $n Two-element array pair. [ 0 => {namespace}, 1 => {url} ]
 124       * @return string 'xmlns="{url}"' or 'xmlns:{namespace}="{url}"'
 125       */
 126  	public static function map_xmlns($p, $n) {
 127          $xd = "xmlns";
 128          if( 0 < strlen($n[0]) ) {
 129              $xd .= ":{$n[0]}";
 130          }
 131          return "{$xd}=\"{$n[1]}\"";
 132      }
 133  
 134      function _p($msg) {
 135          if($this->debug) {
 136              print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n";
 137          }
 138      }
 139  
 140      function error_handler($log_level, $log_text, $error_file, $error_line) {
 141          $this->error = $log_text;
 142      }
 143  
 144      function parse() {
 145  
 146          set_error_handler(array(&$this, 'error_handler'));
 147  
 148          array_unshift($this->ns_contexts, array());
 149  
 150          if ( ! function_exists( 'xml_parser_create_ns' ) ) {
 151              trigger_error( __( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ) );
 152              return false;
 153          }
 154  
 155          $parser = xml_parser_create_ns();
 156          xml_set_object($parser, $this);
 157          xml_set_element_handler($parser, "start_element", "end_element");
 158          xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
 159          xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
 160          xml_set_character_data_handler($parser, "cdata");
 161          xml_set_default_handler($parser, "_default");
 162          xml_set_start_namespace_decl_handler($parser, "start_ns");
 163          xml_set_end_namespace_decl_handler($parser, "end_ns");
 164  
 165          $this->content = '';
 166  
 167          $ret = true;
 168  
 169          $fp = fopen($this->FILE, "r");
 170          while ($data = fread($fp, 4096)) {
 171              if($this->debug) $this->content .= $data;
 172  
 173              if(!xml_parse($parser, $data, feof($fp))) {
 174                  /* translators: 1: Error message, 2: Line number. */
 175                  trigger_error(sprintf(__('XML Error: %1$s at line %2$s')."\n",
 176                      xml_error_string(xml_get_error_code($parser)),
 177                      xml_get_current_line_number($parser)));
 178                  $ret = false;
 179                  break;
 180              }
 181          }
 182          fclose($fp);
 183  
 184          xml_parser_free($parser);
 185          unset($parser);
 186  
 187          restore_error_handler();
 188  
 189          return $ret;
 190      }
 191  
 192      function start_element($parser, $name, $attrs) {
 193  
 194          $name_parts = explode(":", $name);
 195          $tag        = array_pop($name_parts);
 196  
 197          switch($name) {
 198              case $this->NS . ':feed':
 199                  $this->current = $this->feed;
 200                  break;
 201              case $this->NS . ':entry':
 202                  $this->current = new AtomEntry();
 203                  break;
 204          };
 205  
 206          $this->_p("start_element('$name')");
 207          #$this->_p(print_r($this->ns_contexts,true));
 208          #$this->_p('current(' . $this->current . ')');
 209  
 210          array_unshift($this->ns_contexts, $this->ns_decls);
 211  
 212          $this->depth++;
 213  
 214          if(!empty($this->in_content)) {
 215  
 216              $this->content_ns_decls = array();
 217  
 218              if($this->is_html || $this->is_text)
 219                  trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
 220  
 221              $attrs_prefix = array();
 222  
 223              // resolve prefixes for attributes
 224              foreach($attrs as $key => $value) {
 225                  $with_prefix = $this->ns_to_prefix($key, true);
 226                  $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
 227              }
 228  
 229              $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
 230              if(strlen($attrs_str) > 0) {
 231                  $attrs_str = " " . $attrs_str;
 232              }
 233  
 234              $with_prefix = $this->ns_to_prefix($name);
 235  
 236              if(!$this->is_declared_content_ns($with_prefix[0])) {
 237                  array_push($this->content_ns_decls, $with_prefix[0]);
 238              }
 239  
 240              $xmlns_str = '';
 241              if(count($this->content_ns_decls) > 0) {
 242                  array_unshift($this->content_ns_contexts, $this->content_ns_decls);
 243                  $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
 244                  if(strlen($xmlns_str) > 0) {
 245                      $xmlns_str = " " . $xmlns_str;
 246                  }
 247              }
 248  
 249              array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
 250  
 251          } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
 252              $this->in_content = array();
 253              $this->is_xhtml = $attrs['type'] == 'xhtml';
 254              $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
 255              $this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
 256              $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
 257  
 258              if(in_array('src',array_keys($attrs))) {
 259                  $this->current->$tag = $attrs;
 260              } else {
 261                  array_push($this->in_content, array($tag,$this->depth, $type));
 262              }
 263          } else if($tag == 'link') {
 264              array_push($this->current->links, $attrs);
 265          } else if($tag == 'category') {
 266              array_push($this->current->categories, $attrs);
 267          }
 268  
 269          $this->ns_decls = array();
 270      }
 271  
 272      function end_element($parser, $name) {
 273  
 274          $name_parts = explode(":", $name);
 275          $tag        = array_pop($name_parts);
 276  
 277          $ccount = count($this->in_content);
 278  
 279          # if we are *in* content, then let's proceed to serialize it
 280          if(!empty($this->in_content)) {
 281              # if we are ending the original content element
 282              # then let's finalize the content
 283              if($this->in_content[0][0] == $tag &&
 284                  $this->in_content[0][1] == $this->depth) {
 285                  $origtype = $this->in_content[0][2];
 286                  array_shift($this->in_content);
 287                  $newcontent = array();
 288                  foreach($this->in_content as $c) {
 289                      if(count($c) == 3) {
 290                          array_push($newcontent, $c[2]);
 291                      } else {
 292                          if($this->is_xhtml || $this->is_text) {
 293                              array_push($newcontent, $this->xml_escape($c));
 294                          } else {
 295                              array_push($newcontent, $c);
 296                          }
 297                      }
 298                  }
 299                  if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) {
 300                      $this->current->$tag = array($origtype, join('',$newcontent));
 301                  } else {
 302                      $this->current->$tag = join('',$newcontent);
 303                  }
 304                  $this->in_content = array();
 305              } else if($this->in_content[$ccount-1][0] == $tag &&
 306                  $this->in_content[$ccount-1][1] == $this->depth) {
 307                  $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
 308              } else {
 309                  # else, just finalize the current element's content
 310                  $endtag = $this->ns_to_prefix($name);
 311                  array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
 312              }
 313          }
 314  
 315          array_shift($this->ns_contexts);
 316  
 317          $this->depth--;
 318  
 319          if($name == ($this->NS . ':entry')) {
 320              array_push($this->feed->entries, $this->current);
 321              $this->current = null;
 322          }
 323  
 324          $this->_p("end_element('$name')");
 325      }
 326  
 327      function start_ns($parser, $prefix, $uri) {
 328          $this->_p("starting: " . $prefix . ":" . $uri);
 329          array_push($this->ns_decls, array($prefix,$uri));
 330      }
 331  
 332      function end_ns($parser, $prefix) {
 333          $this->_p("ending: #" . $prefix . "#");
 334      }
 335  
 336      function cdata($parser, $data) {
 337          $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
 338          if(!empty($this->in_content)) {
 339              array_push($this->in_content, $data);
 340          }
 341      }
 342  
 343      function _default($parser, $data) {
 344          # when does this gets called?
 345      }
 346  
 347  
 348      function ns_to_prefix($qname, $attr=false) {
 349          # split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
 350          $components = explode(":", $qname);
 351  
 352          # grab the last one (e.g 'div')
 353          $name = array_pop($components);
 354  
 355          if(!empty($components)) {
 356              # re-join back the namespace component
 357              $ns = join(":",$components);
 358              foreach($this->ns_contexts as $context) {
 359                  foreach($context as $mapping) {
 360                      if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
 361                          return array($mapping, "$mapping[0]:$name");
 362                      }
 363                  }
 364              }
 365          }
 366  
 367          if($attr) {
 368              return array(null, $name);
 369          } else {
 370              foreach($this->ns_contexts as $context) {
 371                  foreach($context as $mapping) {
 372                      if(strlen($mapping[0]) == 0) {
 373                          return array($mapping, $name);
 374                      }
 375                  }
 376              }
 377          }
 378      }
 379  
 380      function is_declared_content_ns($new_mapping) {
 381          foreach($this->content_ns_contexts as $context) {
 382              foreach($context as $mapping) {
 383                  if($new_mapping == $mapping) {
 384                      return true;
 385                  }
 386              }
 387          }
 388          return false;
 389      }
 390  
 391      function xml_escape($content)
 392      {
 393               return str_replace(array('&','"',"'",'<','>'),
 394                  array('&amp;','&quot;','&apos;','&lt;','&gt;'),
 395                  $content );
 396      }
 397  }


Generated: Sun Oct 13 01:00:02 2024 Cross-referenced by PHPXref 0.7.1