[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

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      var $map_attrs_func;
  90      var $map_xmlns_func;
  91      var $error;
  92      var $content;
  93  
  94      /**
  95       * PHP5 constructor.
  96       */
  97      function __construct() {
  98  
  99          $this->feed = new AtomFeed();
 100          $this->current = null;
 101          $this->map_attrs_func = array( __CLASS__, 'map_attrs' );
 102          $this->map_xmlns_func = array( __CLASS__, 'map_xmlns' );
 103      }
 104  
 105      /**
 106       * PHP4 constructor.
 107       */
 108  	public function AtomParser() {
 109          self::__construct();
 110      }
 111  
 112      /**
 113       * Map attributes to key="val"
 114       *
 115       * @param string $k Key
 116       * @param string $v Value
 117       * @return string
 118       */
 119  	public static function map_attrs($k, $v) {
 120          return "$k=\"$v\"";
 121      }
 122  
 123      /**
 124       * Map XML namespace to string.
 125       *
 126       * @param indexish $p XML Namespace element index
 127       * @param array $n Two-element array pair. [ 0 => {namespace}, 1 => {url} ]
 128       * @return string 'xmlns="{url}"' or 'xmlns:{namespace}="{url}"'
 129       */
 130  	public static function map_xmlns($p, $n) {
 131          $xd = "xmlns";
 132          if( 0 < strlen($n[0]) ) {
 133              $xd .= ":{$n[0]}";
 134          }
 135          return "{$xd}=\"{$n[1]}\"";
 136      }
 137  
 138      function _p($msg) {
 139          if($this->debug) {
 140              print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n";
 141          }
 142      }
 143  
 144      function error_handler($log_level, $log_text, $error_file, $error_line) {
 145          $this->error = $log_text;
 146      }
 147  
 148      function parse() {
 149  
 150          set_error_handler(array(&$this, 'error_handler'));
 151  
 152          array_unshift($this->ns_contexts, array());
 153  
 154          if ( ! function_exists( 'xml_parser_create_ns' ) ) {
 155              trigger_error( __( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ) );
 156              return false;
 157          }
 158  
 159          $parser = xml_parser_create_ns();
 160          xml_set_element_handler($parser, array($this, "start_element"), array($this, "end_element"));
 161          xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
 162          xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
 163          xml_set_character_data_handler($parser, array($this, "cdata"));
 164          xml_set_default_handler($parser, array($this, "_default"));
 165          xml_set_start_namespace_decl_handler($parser, array($this, "start_ns"));
 166          xml_set_end_namespace_decl_handler($parser, array($this, "end_ns"));
 167  
 168          $this->content = '';
 169  
 170          $ret = true;
 171  
 172          $fp = fopen($this->FILE, "r");
 173          while ($data = fread($fp, 4096)) {
 174              if($this->debug) $this->content .= $data;
 175  
 176              if(!xml_parse($parser, $data, feof($fp))) {
 177                  /* translators: 1: Error message, 2: Line number. */
 178                  trigger_error(sprintf(__('XML Error: %1$s at line %2$s')."\n",
 179                      xml_error_string(xml_get_error_code($parser)),
 180                      xml_get_current_line_number($parser)));
 181                  $ret = false;
 182                  break;
 183              }
 184          }
 185          fclose($fp);
 186  
 187          if (PHP_VERSION_ID < 80000) { // xml_parser_free() has no effect as of PHP 8.0.
 188              xml_parser_free($parser);
 189          }
 190  
 191          unset($parser);
 192  
 193          restore_error_handler();
 194  
 195          return $ret;
 196      }
 197  
 198      function start_element($parser, $name, $attrs) {
 199  
 200          $name_parts = explode(":", $name);
 201          $tag        = array_pop($name_parts);
 202  
 203          switch($name) {
 204              case $this->NS . ':feed':
 205                  $this->current = $this->feed;
 206                  break;
 207              case $this->NS . ':entry':
 208                  $this->current = new AtomEntry();
 209                  break;
 210          };
 211  
 212          $this->_p("start_element('$name')");
 213          #$this->_p(print_r($this->ns_contexts,true));
 214          #$this->_p('current(' . $this->current . ')');
 215  
 216          array_unshift($this->ns_contexts, $this->ns_decls);
 217  
 218          $this->depth++;
 219  
 220          if(!empty($this->in_content)) {
 221  
 222              $this->content_ns_decls = array();
 223  
 224              if($this->is_html || $this->is_text)
 225                  trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
 226  
 227              $attrs_prefix = array();
 228  
 229              // resolve prefixes for attributes
 230              foreach($attrs as $key => $value) {
 231                  $with_prefix = $this->ns_to_prefix($key, true);
 232                  $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
 233              }
 234  
 235              $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
 236              if(strlen($attrs_str) > 0) {
 237                  $attrs_str = " " . $attrs_str;
 238              }
 239  
 240              $with_prefix = $this->ns_to_prefix($name);
 241  
 242              if(!$this->is_declared_content_ns($with_prefix[0])) {
 243                  array_push($this->content_ns_decls, $with_prefix[0]);
 244              }
 245  
 246              $xmlns_str = '';
 247              if(count($this->content_ns_decls) > 0) {
 248                  array_unshift($this->content_ns_contexts, $this->content_ns_decls);
 249                  $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
 250                  if(strlen($xmlns_str) > 0) {
 251                      $xmlns_str = " " . $xmlns_str;
 252                  }
 253              }
 254  
 255              array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
 256  
 257          } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
 258              $this->in_content = array();
 259              $this->is_xhtml = $attrs['type'] == 'xhtml';
 260              $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
 261              $this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
 262              $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
 263  
 264              if(in_array('src',array_keys($attrs))) {
 265                  $this->current->$tag = $attrs;
 266              } else {
 267                  array_push($this->in_content, array($tag,$this->depth, $type));
 268              }
 269          } else if($tag == 'link') {
 270              array_push($this->current->links, $attrs);
 271          } else if($tag == 'category') {
 272              array_push($this->current->categories, $attrs);
 273          }
 274  
 275          $this->ns_decls = array();
 276      }
 277  
 278      function end_element($parser, $name) {
 279  
 280          $name_parts = explode(":", $name);
 281          $tag        = array_pop($name_parts);
 282  
 283          $ccount = count($this->in_content);
 284  
 285          # if we are *in* content, then let's proceed to serialize it
 286          if(!empty($this->in_content)) {
 287              # if we are ending the original content element
 288              # then let's finalize the content
 289              if($this->in_content[0][0] == $tag &&
 290                  $this->in_content[0][1] == $this->depth) {
 291                  $origtype = $this->in_content[0][2];
 292                  array_shift($this->in_content);
 293                  $newcontent = array();
 294                  foreach($this->in_content as $c) {
 295                      if(count($c) == 3) {
 296                          array_push($newcontent, $c[2]);
 297                      } else {
 298                          if($this->is_xhtml || $this->is_text) {
 299                              array_push($newcontent, $this->xml_escape($c));
 300                          } else {
 301                              array_push($newcontent, $c);
 302                          }
 303                      }
 304                  }
 305                  if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) {
 306                      $this->current->$tag = array($origtype, join('',$newcontent));
 307                  } else {
 308                      $this->current->$tag = join('',$newcontent);
 309                  }
 310                  $this->in_content = array();
 311              } else if($this->in_content[$ccount-1][0] == $tag &&
 312                  $this->in_content[$ccount-1][1] == $this->depth) {
 313                  $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
 314              } else {
 315                  # else, just finalize the current element's content
 316                  $endtag = $this->ns_to_prefix($name);
 317                  array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
 318              }
 319          }
 320  
 321          array_shift($this->ns_contexts);
 322  
 323          $this->depth--;
 324  
 325          if($name == ($this->NS . ':entry')) {
 326              array_push($this->feed->entries, $this->current);
 327              $this->current = null;
 328          }
 329  
 330          $this->_p("end_element('$name')");
 331      }
 332  
 333      function start_ns($parser, $prefix, $uri) {
 334          $this->_p("starting: " . $prefix . ":" . $uri);
 335          array_push($this->ns_decls, array($prefix,$uri));
 336      }
 337  
 338      function end_ns($parser, $prefix) {
 339          $this->_p("ending: #" . $prefix . "#");
 340      }
 341  
 342      function cdata($parser, $data) {
 343          $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
 344          if(!empty($this->in_content)) {
 345              array_push($this->in_content, $data);
 346          }
 347      }
 348  
 349      function _default($parser, $data) {
 350          # when does this gets called?
 351      }
 352  
 353  
 354      function ns_to_prefix($qname, $attr=false) {
 355          # split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
 356          $components = explode(":", $qname);
 357  
 358          # grab the last one (e.g 'div')
 359          $name = array_pop($components);
 360  
 361          if(!empty($components)) {
 362              # re-join back the namespace component
 363              $ns = join(":",$components);
 364              foreach($this->ns_contexts as $context) {
 365                  foreach($context as $mapping) {
 366                      if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
 367                          return array($mapping, "$mapping[0]:$name");
 368                      }
 369                  }
 370              }
 371          }
 372  
 373          if($attr) {
 374              return array(null, $name);
 375          } else {
 376              foreach($this->ns_contexts as $context) {
 377                  foreach($context as $mapping) {
 378                      if(strlen($mapping[0]) == 0) {
 379                          return array($mapping, $name);
 380                      }
 381                  }
 382              }
 383          }
 384      }
 385  
 386      function is_declared_content_ns($new_mapping) {
 387          foreach($this->content_ns_contexts as $context) {
 388              foreach($context as $mapping) {
 389                  if($new_mapping == $mapping) {
 390                      return true;
 391                  }
 392              }
 393          }
 394          return false;
 395      }
 396  
 397      function xml_escape($content)
 398      {
 399               return str_replace(array('&','"',"'",'<','>'),
 400                  array('&amp;','&quot;','&apos;','&lt;','&gt;'),
 401                  $content );
 402      }
 403  }


Generated : Tue Sep 9 08:20:04 2025 Cross-referenced by PHPXref