[ 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          xml_parser_free($parser);
 188          unset($parser);
 189  
 190          restore_error_handler();
 191  
 192          return $ret;
 193      }
 194  
 195      function start_element($parser, $name, $attrs) {
 196  
 197          $name_parts = explode(":", $name);
 198          $tag        = array_pop($name_parts);
 199  
 200          switch($name) {
 201              case $this->NS . ':feed':
 202                  $this->current = $this->feed;
 203                  break;
 204              case $this->NS . ':entry':
 205                  $this->current = new AtomEntry();
 206                  break;
 207          };
 208  
 209          $this->_p("start_element('$name')");
 210          #$this->_p(print_r($this->ns_contexts,true));
 211          #$this->_p('current(' . $this->current . ')');
 212  
 213          array_unshift($this->ns_contexts, $this->ns_decls);
 214  
 215          $this->depth++;
 216  
 217          if(!empty($this->in_content)) {
 218  
 219              $this->content_ns_decls = array();
 220  
 221              if($this->is_html || $this->is_text)
 222                  trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
 223  
 224              $attrs_prefix = array();
 225  
 226              // resolve prefixes for attributes
 227              foreach($attrs as $key => $value) {
 228                  $with_prefix = $this->ns_to_prefix($key, true);
 229                  $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
 230              }
 231  
 232              $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
 233              if(strlen($attrs_str) > 0) {
 234                  $attrs_str = " " . $attrs_str;
 235              }
 236  
 237              $with_prefix = $this->ns_to_prefix($name);
 238  
 239              if(!$this->is_declared_content_ns($with_prefix[0])) {
 240                  array_push($this->content_ns_decls, $with_prefix[0]);
 241              }
 242  
 243              $xmlns_str = '';
 244              if(count($this->content_ns_decls) > 0) {
 245                  array_unshift($this->content_ns_contexts, $this->content_ns_decls);
 246                  $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
 247                  if(strlen($xmlns_str) > 0) {
 248                      $xmlns_str = " " . $xmlns_str;
 249                  }
 250              }
 251  
 252              array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
 253  
 254          } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
 255              $this->in_content = array();
 256              $this->is_xhtml = $attrs['type'] == 'xhtml';
 257              $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
 258              $this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
 259              $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
 260  
 261              if(in_array('src',array_keys($attrs))) {
 262                  $this->current->$tag = $attrs;
 263              } else {
 264                  array_push($this->in_content, array($tag,$this->depth, $type));
 265              }
 266          } else if($tag == 'link') {
 267              array_push($this->current->links, $attrs);
 268          } else if($tag == 'category') {
 269              array_push($this->current->categories, $attrs);
 270          }
 271  
 272          $this->ns_decls = array();
 273      }
 274  
 275      function end_element($parser, $name) {
 276  
 277          $name_parts = explode(":", $name);
 278          $tag        = array_pop($name_parts);
 279  
 280          $ccount = count($this->in_content);
 281  
 282          # if we are *in* content, then let's proceed to serialize it
 283          if(!empty($this->in_content)) {
 284              # if we are ending the original content element
 285              # then let's finalize the content
 286              if($this->in_content[0][0] == $tag &&
 287                  $this->in_content[0][1] == $this->depth) {
 288                  $origtype = $this->in_content[0][2];
 289                  array_shift($this->in_content);
 290                  $newcontent = array();
 291                  foreach($this->in_content as $c) {
 292                      if(count($c) == 3) {
 293                          array_push($newcontent, $c[2]);
 294                      } else {
 295                          if($this->is_xhtml || $this->is_text) {
 296                              array_push($newcontent, $this->xml_escape($c));
 297                          } else {
 298                              array_push($newcontent, $c);
 299                          }
 300                      }
 301                  }
 302                  if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) {
 303                      $this->current->$tag = array($origtype, join('',$newcontent));
 304                  } else {
 305                      $this->current->$tag = join('',$newcontent);
 306                  }
 307                  $this->in_content = array();
 308              } else if($this->in_content[$ccount-1][0] == $tag &&
 309                  $this->in_content[$ccount-1][1] == $this->depth) {
 310                  $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
 311              } else {
 312                  # else, just finalize the current element's content
 313                  $endtag = $this->ns_to_prefix($name);
 314                  array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
 315              }
 316          }
 317  
 318          array_shift($this->ns_contexts);
 319  
 320          $this->depth--;
 321  
 322          if($name == ($this->NS . ':entry')) {
 323              array_push($this->feed->entries, $this->current);
 324              $this->current = null;
 325          }
 326  
 327          $this->_p("end_element('$name')");
 328      }
 329  
 330      function start_ns($parser, $prefix, $uri) {
 331          $this->_p("starting: " . $prefix . ":" . $uri);
 332          array_push($this->ns_decls, array($prefix,$uri));
 333      }
 334  
 335      function end_ns($parser, $prefix) {
 336          $this->_p("ending: #" . $prefix . "#");
 337      }
 338  
 339      function cdata($parser, $data) {
 340          $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
 341          if(!empty($this->in_content)) {
 342              array_push($this->in_content, $data);
 343          }
 344      }
 345  
 346      function _default($parser, $data) {
 347          # when does this gets called?
 348      }
 349  
 350  
 351      function ns_to_prefix($qname, $attr=false) {
 352          # split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
 353          $components = explode(":", $qname);
 354  
 355          # grab the last one (e.g 'div')
 356          $name = array_pop($components);
 357  
 358          if(!empty($components)) {
 359              # re-join back the namespace component
 360              $ns = join(":",$components);
 361              foreach($this->ns_contexts as $context) {
 362                  foreach($context as $mapping) {
 363                      if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
 364                          return array($mapping, "$mapping[0]:$name");
 365                      }
 366                  }
 367              }
 368          }
 369  
 370          if($attr) {
 371              return array(null, $name);
 372          } else {
 373              foreach($this->ns_contexts as $context) {
 374                  foreach($context as $mapping) {
 375                      if(strlen($mapping[0]) == 0) {
 376                          return array($mapping, $name);
 377                      }
 378                  }
 379              }
 380          }
 381      }
 382  
 383      function is_declared_content_ns($new_mapping) {
 384          foreach($this->content_ns_contexts as $context) {
 385              foreach($context as $mapping) {
 386                  if($new_mapping == $mapping) {
 387                      return true;
 388                  }
 389              }
 390          }
 391          return false;
 392      }
 393  
 394      function xml_escape($content)
 395      {
 396               return str_replace(array('&','"',"'",'<','>'),
 397                  array('&amp;','&quot;','&apos;','&lt;','&gt;'),
 398                  $content );
 399      }
 400  }


Generated : Tue Dec 3 08:20:01 2024 Cross-referenced by PHPXref