From: Andrew Dolgov Date: Thu, 17 May 2007 07:19:20 +0000 (+0100) Subject: magpie: add latest dev. build of 0.8x from cvs X-Git-Tag: schema_freeze_for_1.2.11~28 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=489ffe5a21687cd5ac3da1e9081b7439a2bcc97b;p=tt-rss.git magpie: add latest dev. build of 0.8x from cvs --- diff --git a/magpierss/rss_parse.inc b/magpierss/rss_parse.inc index b7c0ceb5..0b2ddc83 100644 --- a/magpierss/rss_parse.inc +++ b/magpierss/rss_parse.inc @@ -5,7 +5,7 @@ * File: rss_parse.inc - parse an RSS or Atom feed * return as a simple object. * -* Handles RSS 0.9x, RSS 2.0, RSS 1.0, and Atom 0.3 +* Handles RSS 0.9x, RSS 2.0, RSS 1.0, Atom 0.3, and Atom 1.0 * * The lastest version of MagpieRSS can be obtained from: * http://magpierss.sourceforge.net @@ -15,7 +15,7 @@ * magpierss-general@lists.sourceforge.net * * @author Kellan Elliott-McCrea -* @version 0.7a +* @version 0.8 * @license GPL * */ @@ -50,19 +50,26 @@ class MagpieRSS { // define some constants - var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright'); + var $_ATOM_CONTENT_CONSTRUCTS = array( + 'content', 'summary', 'title', /* common */ + 'info', 'tagline', 'copyright', /* Atom 0.3 */ + 'rights', 'subtitle', /* Atom 1.0 */ + ); + var $_XHTML_CONTENT_CONSTRUCTS = array('body', 'div'); var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1'); // parser variables, useless if you're not a parser, treat as private var $stack = array(); // parser stack var $inchannel = false; var $initem = false; - var $incontent = false; // if in Atom field + + var $incontent = array(); // non-empty if in namespaced XML content field + var $exclude_top = false; // true when Atom 1.0 type="xhtml" + var $intextinput = false; var $inimage = false; var $current_namespace = false; - /** * Set up XML parser, parse source, and return populated RSS object.. * @@ -121,9 +128,7 @@ class MagpieRSS { xml_set_object( $this->parser, $this ); xml_set_element_handler($this->parser, 'feed_start_element', 'feed_end_element' ); - - $source = preg_replace("/&(?![^ ][^ ]*;)/","&",$source); - + xml_set_character_data_handler( $this->parser, 'feed_cdata' ); $status = xml_parse( $this->parser, $source ); @@ -150,14 +155,17 @@ class MagpieRSS { $attrs = array_change_key_case($attrs, CASE_LOWER); // check for a namespace, and split if found - $ns = false; - if ( strpos( $element, ':' ) ) { - list($ns, $el) = split( ':', $element, 2); - } - if ( $ns and $ns != 'rdf' ) { - $this->current_namespace = $ns; - } - + // Don't munge content tags + if ( empty($this->incontent) ) { + $ns = false; + if ( strpos( $element, ':' ) ) { + list($ns, $el) = split( ':', $element, 2); + } + if ( $ns and $ns != 'rdf' ) { + $this->current_namespace = $ns; + } + } + # if feed type isn't set, then this is first element of feed # identify feed from root element # @@ -172,16 +180,39 @@ class MagpieRSS { } elseif ( $el == 'feed' ) { $this->feed_type = ATOM; - $this->feed_version = $attrs['version']; + if ($attrs['xmlns'] == 'http://www.w3.org/2005/Atom') { // Atom 1.0 + $this->feed_version = '1.0'; + } + else { // Atom 0.3, probably. + $this->feed_version = $attrs['version']; + } $this->inchannel = true; } return; } - if ( $el == 'channel' ) + // if we're inside a namespaced content construct, treat tags as text + if ( !empty($this->incontent) ) { + if ((count($this->incontent) > 1) or !$this->exclude_top) { + // if tags are inlined, then flatten + $attrs_str = join(' ', + array_map('map_attrs', + array_keys($attrs), + array_values($attrs) ) + ); + + if (strlen($attrs_str) > 0) { $attrs_str = ' '.$attrs_str; } + + $this->append_content( "<{$element}{$attrs_str}>" ); + } + array_push($this->incontent, $el); // stack for parsing content XML + } + + elseif ( $el == 'channel' ) { $this->inchannel = true; } + elseif ($el == 'item' or $el == 'entry' ) { $this->initem = true; @@ -189,7 +220,7 @@ class MagpieRSS { $this->current_item['about'] = $attrs['rdf:about']; } } - + // if we're in the default namespace of an RSS feed, // record textinput or image fields elseif ( @@ -208,60 +239,84 @@ class MagpieRSS { $this->inimage = true; } - # handle atom content constructs - elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) - { - // avoid clashing w/ RSS mod_content - if ($el == 'content' ) { - $el = 'atom_content'; - } - - $this->incontent = $el; - - - } - - // if inside an Atom content construct (e.g. content or summary) field treat tags as text - elseif ($this->feed_type == ATOM and $this->incontent ) - { - // if tags are inlined, then flatten - $attrs_str = join(' ', - array_map('map_attrs', - array_keys($attrs), - array_values($attrs) ) ); - - $this->append_content( "<$element $attrs_str>" ); - - array_unshift( $this->stack, $el ); - } - - // Atom support many links per containging element. - // Magpie treats link elements of type rel='alternate' - // as being equivalent to RSS's simple link element. - // - elseif ($this->feed_type == ATOM and $el == 'link' ) - { - if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' ) - { - $link_el = 'link'; - } - else { - $link_el = 'link_' . $attrs['rel']; - } - - $this->append($link_el, $attrs['href']); - } // set stack[0] to current element else { - array_unshift($this->stack, $el); - } + // Atom support many links per containing element. + // Magpie treats link elements of type rel='alternate' + // as being equivalent to RSS's simple link element. + + $atom_link = false; + if ($this->feed_type == ATOM and $el == 'link') { + $atom_link = true; + if (isset($attrs['rel']) and $attrs['rel'] != 'alternate') { + $el = $el . "_" . $attrs['rel']; // pseudo-element names for Atom link elements + } + } + # handle atom content constructs + elseif ( $this->feed_type == ATOM and in_array($el, $this->_ATOM_CONTENT_CONSTRUCTS) ) + { + // avoid clashing w/ RSS mod_content + if ($el == 'content' ) { + $el = 'atom_content'; + } + + // assume that everything accepts namespaced XML + // (that will pass through some non-validating feeds; + // but so what? this isn't a validating parser) + $this->incontent = array(); + array_push($this->incontent, $el); // start a stack + + if ( isset($attrs['type']) and trim(strtolower($attrs['type']))=='xhtml') { + $this->exclude_top = true; + } else { + $this->exclude_top = false; + } + } + # Handle inline XHTML body elements --CWJ + elseif (($this->current_namespace=='xhtml' or + (isset($attrs['xmlns']) and $attrs['xmlns'] == 'http://www.w3.org/1999/xhtml')) + and in_array($el, $this->_XHTML_CONTENT_CONSTRUCTS) ) + { + $this->current_namespace = 'xhtml'; + $this->incontent = array(); + array_push($this->incontent, $el); // start a stack + $this->exclude_top = false; + } + + array_unshift($this->stack, $el); + $elpath = join('_', array_reverse($this->stack)); + + $n = $this->element_count($elpath); + $this->element_count($elpath, $n+1); + + if ($n > 0) { + array_shift($this->stack); + array_unshift($this->stack, $el.'#'.($n+1)); + $elpath = join('_', array_reverse($this->stack)); + } + + // this makes the baby Jesus cry, but we can't do it in normalize() + // because we've made the element name for Atom links unpredictable + // by tacking on the relation to the end. -CWJ + if ($atom_link and isset($attrs['href'])) { + $this->append($elpath, $attrs['href']); + } + + // add attributes + if (count($attrs) > 0) { + $this->append($elpath.'@', join(',', array_keys($attrs))); + foreach ($attrs as $attr => $value) { + $this->append($elpath.'@'.$attr, $value); + } + } + } } function feed_cdata ($p, $text) { - if ($this->feed_type == ATOM and $this->incontent) - { + + if ($this->incontent) { $this->append_content( $text ); } else { @@ -272,14 +327,41 @@ class MagpieRSS { function feed_end_element ($p, $el) { $el = strtolower($el); - - if ( $el == 'item' or $el == 'entry' ) + + if ( $this->incontent ) { + $opener = array_pop($this->incontent); + + // Don't get bamboozled by namespace voodoo + if (strpos($el, ':')) { list($ns, $closer) = split(':', $el); } + else { $ns = false; $closer = $el; } + + // Don't get bamboozled by our munging of , either + if ($this->feed_type == ATOM and $closer == 'content') { + $closer = 'atom_content'; + } + + // balance tags properly + // note: i don't think this is actually neccessary + if ($opener != $closer) { + array_push($this->incontent, $opener); + $this->append_content("<$el />"); + } elseif ($this->incontent) { // are we in the content construct still? + if ((count($this->incontent) > 1) or !$this->exclude_top) { + $this->append_content(""); + } + } else { // shift the opening of the content construct off the normal stack + array_shift( $this->stack ); + } + } + elseif ( $el == 'item' or $el == 'entry' ) { $this->items[] = $this->current_item; $this->current_item = array(); $this->initem = false; + + $this->current_category = 0; } - elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) { $this->intextinput = false; } @@ -287,33 +369,18 @@ class MagpieRSS { { $this->inimage = false; } - elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) - { - $this->incontent = false; - } elseif ($el == 'channel' or $el == 'feed' ) { $this->inchannel = false; } - elseif ($this->feed_type == ATOM and $this->incontent ) { - // balance tags properly - // note: i don't think this is actually neccessary - if ( $this->stack[0] == $el ) - { - $this->append_content(""); - } - else { - $this->append_content("<$el />"); - } - - array_shift( $this->stack ); - } else { - array_shift( $this->stack ); + array_shift( $this->stack ); } + if ( !$this->incontent ) { // Don't munge the namespace after finishing with elements in namespaced content constructs -CWJ $this->current_namespace = false; } + } function concat (&$str1, $str2="") { if (!isset($str1) ) { @@ -322,16 +389,22 @@ class MagpieRSS { $str1 .= $str2; } - - function append_content($text) { - if ( $this->initem ) { - $this->concat( $this->current_item[ $this->incontent ], $text ); + if ( $this->initem ) { + if ($this->current_namespace) { + $this->concat( $this->current_item[$this->current_namespace][ reset($this->incontent) ], $text ); + } else { + $this->concat( $this->current_item[ reset($this->incontent) ], $text ); } - elseif ( $this->inchannel ) { - $this->concat( $this->channel[ $this->incontent ], $text ); + } + elseif ( $this->inchannel ) { + if ($this->current_namespace) { + $this->concat( $this->channel[$this->current_namespace][ reset($this->incontent) ], $text ); + } else { + $this->concat( $this->channel[ reset($this->incontent) ], $text ); } } + } // smart append - field and namespace aware function append($el, $text) { @@ -341,13 +414,13 @@ class MagpieRSS { if ( $this->current_namespace ) { if ( $this->initem ) { - $this->concat( - $this->current_item[ $this->current_namespace ][ $el ], $text); + $this->concat( + $this->current_item[ $this->current_namespace ][ $el ], $text); } elseif ($this->inchannel) { - $this->concat( - $this->channel[ $this->current_namespace][ $el ], $text ); - } + $this->concat( + $this->channel[ $this->current_namespace][ $el ], $text ); + } elseif ($this->intextinput) { $this->concat( $this->textinput[ $this->current_namespace][ $el ], $text ); @@ -359,8 +432,8 @@ class MagpieRSS { } else { if ( $this->initem ) { - $this->concat( - $this->current_item[ $el ], $text); + $this->concat( + $this->current_item[ $el ], $text); } elseif ($this->intextinput) { $this->concat( @@ -371,44 +444,267 @@ class MagpieRSS { $this->image[ $el ], $text ); } elseif ($this->inchannel) { - $this->concat( - $this->channel[ $el ], $text ); + $this->concat( + $this->channel[ $el ], $text ); } } } + + // smart count - field and namespace aware + function element_count ($el, $set = NULL) { + if (!$el) { + return; + } + if ( $this->current_namespace ) + { + if ( $this->initem ) { + if (!is_null($set)) { $this->current_item[ $this->current_namespace ][ $el.'#' ] = $set; } + $ret = (isset($this->current_item[ $this->current_namespace ][ $el.'#' ]) ? + $this->current_item[ $this->current_namespace ][ $el.'#' ] : 0); + } + elseif ($this->inchannel) { + if (!is_null($set)) { $this->channel[ $this->current_namespace ][ $el.'#' ] = $set; } + $ret = (isset($this->channel[ $this->current_namespace][ $el.'#' ]) ? + $this->channel[ $this->current_namespace][ $el.'#' ] : 0); + } + } + else { + if ( $this->initem ) { + if (!is_null($set)) { $this->current_item[ $el.'#' ] = $set; } + $ret = (isset($this->current_item[ $el.'#' ]) ? + $this->current_item[ $el.'#' ] : 0); + } + elseif ($this->inchannel) { + if (!is_null($set)) {$this->channel[ $el.'#' ] = $set; } + $ret = (isset($this->channel[ $el.'#' ]) ? + $this->channel[ $el.'#' ] : 0); + } + } + return $ret; + } + + function normalize_enclosure (&$source, $from, &$dest, $to, $i) { + $id_from = $this->element_id($from, $i); + $id_to = $this->element_id($to, $i); + if (isset($source["{$id_from}@"])) { + foreach (explode(',', $source["{$id_from}@"]) as $attr) { + if ($from=='link_enclosure' and $attr=='href') { // from Atom + $dest["{$id_to}@url"] = $source["{$id_from}@{$attr}"]; + $dest["{$id_to}"] = $source["{$id_from}@{$attr}"]; + } + elseif ($from=='enclosure' and $attr=='url') { // from RSS + $dest["{$id_to}@href"] = $source["{$id_from}@{$attr}"]; + $dest["{$id_to}"] = $source["{$id_from}@{$attr}"]; + } + else { + $dest["{$id_to}@{$attr}"] = $source["{$id_from}@{$attr}"]; + } + } + } + } + + function normalize_atom_person (&$source, $person, &$dest, $to, $i) { + $id = $this->element_id($person, $i); + $id_to = $this->element_id($to, $i); + + // Atom 0.3 <=> Atom 1.0 + if ($this->feed_version >= 1.0) { $used = 'uri'; $norm = 'url'; } + else { $used = 'url'; $norm = 'uri'; } + + if (isset($source["{$id}_{$used}"])) { + $dest["{$id_to}_{$norm}"] = $source["{$id}_{$used}"]; + } + + // Atom to RSS 2.0 and Dublin Core + // RSS 2.0 person strings should be valid e-mail addresses if possible. + if (isset($source["{$id}_email"])) { + $rss_author = $source["{$id}_email"]; + } + if (isset($source["{$id}_name"])) { + $rss_author = $source["{$id}_name"] + . (isset($rss_author) ? " <$rss_author>" : ''); + } + if (isset($rss_author)) { + $source[$id] = $rss_author; // goes to top-level author or contributor + $dest[$id_to] = $rss_author; // goes to dc:creator or dc:contributor + } + } + + // Normalize Atom 1.0 and RSS 2.0 categories to Dublin Core... + function normalize_category (&$source, $from, &$dest, $to, $i) { + $cat_id = $this->element_id($from, $i); + $dc_id = $this->element_id($to, $i); + + // first normalize category elements: Atom 1.0 <=> RSS 2.0 + if ( isset($source["{$cat_id}@term"]) ) { // category identifier + $source[$cat_id] = $source["{$cat_id}@term"]; + } elseif ( $this->feed_type == RSS ) { + $source["{$cat_id}@term"] = $source[$cat_id]; + } + + if ( isset($source["{$cat_id}@scheme"]) ) { // URI to taxonomy + $source["{$cat_id}@domain"] = $source["{$cat_id}@scheme"]; + } elseif ( isset($source["{$cat_id}@domain"]) ) { + $source["{$cat_id}@scheme"] = $source["{$cat_id}@domain"]; + } + + // Now put the identifier into dc:subject + $dest[$dc_id] = $source[$cat_id]; + } + // ... or vice versa + function normalize_dc_subject (&$source, $from, &$dest, $to, $i) { + $dc_id = $this->element_id($from, $i); + $cat_id = $this->element_id($to, $i); + + $dest[$cat_id] = $source[$dc_id]; // RSS 2.0 + $dest["{$cat_id}@term"] = $source[$dc_id]; // Atom 1.0 + } + + // simplify the logic for normalize(). Makes sure that count of elements and + // each of multiple elements is normalized properly. If you need to mess + // with things like attributes or change formats or the like, pass it a + // callback to handle each element. + function normalize_element (&$source, $from, &$dest, $to, $via = NULL) { + if (isset($source[$from]) or isset($source["{$from}#"])) { + if (isset($source["{$from}#"])) { + $n = $source["{$from}#"]; + $dest["{$to}#"] = $source["{$from}#"]; + } + else { $n = 1; } + + for ($i = 1; $i <= $n; $i++) { + if (isset($via)) { // custom callback for ninja attacks + $this->{$via}($source, $from, $dest, $to, $i); + } + else { // just make it the same + $from_id = $this->element_id($from, $i); + $to_id = $this->element_id($to, $i); + $dest[$to_id] = $source[$from_id]; + } + } + } + } + function normalize () { - // if atom populate rss fields + // if atom populate rss fields and normalize 0.3 and 1.0 feeds if ( $this->is_atom() ) { - $this->channel['description'] = $this->channel['tagline']; - for ( $i = 0; $i < count($this->items); $i++) { - $item = $this->items[$i]; - if ( isset($item['summary']) ) - $item['description'] = $item['summary']; - if ( isset($item['atom_content'])) - $item['content']['encoded'] = $item['atom_content']; - - $atom_date = (isset($item['issued']) ) ? $item['issued'] : $item['modified']; - if ( $atom_date ) { - $epoch = @parse_w3cdtf($atom_date); - if ($epoch and $epoch > 0) { - $item['date_timestamp'] = $epoch; + // Atom 1.0 elements <=> Atom 0.3 elements (Thanks, o brilliant wordsmiths of the Atom 1.0 standard!) + if ($this->feed_version < 1.0) { + $this->normalize_element($this->channel, 'tagline', $this->channel, 'subtitle'); + $this->normalize_element($this->channel, 'copyright', $this->channel, 'rights'); + $this->normalize_element($this->channel, 'modified', $this->channel, 'updated'); + } else { + $this->normalize_element($this->channel, 'subtitle', $this->channel, 'tagline'); + $this->normalize_element($this->channel, 'rights', $this->channel, 'copyright'); + $this->normalize_element($this->channel, 'updated', $this->channel, 'modified'); + } + $this->normalize_element($this->channel, 'author', $this->channel['dc'], 'creator', 'normalize_atom_person'); + $this->normalize_element($this->channel, 'contributor', $this->channel['dc'], 'contributor', 'normalize_atom_person'); + + // Atom elements to RSS elements + $this->normalize_element($this->channel, 'subtitle', $this->channel, 'description'); + + if ( isset($this->channel['logo']) ) { + $this->normalize_element($this->channel, 'logo', $this->image, 'url'); + $this->normalize_element($this->channel, 'link', $this->image, 'link'); + $this->normalize_element($this->channel, 'title', $this->image, 'title'); + } + + for ( $i = 0; $i < count($this->items); $i++) { + $item = $this->items[$i]; + + // Atom 1.0 elements <=> Atom 0.3 elements + if ($this->feed_version < 1.0) { + $this->normalize_element($item, 'modified', $item, 'updated'); + $this->normalize_element($item, 'issued', $item, 'published'); + } else { + $this->normalize_element($item, 'updated', $item, 'modified'); + $this->normalize_element($item, 'published', $item, 'issued'); + } + + // "If an atom:entry element does not contain + // atom:author elements, then the atom:author elements + // of the contained atom:source element are considered + // to apply. In an Atom Feed Document, the atom:author + // elements of the containing atom:feed element are + // considered to apply to the entry if there are no + // atom:author elements in the locations described + // above." + if (!isset($item["author#"])) { + if (isset($item["source_author#"])) { // from aggregation source + $source = $item; + $author = "source_author"; + } elseif (isset($this->channel["author#"])) { // from containing feed + $source = $this->channel; + $author = "author"; + } + + $item["author#"] = $source["{$author}#"]; + for ($au = 1; $au <= $item["author#"]; $au++) { + $id_to = $this->element_id('author', $au); + $id_from = $this->element_id($author, $au); + + $item[$id_to] = $source[$id_from]; + foreach (array('name', 'email', 'uri', 'url') as $what) { + if (isset($source["{$id_from}_{$what}"])) { + $item["{$id_to}_{$what}"] = $source["{$id_from}_{$what}"]; + } } } - - $this->items[$i] = $item; - } + } + + // Atom elements to RSS elements + $this->normalize_element($item, 'author', $item['dc'], 'creator', 'normalize_atom_person'); + $this->normalize_element($item, 'contributor', $item['dc'], 'contributor', 'normalize_atom_person'); + $this->normalize_element($item, 'summary', $item, 'description'); + $this->normalize_element($item, 'atom_content', $item['content'], 'encoded'); + $this->normalize_element($item, 'link_enclosure', $item, 'enclosure', 'normalize_enclosure'); + + // Categories + if ( isset($item['category#']) ) { // Atom 1.0 categories to dc:subject and RSS 2.0 categories + $this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category'); + } + elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories + $this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject'); + } + + // Normalized item timestamp + $atom_date = (isset($item['published']) ) ? $item['published'] : $item['updated']; + if ( $atom_date ) { + $epoch = @parse_w3cdtf($atom_date); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $this->items[$i] = $item; + } } elseif ( $this->is_rss() ) { - $this->channel['tagline'] = $this->channel['description']; + // RSS elements to Atom elements + $this->normalize_element($this->channel, 'description', $this->channel, 'tagline'); // Atom 0.3 + $this->normalize_element($this->channel, 'description', $this->channel, 'subtitle'); // Atom 1.0 (yay wordsmithing!) + $this->normalize_element($this->image, 'url', $this->channel, 'logo'); + for ( $i = 0; $i < count($this->items); $i++) { $item = $this->items[$i]; - if ( isset($item['description'])) - $item['summary'] = $item['description']; - if ( isset($item['content']['encoded'] ) ) - $item['atom_content'] = $item['content']['encoded']; - + + // RSS elements to Atom elements + $this->normalize_element($item, 'description', $item, 'summary'); + $this->normalize_element($item['content'], 'encoded', $item, 'atom_content'); + $this->normalize_element($item, 'enclosure', $item, 'link_enclosure', 'normalize_enclosure'); + + // Categories + if ( isset($item['category#']) ) { // RSS 2.0 categories to dc:subject and Atom 1.0 categories + $this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category'); + } + elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories + $this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject'); + } + + // Normalized item timestamp if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) { $epoch = @parse_w3cdtf($item['dc']['date']); if ($epoch and $epoch > 0) { @@ -421,7 +717,7 @@ class MagpieRSS { $item['date_timestamp'] = $epoch; } } - + $this->items[$i] = $item; } } @@ -577,8 +873,12 @@ class MagpieRSS { $this->ERROR = $errormsg; } } - - + + // magic ID function for multiple elemenets. + // can be called as static MagpieRSS::element_id() + function element_id ($el, $counter) { + return $el . (($counter > 1) ? '#'.$counter : ''); + } } // end class RSS function map_attrs($k, $v) { @@ -589,18 +889,18 @@ function map_attrs($k, $v) { // courtesy, Ryan Currie, ryan@digibliss.com if (!function_exists('array_change_key_case')) { - define("CASE_UPPER",1); - define("CASE_LOWER",0); + define("CASE_UPPER",1); + define("CASE_LOWER",0); - function array_change_key_case($array,$case=CASE_LOWER) { - if ($case=CASE_LOWER) $cmd=strtolower; - elseif ($case=CASE_UPPER) $cmd=strtoupper; + function array_change_key_case($array,$case=CASE_LOWER) { + if ($case==CASE_LOWER) $cmd='strtolower'; + elseif ($case==CASE_UPPER) $cmd='strtoupper'; foreach($array as $key=>$value) { $output[$cmd($key)]=$value; } return $output; - } + } }