WordPress.org

Make WordPress Core

Ticket #10683: 10683.patch

File 10683.patch, 19.0 KB (added by Simek, 9 years ago)
  • atomlib.php

     
    2121         * @var array
    2222         * @access public
    2323         */
    24     var $links = array();
    25     /**
    26      * Stores Categories
    27      * @var array
    28      * @access public
    29      */
    30     var $categories = array();
     24        var $links = array();
    3125        /**
     26         * Stores Categories
     27         * @var array
     28         * @access public
     29         */
     30        var $categories = array();
     31        /**
    3232         * Stores Entries
    3333         *
    3434         * @var array
    3535         * @access public
    3636         */
    37     var $entries = array();
     37        var $entries = array();
    3838}
    3939
    4040/**
     
    4848         * @var array
    4949         * @access public
    5050         */
    51     var $links = array();
    52     /**
    53     * Stores Categories
    54     * @var array
     51        var $links = array();
     52        /**
     53        * Stores Categories
     54        * @var array
    5555         * @access public
    56     */
    57     var $categories = array();
     56        */
     57        var $categories = array();
    5858}
    5959
    6060/**
     
    6464 */
    6565class AtomParser {
    6666
    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');
     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');
    7070
    71     var $debug = false;
     71        var $debug = false;
    7272
    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;
     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;
    8484
    85     var $FILE = "php://input";
     85        var $FILE = "php://input";
    8686
    87     var $feed;
    88     var $current;
     87        var $feed;
     88        var $current;
    8989
    90     function AtomParser() {
     90        function AtomParser() {
     91                $this->feed = new AtomFeed();
     92                $this->current = null;
     93                $this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
     94                $this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
     95        }
    9196
    92         $this->feed = new AtomFeed();
    93         $this->current = null;
    94         $this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
    95         $this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
    96     }
     97        function _p($msg) {
     98                if($this->debug) print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n";
     99        }
    97100
    98     function _p($msg) {
    99         if($this->debug) {
    100             print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n";
    101         }
    102     }
     101        function error_handler($log_level, $log_text, $error_file, $error_line) {
     102                $this->error = $log_text;
     103        }
    103104
    104     function error_handler($log_level, $log_text, $error_file, $error_line) {
    105         $this->error = $log_text;
    106     }
     105        function parse() {
     106                set_error_handler(array(&$this, 'error_handler'));
    107107
    108     function parse() {
     108                array_unshift($this->ns_contexts, array());
    109109
    110         set_error_handler(array(&$this, 'error_handler'));
     110                $parser = xml_parser_create_ns();
     111                xml_set_object($parser, $this);
     112                xml_set_element_handler($parser, "start_element", "end_element");
     113                xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
     114                xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
     115                xml_set_character_data_handler($parser, "cdata");
     116                xml_set_default_handler($parser, "_default");
     117                xml_set_start_namespace_decl_handler($parser, "start_ns");
     118                xml_set_end_namespace_decl_handler($parser, "end_ns");
    111119
    112         array_unshift($this->ns_contexts, array());
     120                $this->content = '';
    113121
    114         $parser = xml_parser_create_ns();
    115         xml_set_object($parser, $this);
    116         xml_set_element_handler($parser, "start_element", "end_element");
    117         xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
    118         xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
    119         xml_set_character_data_handler($parser, "cdata");
    120         xml_set_default_handler($parser, "_default");
    121         xml_set_start_namespace_decl_handler($parser, "start_ns");
    122         xml_set_end_namespace_decl_handler($parser, "end_ns");
     122                $ret = true;
    123123
    124         $this->content = '';
     124                $fp = fopen($this->FILE, "r");
     125                while ($data = fread($fp, 4096)) {
     126                        if($this->debug) $this->content .= $data;
    125127
    126         $ret = true;
     128                        if(!xml_parse($parser, $data, feof($fp))) {
     129                                trigger_error(sprintf(__('XML error: %s at line %d')."\n",
     130                                        xml_error_string(xml_get_error_code($xml_parser)),
     131                                        xml_get_current_line_number($xml_parser)));
     132                                $ret = false;
     133                                break;
     134                        }
     135                }
     136                fclose($fp);
    127137
    128         $fp = fopen($this->FILE, "r");
    129         while ($data = fread($fp, 4096)) {
    130             if($this->debug) $this->content .= $data;
     138                xml_parser_free($parser);
    131139
    132             if(!xml_parse($parser, $data, feof($fp))) {
    133                 trigger_error(sprintf(__('XML error: %s at line %d')."\n",
    134                     xml_error_string(xml_get_error_code($xml_parser)),
    135                     xml_get_current_line_number($xml_parser)));
    136                 $ret = false;
    137                 break;
    138             }
    139         }
    140         fclose($fp);
     140                restore_error_handler();
    141141
    142         xml_parser_free($parser);
     142                return $ret;
     143        }
    143144
    144         restore_error_handler();
     145        function start_element($parser, $name, $attrs) {
     146                $tag = array_pop(split(":", $name));
    145147
    146         return $ret;
    147     }
     148                switch($name) {
     149                        case $this->NS . ':feed':
     150                                $this->current = $this->feed;
     151                                break;
     152                        case $this->NS . ':entry':
     153                                $this->current = new AtomEntry();
     154                                break;
     155                };
    148156
    149     function start_element($parser, $name, $attrs) {
     157                $this->_p("start_element('$name')");
     158                #$this->_p(print_r($this->ns_contexts,true));
     159                #$this->_p('current(' . $this->current . ')');
    150160
    151         $tag = array_pop(split(":", $name));
     161                array_unshift($this->ns_contexts, $this->ns_decls);
    152162
    153         switch($name) {
    154             case $this->NS . ':feed':
    155                 $this->current = $this->feed;
    156                 break;
    157             case $this->NS . ':entry':
    158                 $this->current = new AtomEntry();
    159                 break;
    160         };
     163                $this->depth++;
    161164
    162         $this->_p("start_element('$name')");
    163         #$this->_p(print_r($this->ns_contexts,true));
    164         #$this->_p('current(' . $this->current . ')');
     165                if(!empty($this->in_content)) {
    165166
    166         array_unshift($this->ns_contexts, $this->ns_decls);
     167                        $this->content_ns_decls = array();
    167168
    168         $this->depth++;
     169                        if($this->is_html || $this->is_text)
     170                                trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
    169171
    170         if(!empty($this->in_content)) {
     172                        $attrs_prefix = array();
    171173
    172             $this->content_ns_decls = array();
     174                        // resolve prefixes for attributes
     175                        foreach($attrs as $key => $value) {
     176                                $with_prefix = $this->ns_to_prefix($key, true);
     177                                $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
     178                        }
    173179
    174             if($this->is_html || $this->is_text)
    175                 trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
     180                        $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
     181                        if(strlen($attrs_str) > 0)
     182                                $attrs_str = " " . $attrs_str;
    176183
    177             $attrs_prefix = array();
     184                        $with_prefix = $this->ns_to_prefix($name);
    178185
    179             // resolve prefixes for attributes
    180             foreach($attrs as $key => $value) {
    181                 $with_prefix = $this->ns_to_prefix($key, true);
    182                 $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
    183             }
     186                        if(!$this->is_declared_content_ns($with_prefix[0]))
     187                                array_push($this->content_ns_decls, $with_prefix[0]);
    184188
    185             $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
    186             if(strlen($attrs_str) > 0) {
    187                 $attrs_str = " " . $attrs_str;
    188             }
     189                        $xmlns_str = '';
     190                        if(count($this->content_ns_decls) > 0) {
     191                                array_unshift($this->content_ns_contexts, $this->content_ns_decls);
     192                                $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
     193                                if(strlen($xmlns_str) > 0)
     194                                        $xmlns_str = " " . $xmlns_str;
     195                        }
    189196
    190             $with_prefix = $this->ns_to_prefix($name);
     197                        array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
    191198
    192             if(!$this->is_declared_content_ns($with_prefix[0])) {
    193                 array_push($this->content_ns_decls, $with_prefix[0]);
    194             }
     199                } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
     200                        $this->in_content = array();
     201                        $this->is_xhtml = $attrs['type'] == 'xhtml';
     202                        $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
     203                        $this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
     204                        $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
    195205
    196             $xmlns_str = '';
    197             if(count($this->content_ns_decls) > 0) {
    198                 array_unshift($this->content_ns_contexts, $this->content_ns_decls);
    199                 $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
    200                 if(strlen($xmlns_str) > 0) {
    201                     $xmlns_str = " " . $xmlns_str;
    202                 }
    203             }
     206                        if(in_array('src',array_keys($attrs)))
     207                                $this->current->$tag = $attrs;
     208                        else
     209                                array_push($this->in_content, array($tag,$this->depth, $type));
    204210
    205             array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
     211                } else if($tag == 'link') {
     212                        array_push($this->current->links, $attrs);
     213                } else if($tag == 'category') {
     214                        array_push($this->current->categories, $attrs);
     215                }
    206216
    207         } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
    208             $this->in_content = array();
    209             $this->is_xhtml = $attrs['type'] == 'xhtml';
    210             $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
    211             $this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
    212             $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
     217                $this->ns_decls = array();
     218        }
    213219
    214             if(in_array('src',array_keys($attrs))) {
    215                 $this->current->$tag = $attrs;
    216             } else {
    217                 array_push($this->in_content, array($tag,$this->depth, $type));
    218             }
    219         } else if($tag == 'link') {
    220             array_push($this->current->links, $attrs);
    221         } else if($tag == 'category') {
    222             array_push($this->current->categories, $attrs);
    223         }
     220        function end_element($parser, $name) {
    224221
    225         $this->ns_decls = array();
    226     }
     222                $tag = array_pop(split(":", $name));
    227223
    228     function end_element($parser, $name) {
     224                $ccount = count($this->in_content);
    229225
    230         $tag = array_pop(split(":", $name));
     226                # if we are *in* content, then let's proceed to serialize it
     227                if(!empty($this->in_content)) {
     228                        # if we are ending the original content element
     229                        # then let's finalize the content
     230                        if($this->in_content[0][0] == $tag &&
     231                                $this->in_content[0][1] == $this->depth) {
     232                                $origtype = $this->in_content[0][2];
     233                                array_shift($this->in_content);
     234                                $newcontent = array();
     235                                foreach($this->in_content as $c) {
     236                                        if(count($c) == 3) {
     237                                                array_push($newcontent, $c[2]);
     238                                        } else {
     239                                                if($this->is_xhtml || $this->is_text)
     240                                                        array_push($newcontent, $this->xml_escape($c));
     241                                                else
     242                                                        array_push($newcontent, $c);
     243                                        }
     244                                }
     245                                if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS))
     246                                        $this->current->$tag = array($origtype, join('',$newcontent));
     247                                else
     248                                        $this->current->$tag = join('',$newcontent);
    231249
    232         $ccount = count($this->in_content);
     250                                $this->in_content = array();
     251                        } else if($this->in_content[$ccount-1][0] == $tag &&
     252                                $this->in_content[$ccount-1][1] == $this->depth) {
     253                                $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
     254                        } else {
     255                                # else, just finalize the current element's content
     256                                $endtag = $this->ns_to_prefix($name);
     257                                array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
     258                        }
     259                }
    233260
    234         # if we are *in* content, then let's proceed to serialize it
    235         if(!empty($this->in_content)) {
    236             # if we are ending the original content element
    237             # then let's finalize the content
    238             if($this->in_content[0][0] == $tag &&
    239                 $this->in_content[0][1] == $this->depth) {
    240                 $origtype = $this->in_content[0][2];
    241                 array_shift($this->in_content);
    242                 $newcontent = array();
    243                 foreach($this->in_content as $c) {
    244                     if(count($c) == 3) {
    245                         array_push($newcontent, $c[2]);
    246                     } else {
    247                         if($this->is_xhtml || $this->is_text) {
    248                             array_push($newcontent, $this->xml_escape($c));
    249                         } else {
    250                             array_push($newcontent, $c);
    251                         }
    252                     }
    253                 }
    254                 if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) {
    255                     $this->current->$tag = array($origtype, join('',$newcontent));
    256                 } else {
    257                     $this->current->$tag = join('',$newcontent);
    258                 }
    259                 $this->in_content = array();
    260             } else if($this->in_content[$ccount-1][0] == $tag &&
    261                 $this->in_content[$ccount-1][1] == $this->depth) {
    262                 $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
    263             } else {
    264                 # else, just finalize the current element's content
    265                 $endtag = $this->ns_to_prefix($name);
    266                 array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
    267             }
    268         }
     261                array_shift($this->ns_contexts);
    269262
    270         array_shift($this->ns_contexts);
     263                $this->depth--;
    271264
    272         $this->depth--;
     265                if($name == ($this->NS . ':entry')) {
     266                        array_push($this->feed->entries, $this->current);
     267                        $this->current = null;
     268                }
    273269
    274         if($name == ($this->NS . ':entry')) {
    275             array_push($this->feed->entries, $this->current);
    276             $this->current = null;
    277         }
     270                $this->_p("end_element('$name')");
     271        }
    278272
    279         $this->_p("end_element('$name')");
    280     }
     273        function start_ns($parser, $prefix, $uri) {
     274                $this->_p("starting: " . $prefix . ":" . $uri);
     275                array_push($this->ns_decls, array($prefix,$uri));
     276        }
    281277
    282     function start_ns($parser, $prefix, $uri) {
    283         $this->_p("starting: " . $prefix . ":" . $uri);
    284         array_push($this->ns_decls, array($prefix,$uri));
    285     }
     278        function end_ns($parser, $prefix) {
     279                $this->_p("ending: #" . $prefix . "#");
     280        }
    286281
    287     function end_ns($parser, $prefix) {
    288         $this->_p("ending: #" . $prefix . "#");
    289     }
     282        function cdata($parser, $data) {
     283                $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
     284                if(!empty($this->in_content))
     285                        array_push($this->in_content, $data);
     286        }
    290287
    291     function cdata($parser, $data) {
    292         $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
    293         if(!empty($this->in_content)) {
    294             array_push($this->in_content, $data);
    295         }
    296     }
     288        function _default($parser, $data) {
     289                # when does this gets called?
     290        }
    297291
    298     function _default($parser, $data) {
    299         # when does this gets called?
    300     }
    301292
     293        function ns_to_prefix($qname, $attr=false) {
     294                # split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
     295                $components = split(":", $qname);
    302296
    303     function ns_to_prefix($qname, $attr=false) {
    304         # split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
    305         $components = split(":", $qname);
     297                # grab the last one (e.g 'div')
     298                $name = array_pop($components);
    306299
    307         # grab the last one (e.g 'div')
    308         $name = array_pop($components);
     300                if(!empty($components)) {
     301                        # re-join back the namespace component
     302                        $ns = join(":",$components);
     303                        foreach($this->ns_contexts as $context) {
     304                                foreach($context as $mapping) {
     305                                        if($mapping[1] == $ns && strlen($mapping[0]) > 0)
     306                                                return array($mapping, "$mapping[0]:$name");
     307                                }
     308                        }
     309                }
    309310
    310         if(!empty($components)) {
    311             # re-join back the namespace component
    312             $ns = join(":",$components);
    313             foreach($this->ns_contexts as $context) {
    314                 foreach($context as $mapping) {
    315                     if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
    316                         return array($mapping, "$mapping[0]:$name");
    317                     }
    318                 }
    319             }
    320         }
     311                if($attr) {
     312                        return array(null, $name);
     313                } else {
     314                        foreach($this->ns_contexts as $context) {
     315                                foreach($context as $mapping) {
     316                                        if(strlen($mapping[0]) == 0)
     317                                                return array($mapping, $name);
     318                                }
     319                        }
     320                }
     321        }
    321322
    322         if($attr) {
    323             return array(null, $name);
    324         } else {
    325             foreach($this->ns_contexts as $context) {
    326                 foreach($context as $mapping) {
    327                     if(strlen($mapping[0]) == 0) {
    328                         return array($mapping, $name);
    329                     }
    330                 }
    331             }
    332         }
    333     }
     323        function is_declared_content_ns($new_mapping) {
     324                foreach($this->content_ns_contexts as $context) {
     325                        foreach($context as $mapping) {
     326                                if($new_mapping == $mapping)
     327                                        return true;
     328                        }
     329                }
     330                return false;
     331        }
    334332
    335     function is_declared_content_ns($new_mapping) {
    336         foreach($this->content_ns_contexts as $context) {
    337             foreach($context as $mapping) {
    338                 if($new_mapping == $mapping) {
    339                     return true;
    340                 }
    341             }
    342         }
    343         return false;
    344     }
    345 
    346     function xml_escape($string)
    347     {
    348              return str_replace(array('&','"',"'",'<','>'),
    349                 array('&amp;','&quot;','&apos;','&lt;','&gt;'),
    350                 $string );
    351     }
     333        function xml_escape($string)
     334        {
     335                         return str_replace(array('&','"',"'",'<','>'),
     336                                array('&amp;','&quot;','&apos;','&lt;','&gt;'),
     337                                $string );
     338        }
    352339}
    353340
    354341?>