summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordonncha <donncha@7be80a69-a1ef-0310-a953-fb0f7c49ff36>2007-01-11 15:57:00 +0000
committerdonncha <donncha@7be80a69-a1ef-0310-a953-fb0f7c49ff36>2007-01-11 15:57:00 +0000
commite4426def6d30d301a3f2eb8f7270345d9781edfe (patch)
treee881e449092e7f1617cad3d89e0a7a3878641fb3
parenta35bb9df8c7816a6facf68ff963d5350999befe4 (diff)
downloadwordpress-mu-e4426def6d30d301a3f2eb8f7270345d9781edfe.tar.gz
wordpress-mu-e4426def6d30d301a3f2eb8f7270345d9781edfe.tar.xz
wordpress-mu-e4426def6d30d301a3f2eb8f7270345d9781edfe.zip
WP Merge to rev 4721
git-svn-id: http://svn.automattic.com/wordpress-mu/trunk@840 7be80a69-a1ef-0310-a953-fb0f7c49ff36
-rw-r--r--wp-admin/upload-functions.php2
-rw-r--r--wp-includes/category.php2
-rw-r--r--wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js2
-rw-r--r--wp-includes/js/tinymce/tiny_mce.js2
-rw-r--r--wp-includes/link-template.php12
-rw-r--r--wp-includes/rss.php1610
-rw-r--r--wp-settings.php4
7 files changed, 654 insertions, 980 deletions
diff --git a/wp-admin/upload-functions.php b/wp-admin/upload-functions.php
index ef54c50..40bb97d 100644
--- a/wp-admin/upload-functions.php
+++ b/wp-admin/upload-functions.php
@@ -201,7 +201,7 @@ function wp_upload_tab_upload_action() {
if ( isset($file['error']) )
wp_die($file['error'] . "<br /><a href='" . get_option('siteurl')
- . "/wp-admin/upload.php?style=$style&amp;tab=$from_tab&amp;post_id=$post_id'>'" . __('Back to Image Uploading') . '</a>'
+ . "/wp-admin/upload.php?style=$style&amp;tab=$from_tab&amp;post_id=$post_id'>" . __('Back to Image Uploading') . '</a>'
);
$url = $file['url'];
diff --git a/wp-includes/category.php b/wp-includes/category.php
index 6025a67..7f47161 100644
--- a/wp-includes/category.php
+++ b/wp-includes/category.php
@@ -294,7 +294,7 @@ function _pad_category_counts($type, &$categories) {
}
// Transfer the touched cells
- foreach ( $cat_items as $id => $items )
+ foreach ( (array) $cat_items as $id => $items )
if ( isset($cats[$id]) )
$cats[$id]->{'link' == $type ? 'link_count' : 'category_count'} = count($items);
}
diff --git a/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js b/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js
index c005a9e..304e478 100644
--- a/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js
+++ b/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js
@@ -558,6 +558,8 @@ TinyMCE_Window.prototype.close = function() {
e.parentNode.removeChild(e);
mcWindows.setDocumentLock(false);
+
+ tinyMCE.selectedInstance.getWin().focus();
};
TinyMCE_Window.prototype.onMouseMove = function(e) {
diff --git a/wp-includes/js/tinymce/tiny_mce.js b/wp-includes/js/tinymce/tiny_mce.js
index ecd78a2..aece8d1 100644
--- a/wp-includes/js/tinymce/tiny_mce.js
+++ b/wp-includes/js/tinymce/tiny_mce.js
@@ -2813,7 +2813,7 @@ TinyMCE_Control.prototype = {
if (tinyMCE.isGecko && this.getSel().isCollapsed) {
focusElm = tinyMCE.getParentElement(focusElm, 'A');
- if (focusElm)
+ if (focusElm && this.getRng(0).endOffset > 0 && this.getRng(0).endOffset != focusElm.innerHTML.length)
this.selection.selectNode(focusElm, false);
}
diff --git a/wp-includes/link-template.php b/wp-includes/link-template.php
index ef570f2..20b9132 100644
--- a/wp-includes/link-template.php
+++ b/wp-includes/link-template.php
@@ -296,7 +296,11 @@ function get_previous_post($in_same_cat = false, $excluded_categories = '') {
$posts_in_ex_cats_sql = 'AND ID NOT IN (' . implode($posts_in_ex_cats, ',') . ')';
}
- return @$wpdb->get_row("SELECT ID, post_title FROM $wpdb->posts $join WHERE post_date < '$current_post_date' AND post_type = 'post' AND post_status = 'publish' $posts_in_ex_cats_sql ORDER BY post_date DESC LIMIT 1");
+ $join = apply_filters( 'get_previous_post_join', $join, $in_same_cat, $excluded_categories );
+ $where = apply_filters( 'get_previous_post_where', "WHERE post_date < '$current_post_date' AND post_type = 'post' AND post_status = 'publish' $posts_in_ex_cats_sql", $in_same_cat, $excluded_categories );
+ $sort = apply_filters( 'get_previous_post_sort', 'ORDER BY post_date DESC LIMIT 1' );
+
+ return @$wpdb->get_row("SELECT ID, post_title FROM $wpdb->posts $join $where $sort");
}
function get_next_post($in_same_cat = false, $excluded_categories = '') {
@@ -329,7 +333,11 @@ function get_next_post($in_same_cat = false, $excluded_categories = '') {
$posts_in_ex_cats_sql = 'AND ID NOT IN (' . implode($posts_in_ex_cats, ',') . ')';
}
- return @$wpdb->get_row("SELECT ID,post_title FROM $wpdb->posts $join WHERE post_date > '$current_post_date' AND post_type = 'post' AND post_status = 'publish' $posts_in_ex_cats_sql AND ID != $post->ID ORDER BY post_date ASC LIMIT 1");
+ $join = apply_filters( 'get_next_post_join', $join, $in_same_cat, $excluded_categories );
+ $where = apply_filters( 'get_next_post_where', "WHERE post_date > '$current_post_date' AND post_type = 'post' AND post_status = 'publish' $posts_in_ex_cats_sql AND ID != $post->ID", $in_same_cat, $excluded_categories );
+ $sort = apply_filters( 'get_next_post_sort', 'ORDER BY post_date ASC LIMIT 1' );
+
+ return @$wpdb->get_row("SELECT ID, post_title FROM $wpdb->posts $join $where $sort");
}
diff --git a/wp-includes/rss.php b/wp-includes/rss.php
index e0c1d84..a42e7e0 100644
--- a/wp-includes/rss.php
+++ b/wp-includes/rss.php
@@ -1,1159 +1,788 @@
<?php
-
-/* Much of the code in this file was taken from MagpieRSS
- * by Kellan Elliott-McCrea <kellan@protest.net> which is
- * released under the GPL license.
- *
- * The lastest version of MagpieRSS can be obtained from:
- * http://magpierss.sourceforge.net
+/*
+ * Project: MagpieRSS: a simple RSS integration tool
+ * File: A compiled file for RSS syndication
+ * Author: Kellan Elliott-McCrea <kellan@protest.net>
+ * Version: 0.51
+ * License: GPL
*/
-function fetch_rss($url) {
- $url = apply_filters('fetch_rss_url', $url);
+define('RSS', 'RSS');
+define('ATOM', 'Atom');
+define('MAGPIE_USER_AGENT', 'WordPressMU/' . $wp_version);
- $feeder = new WP_Feeder();
+class MagpieRSS {
+ var $parser;
+ var $current_item = array(); // item currently being parsed
+ var $items = array(); // collection of parsed items
+ var $channel = array(); // hash of channel fields
+ var $textinput = array();
+ var $image = array();
+ var $feed_type;
+ var $feed_version;
- $feed = $feeder->get($url);
+ // parser variables
+ var $stack = array(); // parser stack
+ var $inchannel = false;
+ var $initem = false;
+ var $incontent = false; // if in Atom <content mode="xml"> field
+ var $intextinput = false;
+ var $inimage = false;
+ var $current_field = '';
+ var $current_namespace = false;
- $magpie = $feed->to_magpie();
+ //var $ERROR = "";
- return $magpie;
-}
+ var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
-class WP_Feeder {
- var $url, $http_client, $last_fetch, $wp_object_cache, $cache;
- var $redirects = 0;
- var $max_redirects = 3;
- var $cache_redirects = true;
-
- function WP_Feeder () {
- global $wp_object_cache;
-
- if ( $wp_object_cache->cache_enabled ) {
- $this->wp_object_cache = true;
- } else {
- $this->wp_object_cache = false;
- $this->cache = new RSSCache();
- }
- }
+ function MagpieRSS ($source) {
- function get ($url) {
- $cached = false;
+ # if PHP xml isn't compiled in, die
+ #
+ if ( !function_exists('xml_parser_create') )
+ trigger_error( "Failed to load PHP's XML Extension. http://www.php.net/manual/en/ref.xml.php" );
- $feed = $this->cache_get($url);
+ $parser = @xml_parser_create();
- if ( is_object($feed) ) {
- $cached = true;
- } else {
- unset($feed);
+ if ( !is_resource($parser) )
+ trigger_error( "Failed to create an instance of PHP's XML parser. http://www.php.net/manual/en/ref.xml.php");
- $this->fetch($url);
- $feed = new WP_Feed($this->http_client);
- }
+ $this->parser = $parser;
- // Handle redirects
- if ( $feed->status >= 300 && $feed->status < 400 && $this->redirects < $this->max_redirects ) {
- ++$this->redirects;
+ # pass in parser, and a reference to this object
+ # setup handlers
+ #
+ xml_set_object( $this->parser, $this );
+ xml_set_element_handler($this->parser,
+ 'feed_start_element', 'feed_end_element' );
- if ( $this->cache_redirects && !$cached )
- $this->cache_set($url, $feed);
+ xml_set_character_data_handler( $this->parser, 'feed_cdata' );
- return $this->get($feed->redirect_location);
- }
+ $status = xml_parse( $this->parser, $source );
- if ( !$cached )
- $this->cache_set($url, $feed);
+ if (! $status ) {
+ $errorcode = xml_get_error_code( $this->parser );
+ if ( $errorcode != XML_ERROR_NONE ) {
+ $xml_error = xml_error_string( $errorcode );
+ $error_line = xml_get_current_line_number($this->parser);
+ $error_col = xml_get_current_column_number($this->parser);
+ $errormsg = "$xml_error at line $error_line, column $error_col";
- return $feed;
- }
+ $this->error( $errormsg );
+ }
+ }
- function fetch ($url) {
- $this->last_fetch = $url;
- $parts = parse_url($url);
- $url = ($parts['path'] ? $parts['path'] : '/') . ($parts['query'] ? '?'.$parts['query'] : '');
- $this->http_client = new HttpClient('', 80);
- $this->http_client->handle_redirects = false;
- $this->http_client->host = $parts['host'];
- $this->http_client->port = $parts['port'] ? $parts['port'] : 80;
- $this->http_client->user_agent = 'WordPress ' . $GLOBALS['wp_version'] . ' Feed Client';
- $this->http_client->get($url);
- }
-
- function cache_get ($url) {
- if ( $this->wp_object_cache )
- return unserialize(wp_cache_get($url, 'rss'));
+ xml_parser_free( $this->parser );
- return $this->cache->get($url);
- }
-
- function cache_set ($url, $object) {
- if ( $this->wp_object_cache )
- return wp_cache_set($url, serialize($object), 'rss', 3600);
-
- return $this->cache->set($url, $object);
+ $this->normalize();
}
-}
-class RSSCache {
- var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
- var $MAX_AGE = 43200; // when are files stale, default twelve hours
- var $ERROR = ''; // accumulate error messages
+ function feed_start_element($p, $element, &$attrs) {
+ $el = $element = strtolower($element);
+ $attrs = array_change_key_case($attrs, CASE_LOWER);
- function RSSCache ($base='', $age='') {
- if ( $base ) {
- $this->BASE_CACHE = $base;
+ // check for a namespace, and split if found
+ $ns = false;
+ if ( strpos( $element, ':' ) ) {
+ list($ns, $el) = split( ':', $element, 2);
}
- if ( $age ) {
- $this->MAX_AGE = $age;
+ 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
+ #
+ if (!isset($this->feed_type) ) {
+ if ( $el == 'rdf' ) {
+ $this->feed_type = RSS;
+ $this->feed_version = '1.0';
+ }
+ elseif ( $el == 'rss' ) {
+ $this->feed_type = RSS;
+ $this->feed_version = $attrs['version'];
+ }
+ elseif ( $el == 'feed' ) {
+ $this->feed_type = ATOM;
+ $this->feed_version = $attrs['version'];
+ $this->inchannel = true;
+ }
+ return;
+ }
- function set ($url, $rss) {
- global $wpdb;
- $cache_option = 'rss_' . $this->file_name( $url );
- $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
+ if ( $el == 'channel' )
+ {
+ $this->inchannel = true;
+ }
+ elseif ($el == 'item' or $el == 'entry' )
+ {
+ $this->initem = true;
+ if ( isset($attrs['rdf:about']) ) {
+ $this->current_item['about'] = $attrs['rdf:about'];
+ }
+ }
- if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_option'") )
- add_option($cache_option, '', '', 'no');
- if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_timestamp'") )
- add_option($cache_timestamp, '', '', 'no');
+ // if we're in the default namespace of an RSS feed,
+ // record textinput or image fields
+ elseif (
+ $this->feed_type == RSS and
+ $this->current_namespace == '' and
+ $el == 'textinput' )
+ {
+ $this->intextinput = true;
+ }
- update_option($cache_option, $rss);
- update_option($cache_timestamp, time() );
+ elseif (
+ $this->feed_type == RSS and
+ $this->current_namespace == '' and
+ $el == 'image' )
+ {
+ $this->inimage = true;
+ }
- return $cache_option;
- }
+ # 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;
- function get ($url) {
- $this->ERROR = "";
- $cache_option = 'rss_' . $this->file_name( $url );
- if ( ! get_option( $cache_option ) ) {
- $this->debug(
- "Cache doesn't contain: $url (cache option: $cache_option)"
- );
- return 0;
}
- $rss = get_option( $cache_option );
+ // 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) ) );
- return $rss;
- }
+ $this->append_content( "<$element $attrs_str>" );
- function check_cache ( $url ) {
- $this->ERROR = "";
- $cache_option = $this->file_name( $url );
- $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
+ array_unshift( $this->stack, $el );
+ }
- if ( $mtime = get_option($cache_timestamp) ) {
- // find how long ago the file was added to the cache
- // and whether that is longer then MAX_AGE
- $age = time() - $mtime;
- if ( $this->MAX_AGE > $age ) {
- // object exists and is current
- return 'HIT';
+ // 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 {
- // object exists but is old
- return 'STALE';
+ $link_el = 'link_' . $attrs['rel'];
}
+
+ $this->append($link_el, $attrs['href']);
}
+ // set stack[0] to current element
else {
- // object does not exist
- return 'MISS';
+ array_unshift($this->stack, $el);
}
}
- function serialize ( $rss ) {
- return serialize( $rss );
- }
- function unserialize ( $data ) {
- return unserialize( $data );
- }
- function file_name ($url) {
- return md5( $url );
- }
+ function feed_cdata ($p, $text) {
- function error ($errormsg, $lvl=E_USER_WARNING) {
- // append PHP's error message if track_errors enabled
- if ( isset($php_errormsg) ) {
- $errormsg .= " ($php_errormsg)";
- }
- $this->ERROR = $errormsg;
- if ( MAGPIE_DEBUG ) {
- trigger_error( $errormsg, $lvl);
+ if ($this->feed_type == ATOM and $this->incontent)
+ {
+ $this->append_content( $text );
}
else {
- error_log( $errormsg, 0);
- }
- }
- function debug ($debugmsg, $lvl=E_USER_NOTICE) {
- if ( MAGPIE_DEBUG ) {
- $this->error("MagpieRSS [debug] $debugmsg", $lvl);
+ $current_el = join('_', array_reverse($this->stack));
+ $this->append($current_el, $text);
}
}
-}
-
-class WP_Feed {
- var $status;
- var $raw_xml;
- var $last_updated;
- var $tree;
- var $items;
- var $children;
- var $parser;
- var $feed_type;
- var $feed_version;
- var $stack = array();
+ function feed_end_element ($p, $el) {
+ $el = strtolower($el);
- function WP_Feed ($source)
- {
- # if PHP xml isn't compiled in, die
- #
- if (!function_exists('xml_parser_create')) {
- $this->error( "Failed to load PHP's XML Extension. " .
- "http://www.php.net/manual/en/ref.xml.php",
- E_USER_ERROR );
+ if ( $el == 'item' or $el == 'entry' )
+ {
+ $this->items[] = $this->current_item;
+ $this->current_item = array();
+ $this->initem = false;
}
-
- // Handle overloaded arg (string or HttpClient object)
- if ( is_object($source) ) {
- if ( $source->status >= 200 && $source->status < 300) {
- $this->etag = $source->headers['etag'];
- $this->last_modified = $source->headers['last-modified'];
- $source = $source->content;
- } else {
- $this->scour();
- $this->status = $source->status;
- $this->redirect_location = $source->headers->location;
- $this->bathe();
- return;
- }
+ elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
+ {
+ $this->intextinput = false;
}
-
- list($parser, $source) = $this->create_parser($source, 'UTF-8', null, true);
-
- if (!is_resource($parser)) {
- $this->error( "Failed to create an instance of PHP's XML parser. " .
- "http://www.php.net/manual/en/ref.xml.php",
- E_USER_ERROR );
+ elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' )
+ {
+ $this->inimage = false;
}
-
- $this->parser = $parser;
-
- # pass in parser, and a reference to this object
- # setup handlers
- #
- xml_set_object($this->parser, $this);
- xml_set_element_handler($this->parser, 'start_element', 'end_element');
- xml_set_character_data_handler( $this->parser, 'cdata');
-
- $status = xml_parse( $this->parser, $source );
-
- if (! $status ) {
- $errorcode = xml_get_error_code( $this->parser );
- if ( $errorcode != XML_ERROR_NONE ) {
- $xml_error = xml_error_string( $errorcode );
- $error_line = xml_get_current_line_number($this->parser);
- $error_col = xml_get_current_column_number($this->parser);
- $errormsg = "$xml_error at line $error_line, column $error_col";
-
- $this->error( $errormsg );
- }
+ elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
+ {
+ $this->incontent = false;
}
-
- // SUPER SLOPPY FEED DISCOVERY!! TO-DO: AXE THIS CRAP!!
- if ( !is_object($this->feed) || !method_exists($this->feed, 'to_xml') ) {
- if ( preg_match_all('/<link [^>]*href=([^ >]+)[^>]+>/i', $source, $matches) ) {
- $types = array('rss', 'atom');
- foreach ( $types as $type )
- foreach ( $matches[0] as $key => $link )
- if ( preg_match('/rel=.alternate./', $link) && preg_match("/type=[^ >]*{$type}[^ >]*/", $link) )
- break 2;
- $this->scour();
- $this->redirect_location = 'http://xml.wordpress.com/get/' . trim($matches[1][$key], '\'"');
- $this->status = 301;
- return;
- } else {
- $this->scour();
- $this->status = 404;
- return;
- }
- } else {
- $this->status = 200;
+ 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("</$el>");
+ }
+ else {
+ $this->append_content("<$el />");
+ }
- xml_parser_free( $this->parser );
- unset($this->parser);
-
- $this->bathe();
- }
-
- function to_xml() {
- if ( is_object($this->feed) && method_exists($this->feed, 'to_xml') )
- return $this->feed->to_xml();
-
- return false;
- }
-
- // Called internally by xml_parse(). We create an object and call its start_element method.
- function start_element($p, $element, &$attrs) {
- $el = $element;// = strtolower($element);
- // $attrs = array_change_key_case($attrs, CASE_LOWER);
-
- // If there is an extended class for this element, use it.
- $class = 'element';
-
- $maybe_class = $test_class = strtolower(str_replace(':', '_', $el));
- if ( class_exists($maybe_class) ) {
- for ($classes[] = $test_class; $test_class = get_parent_class ($test_class); $classes[] = $test_class);
- if ( in_array($class, $classes) )
- $class = $maybe_class;
+ array_shift( $this->stack );
+ }
+ else {
+ array_shift( $this->stack );
}
- // Instantiate an object for this element.
- $object = new $class();
-
- // Tell the element to start itself.
- $object->start_element($p, $element, $attrs, $this);
- }
-
- function cdata ($p, $data) {
- $this->stack[0]->cdata($p, $data, $this);
- }
-
- function end_element ($p, $el) {
- $this->stack[0]->end_element($p, $el, $this);
+ $this->current_namespace = false;
}
- function create_parser($source, $out_enc, $in_enc, $detect) {
- if ( substr(phpversion(),0,1) == 5) {
- $parser = $this->php5_create_parser($in_enc, $detect);
- }
- else {
- list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect);
- }
- if ($out_enc) {
- $this->encoding = $out_enc;
- xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+ function concat (&$str1, $str2="") {
+ if (!isset($str1) ) {
+ $str1="";
}
-
- return array($parser, $source);
+ $str1 .= $str2;
}
- function php5_create_parser($in_enc, $detect) {
- // by default php5 does a fine job of detecting input encodings
- if(!$detect && $in_enc) {
- return xml_parser_create($in_enc);
+ function append_content($text) {
+ if ( $this->initem ) {
+ $this->concat( $this->current_item[ $this->incontent ], $text );
}
- else {
- return xml_parser_create('');
+ elseif ( $this->inchannel ) {
+ $this->concat( $this->channel[ $this->incontent ], $text );
}
}
- /**
- * Instaniate an XML parser under PHP4
- *
- * Unfortunately PHP4's support for character encodings
- * and especially XML and character encodings sucks. As
- * long as the documents you parse only contain characters
- * from the ISO-8859-1 character set (a superset of ASCII,
- * and a subset of UTF-8) you're fine. However once you
- * step out of that comfy little world things get mad, bad,
- * and dangerous to know.
- *
- * The following code is based on SJM's work with FoF
- * @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
- *
- */
- function php4_create_parser($source, $in_enc, $detect) {
- if ( !$detect ) {
- return array(xml_parser_create($in_enc), $source);
+ // smart append - field and namespace aware
+ function append($el, $text) {
+ if (!$el) {
+ return;
}
-
- if (!$in_enc) {
- if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
- $in_enc = strtoupper($m[1]);
- $this->source_encoding = $in_enc;
+ if ( $this->current_namespace )
+ {
+ if ( $this->initem ) {
+ $this->concat(
+ $this->current_item[ $this->current_namespace ][ $el ], $text);
}
- else {
- $in_enc = 'UTF-8';
+ elseif ($this->inchannel) {
+ $this->concat(
+ $this->channel[ $this->current_namespace][ $el ], $text );
+ }
+ elseif ($this->intextinput) {
+ $this->concat(
+ $this->textinput[ $this->current_namespace][ $el ], $text );
+ }
+ elseif ($this->inimage) {
+ $this->concat(
+ $this->image[ $this->current_namespace ][ $el ], $text );
}
}
+ else {
+ if ( $this->initem ) {
+ $this->concat(
+ $this->current_item[ $el ], $text);
+ }
+ elseif ($this->intextinput) {
+ $this->concat(
+ $this->textinput[ $el ], $text );
+ }
+ elseif ($this->inimage) {
+ $this->concat(
+ $this->image[ $el ], $text );
+ }
+ elseif ($this->inchannel) {
+ $this->concat(
+ $this->channel[ $el ], $text );
+ }
- if ($this->known_encoding($in_enc)) {
- return array(xml_parser_create($in_enc), $source);
}
+ }
- // the dectected encoding is not one of the simple encodings PHP knows
-
- // attempt to use the iconv extension to
- // cast the XML to a known encoding
- // @see http://php.net/iconv
+ function normalize () {
+ // if atom populate rss fields
+ if ( $this->is_atom() ) {
+ $this->channel['descripton'] = $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'];
- if (function_exists('iconv')) {
- $encoded_source = iconv($in_enc,'UTF-8', $source);
- if ($encoded_source) {
- return array(xml_parser_create('UTF-8'), $encoded_source);
+ $this->items[$i] = $item;
}
}
+ elseif ( $this->is_rss() ) {
+ $this->channel['tagline'] = $this->channel['description'];
+ 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'];
- // iconv didn't work, try mb_convert_encoding
- // @see http://php.net/mbstring
- if(function_exists('mb_convert_encoding')) {
- $encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc );
- if ($encoded_source) {
- return array(xml_parser_create('UTF-8'), $encoded_source);
+ $this->items[$i] = $item;
}
}
+ }
- // else
- $this->error("Feed is in an unsupported character encoding. ($in_enc) " .
- "You may see strange artifacts, and mangled characters.",
- E_USER_NOTICE);
-
- return array(xml_parser_create(), $source);
+ function is_rss () {
+ if ( $this->feed_type == RSS ) {
+ return $this->feed_version;
+ }
+ else {
+ return false;
+ }
}
- function known_encoding($enc) {
- $enc = strtoupper($enc);
- if ( in_array($enc, array('UTF-8', 'US-ASCII', 'ISO-8859-1')) ) {
- return $enc;
+ function is_atom() {
+ if ( $this->feed_type == ATOM ) {
+ return $this->feed_version;
}
else {
return false;
}
}
- function error ($errormsg, $lvl=E_USER_WARNING) {
+ function map_attrs($k, $v) {
+ return "$k=\"$v\"";
+ }
+
+ function error( $errormsg, $lvl = E_USER_WARNING ) {
// append PHP's error message if track_errors enabled
if ( isset($php_errormsg) ) {
$errormsg .= " ($php_errormsg)";
}
if ( MAGPIE_DEBUG ) {
- // trigger_error( $errormsg, $lvl);
- }
- else {
- error_log( $errormsg, 0);
- }
-
- $notices = E_USER_NOTICE|E_NOTICE;
- if ( $lvl&$notices ) {
- $this->WARNING = $errormsg;
+ trigger_error( $errormsg, $lvl);
} else {
- $this->ERROR = $errormsg;
+ error_log( $errormsg, 0);
}
}
- // Remove empty and |^_.*| object vars
- function bathe() {
- foreach ( get_object_vars($this) as $key => $data )
- if ( empty($this->$key) || substr($key, 0, 1) == '_' )
- unset($this->$key);
+}
+require_once( dirname(__FILE__) . '/class-snoopy.php');
+
+function fetch_rss ($url) {
+ // initialize constants
+ init();
+
+ if ( !isset($url) ) {
+ // error("fetch_rss called without a url");
+ return false;
}
- // Remove ALL object vars
- function scour() {
- foreach ( get_object_vars($this) as $key => $data )
- unset($this->$key);
+ // if cache is disabled
+ if ( !MAGPIE_CACHE_ON ) {
+ // fetch file, and parse it
+ $resp = _fetch_remote_file( $url );
+ if ( is_success( $resp->status ) ) {
+ return _response_to_rss( $resp );
+ }
+ else {
+ // error("Failed to fetch $url and cache is off");
+ return false;
+ }
}
-
- function to_magpie() {
- $magpie = new stdClass();
-
- foreach ( $this as $var => $value ) {
- if ( $var == 'feed' ) {
- continue;
- } else {
- $magpie->$var = $this->$var;
- }
+ // else cache is ON
+ else {
+ // Flow
+ // 1. check cache
+ // 2. if there is a hit, make sure its fresh
+ // 3. if cached obj fails freshness check, fetch remote
+ // 4. if remote fails, return stale object, or error
+
+ $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
+
+ if (MAGPIE_DEBUG and $cache->ERROR) {
+ debug($cache->ERROR, E_USER_WARNING);
}
- $magpie->items = array();
- if ( is_object($this->feed) && method_exists($this->feed, 'to_magpie') ) {
- $feed = $this->feed->to_magpie();
+ $cache_status = 0; // response of check_cache
+ $request_headers = array(); // HTTP headers to send with fetch
+ $rss = 0; // parsed RSS object
+ $errormsg = 0; // errors, if any
- if ( is_array($feed) ) {
- foreach ( $this->feed->to_magpie() as $var => $val ) {
- if ( $var == 'items' )
- $magpie->items = $val;
- else
- $magpie->channel["$var"] = $val;
- }
+ if (!$cache->ERROR) {
+ // return cache HIT, MISS, or STALE
+ $cache_status = $cache->check_cache( $url );
+ }
+
+ // if object cached, and cache is fresh, return cached obj
+ if ( $cache_status == 'HIT' ) {
+ $rss = $cache->get( $url );
+ if ( isset($rss) and $rss ) {
+ $rss->from_cache = 1;
+ if ( MAGPIE_DEBUG > 1) {
+ debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
+ }
+ return $rss;
}
}
- return $magpie;
- }
-}
+ // else attempt a conditional get
+ // setup headers
+ if ( $cache_status == 'STALE' ) {
+ $rss = $cache->get( $url );
+ if ( $rss->etag and $rss->last_modified ) {
+ $request_headers['If-None-Match'] = $rss->etag;
+ $request_headers['If-Last-Modified'] = $rss->last_modified;
+ }
+ }
-class element {
- function element() {
- }
+ $resp = _fetch_remote_file( $url, $request_headers );
- function start_element($p, $el, $attr, &$mag) {
- $this->name = $el;
- $this->attributes = $attr;
+ if (isset($resp) and $resp) {
+ if ($resp->status == '304' ) {
+ // we have the most current copy
+ if ( MAGPIE_DEBUG > 1) {
+ debug("Got 304 for $url");
+ }
+ // reset cache on 304 (at minutillo insistent prodding)
+ $cache->set($url, $rss);
+ return $rss;
+ }
+ elseif ( is_success( $resp->status ) ) {
+ $rss = _response_to_rss( $resp );
+ if ( $rss ) {
+ if (MAGPIE_DEBUG > 1) {
+ debug("Fetch successful");
+ }
+ // add object to cache
+ $cache->set( $url, $rss );
+ return $rss;
+ }
+ }
+ else {
+ $errormsg = "Failed to fetch $url. ";
+ if ( $resp->error ) {
+ # compensate for Snoopy's annoying habbit to tacking
+ # on '\n'
+ $http_error = substr($resp->error, 0, -2);
+ $errormsg .= "(HTTP Error: $http_error)";
+ }
+ else {
+ $errormsg .= "(HTTP Response: " . $resp->response_code .')';
+ }
+ }
+ }
+ else {
+ $errormsg = "Unable to retrieve RSS file for unknown reasons.";
+ }
- array_unshift($mag->stack, $this);
- }
- function cdata($p, $data, &$mag) {
- if ( empty($this->children) )
- $this->appendText($data);
- }
+ // else fetch failed
- function end_element($p, $el, &$mag) {
- array_shift($mag->stack);
+ // attempt to return cached object
+ if ($rss) {
+ if ( MAGPIE_DEBUG ) {
+ debug("Returning STALE object for $url");
+ }
+ return $rss;
+ }
- $this->bathe();
+ // else we totally failed
+ // error( $errormsg );
- if ( is_object($mag->stack[0]) )
- $mag->stack[0]->appendChild($this);
- }
+ return false;
- function wrap_cdata() {
- if ( strpos($this->innerText, '<') ) {
- $spacer = (substr($this->innerText, -1) == ']') ? ' ' : '';
- $this->innerText = str_replace(']]>', ']]&gt;', $this->innerText);
- $this->innerText = '<![CDATA[' . $this->innerText . $spacer . ']]>';
- }
- }
+ } // end if ( !MAGPIE_CACHE_ON ) {
+} // end fetch_rss()
- function appendText($text) {
- $this->innerText .= $text;
+function _fetch_remote_file ($url, $headers = "" ) {
+ // Snoopy is an HTTP client in PHP
+ $client = new Snoopy();
+ $client->agent = MAGPIE_USER_AGENT;
+ $client->read_timeout = MAGPIE_FETCH_TIME_OUT;
+ $client->use_gzip = MAGPIE_USE_GZIP;
+ if (is_array($headers) ) {
+ $client->rawheaders = $headers;
}
- function appendChild($object) {
- $this->children[] = & $object;
- }
+ @$client->fetch($url);
+ return $client;
- // Add self to array
- function to_array(&$array) {
- $self = get_object_vars($this);
+}
- unset($self['children']);
+function _response_to_rss ($resp) {
+ $rss = new MagpieRSS( $resp->results );
- foreach ( $this->children as $child )
- $child->to_array($self);
+ // if RSS parsed successfully
+ if ( $rss and !$rss->ERROR) {
- $array[$this->name] = $self;
- }
+ // find Etag, and Last-Modified
+ foreach($resp->headers as $h) {
+ // 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1"
+ if (strpos($h, ": ")) {
+ list($field, $val) = explode(": ", $h, 2);
+ }
+ else {
+ $field = $h;
+ $val = "";
+ }
- // Return self as XML
- function to_xml($indent = "\t", $generation = 0) {
- $self = "<$this->name";
- $self .= $this->attributes ? ' '.string_attributes($this->attributes) : '';
- if ( empty($this->innerText) && empty($this->children) )
- $self .= " />\n";
- else {
- $self .= ">";
- if ( $this->children ) {
- $self .= "\n";
- foreach ( $this->children as $child )
- $self .= $child->to_xml($indent, $generation + 1);
- $self .= $indent ? $this->indent('', $indent, $generation) : '';
- } else {
- $self .= $this->innerText;
+ if ( $field == 'ETag' ) {
+ $rss->etag = $val;
+ }
+
+ if ( $field == 'Last-Modified' ) {
+ $rss->last_modified = $val;
}
- $self .= "</$this->name>\n";
}
- return $indent ? $this->indent($self, $indent, $generation) : $self;
- }
- function indent($string, $indent, $generation) {
- for ( $i = ''; strlen($i) < $generation; $i .= $indent ) ;
- return $i . $string;
- }
+ return $rss;
+ } // else construct error message
+ else {
+ $errormsg = "Failed to parse RSS file.";
+
+ if ($rss) {
+ $errormsg .= " (" . $rss->ERROR . ")";
+ }
+ // error($errormsg);
- /**
- * Gets the innerText of the first matching element in the vars
- * @param string Provide any number of strings to try
- * @return mixed
- */
- function getChildText() {
- foreach ( func_get_args() as $name )
- foreach ( $this->children as $element )
- if ( $element->name == $name )
- return $element->innerText;
return false;
+ } // end if ($rss and !$rss->error)
+}
+
+/*=======================================================================*\
+ Function: init
+ Purpose: setup constants with default values
+ check for user overrides
+\*=======================================================================*/
+function init () {
+ if ( defined('MAGPIE_INITALIZED') ) {
+ return;
+ }
+ else {
+ define('MAGPIE_INITALIZED', 1);
}
- /**
- * Gets a ref to the first matching element
- * @param string Provide any number of strings to try
- * @return object
- */
- function &getChildElement() {
- foreach ( func_get_args() as $name )
- foreach ( $this->children as $key => $element )
- if ( $element->name == $name )
- return $this->children[$key];
- return false;
+ if ( !defined('MAGPIE_CACHE_ON') ) {
+ define('MAGPIE_CACHE_ON', 1);
+ }
+
+ if ( !defined('MAGPIE_CACHE_DIR') ) {
+ define('MAGPIE_CACHE_DIR', './cache');
}
- function getAttribute($name) {
- if ( is_array($this->attributes) )
- foreach ( $this->attributes as $attr => $value )
- if ( $attr == $name )
- return $value;
- return null;
+ if ( !defined('MAGPIE_CACHE_AGE') ) {
+ define('MAGPIE_CACHE_AGE', 60*60); // one hour
}
- function bathe() {
- foreach ( get_object_vars($this) as $var => $value )
- if ( empty($this->$var) )
- unset($this->$var);
+ if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
+ define('MAGPIE_CACHE_FRESH_ONLY', 0);
}
- function to_magpie() {
- if ( strlen(trim($this->innerText)) > 0 )
- return $this->innerText;
+ if ( !defined('MAGPIE_DEBUG') ) {
+ define('MAGPIE_DEBUG', 0);
+ }
- if ( is_array($this->attributes) )
- $e = $this->attributes;
+ if ( !defined('MAGPIE_USER_AGENT') ) {
+ $ua = 'WordPress/' . $wp_version;
- if ( is_array($this->children) && count($this->children) > 0 )
- foreach ( $this->children as $k => $c )
- $e[$k] = $this->children[$k]->to_magpie();
+ if ( MAGPIE_CACHE_ON ) {
+ $ua = $ua . ')';
+ }
+ else {
+ $ua = $ua . '; No cache)';
+ }
- return $e;
+ define('MAGPIE_USER_AGENT', $ua);
}
-}
-// Base Atom class
-class feed extends element {
- function end_element($p, $el, &$mag) {
- $mag->feed = $this;
- $mag->is_feed = true;
- $mag->last_modified = $this->last_modified();
- $mag->stack = array();
- }
- function last_modified() {
- $time = parse_w3cdtf($this->getChildText('modified'));
- return gmdate('D, d M Y H:i:s T', $time);
+ if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
+ define('MAGPIE_FETCH_TIME_OUT', 2); // 2 second timeout
}
- function to_magpie() {
- foreach ( $this->children as $k => $c ) {
- if ( $this->children[$k]->name == 'entry' )
- $magpie['items'][] = $this->children[$k]->to_magpie();
- else
- $magpie[$this->children[$k]->name] = $this->children[$k]->innerText;
- }
- return $magpie;
+ // use gzip encoding to fetch rss files if supported?
+ if ( !defined('MAGPIE_USE_GZIP') ) {
+ define('MAGPIE_USE_GZIP', true);
}
}
-// RSS base class
-class rss extends feed {
- function last_modified() {
- $channel =& $this->getChildElement('channel');
- $date = $channel->getChildText('pubDate', 'lastBuildDate');
- return gmdate('D, d M Y H:i:s T', strtotime($date));
- }
- function to_magpie() {
- return $this->children[0]->to_magpie();
- }
+function is_info ($sc) {
+ return $sc >= 100 && $sc < 200;
}
-class rdf_rdf extends feed {
- function to_magpie() {
- $magpie = array();
- foreach ( $this->children as $k => $child ) {
- if ( $this->children[$k]->name == 'item' )
- $magpie['items'][] = $this->children[$k]->to_magpie();
- elseif ( method_exists($this->children[$k], 'to_magpie') )
- $magpie[$this->children[$k]->name] = $this->children[$k]->to_magpie();
- else
- $magpie[$this->children[$k]->name] = $this->children[$k]->innerText;
- }
- if ( is_array($magpie['channel']) )
- $magpie = array_merge($magpie['channel'], $magpie);
- return $magpie;
- }
+function is_success ($sc) {
+ return $sc >= 200 && $sc < 300;
}
-class channel extends element {
- function to_magpie() {
- foreach ( $this->children as $k => $c ) {
- if ( $this->children[$k]->name == 'item' )
- $magpie['items'][] = $this->children[$k]->to_magpie();
- else
- $magpie[$this->children[$k]->name] = $this->children[$k]->innerText;
- }
- return $magpie;
- }
+function is_redirect ($sc) {
+ return $sc >= 300 && $sc < 400;
}
-// Atom article class
-class entry extends element {
- function to_magpie() {
- foreach ( $this->children as $k => $v ) {
- if ( is_object($this->children[$k]) )
- $value = $this->children[$k]->to_magpie();
- else
- $value = $this->children[$k]->innerText;
-
- $name = $this->children[$k]->name;
-
- $norms = array(
- 'dc:subject' => 'categories',
- 'summary' => 'description',
- );
- $name = str_replace(array_keys($norms), array_values($norms), $name);
-
- switch ( $name ) {
- // The ones that needs to be dereferenced
- case 'author':
- $magpie[$name] = $value[0];
- break;
-
- // The ones that can be multiple
- case 'categories':
- $magpie[$name][] = $value;
- break;
-
- default:
- $magpie[$name] = $value;
- }
+function is_error ($sc) {
+ return $sc >= 400 && $sc < 600;
+}
+
+function is_client_error ($sc) {
+ return $sc >= 400 && $sc < 500;
+}
+
+function is_server_error ($sc) {
+ return $sc >= 500 && $sc < 600;
+}
+
+class RSSCache {
+ var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
+ var $MAX_AGE = 43200; // when are files stale, default twelve hours
+ var $ERROR = ''; // accumulate error messages
+
+ function RSSCache ($base='', $age='') {
+ if ( $base ) {
+ $this->BASE_CACHE = $base;
+ }
+ if ( $age ) {
+ $this->MAX_AGE = $age;
}
- return $magpie;
+
}
- function to_array(&$array) {
- $self = get_object_vars($this);
+/*=======================================================================*\
+ Function: set
+ Purpose: add an item to the cache, keyed on url
+ Input: url from wich the rss file was fetched
+ Output: true on sucess
+\*=======================================================================*/
+ function set ($url, $rss) {
+ global $wpdb;
+ $cache_option = 'rss_' . $this->file_name( $url );
+ $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
- unset($self['children']);
+ if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_option'") )
+ add_option($cache_option, '', '', 'no');
+ if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_timestamp'") )
+ add_option($cache_timestamp, '', '', 'no');
- foreach ( $this->children as $child )
- $child->to_array($self);
+ update_option($cache_option, $rss);
+ update_option($cache_timestamp, time() );
- $array['items'][] = $self;
+ return $cache_option;
}
-}
-// RSS article class
-class item extends entry {
- function to_magpie() {
- foreach ( $this->children as $k => $v ) {
- if ( is_object($this->children[$k]) )
- $value = $this->children[$k]->to_magpie();
- else
- $value = $this->children[$k]->innerText;
-
- $name = $this->children[$k]->name;
-
- $norms = array(
- 'category' => 'categories',
- 'content:encoded' => 'content',
- 'dc:creator' => 'author',
- 'wfw:commentRss' => 'comments',
- 'wfw:commentRSS' => 'comments',
- 'pubDate' => 'pubdate',
- );
- $name = str_replace(array_keys($norms), array_values($norms), $name);
-
- switch ( $name ) {
- // The ones that needs to be dereferenced
- case 'taxo:topics':
- $magpie[$name] = $value[0];
- break;
-
- // The ones that can be multiple
- case 'categories':
- $magpie[$name][] = $value;
- break;
-
- default:
- $magpie[$name] = $value;
- }
+/*=======================================================================*\
+ Function: get
+ Purpose: fetch an item from the cache
+ Input: url from wich the rss file was fetched
+ Output: cached object on HIT, false on MISS
+\*=======================================================================*/
+ function get ($url) {
+ $this->ERROR = "";
+ $cache_option = 'rss_' . $this->file_name( $url );
+
+ if ( ! get_option( $cache_option ) ) {
+ $this->debug(
+ "Cache doesn't contain: $url (cache option: $cache_option)"
+ );
+ return 0;
}
- return $magpie;
- }
-}
-class category extends element {
- function to_array(&$array) {
- $self = get_object_vars($this);
+ $rss = get_option( $cache_option );
- unset($self['children']);
+ return $rss;
+ }
- foreach ( $this->children as $child )
- $child->to_array($self);
+/*=======================================================================*\
+ Function: check_cache
+ Purpose: check a url for membership in the cache
+ and whether the object is older then MAX_AGE (ie. STALE)
+ Input: url from wich the rss file was fetched
+ Output: cached object on HIT, false on MISS
+\*=======================================================================*/
+ function check_cache ( $url ) {
+ $this->ERROR = "";
+ $cache_option = $this->file_name( $url );
+ $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
- $array['categories'][] = $self;
+ if ( $mtime = get_option($cache_timestamp) ) {
+ // find how long ago the file was added to the cache
+ // and whether that is longer then MAX_AGE
+ $age = time() - $mtime;
+ if ( $this->MAX_AGE > $age ) {
+ // object exists and is current
+ return 'HIT';
+ }
+ else {
+ // object exists but is old
+ return 'STALE';
+ }
+ }
+ else {
+ // object does not exist
+ return 'MISS';
+ }
}
-}
-
-class link extends element {
- function end_element($p, $el, &$mag) {
- if ( $href = $this->getAttribute('href') )
- $this->innerText = $href;
- parent::end_element($p, $el, $mag);
+/*=======================================================================*\
+ Function: serialize
+\*=======================================================================*/
+ function serialize ( $rss ) {
+ return serialize( $rss );
}
-}
+/*=======================================================================*\
+ Function: unserialize
+\*=======================================================================*/
+ function unserialize ( $data ) {
+ return unserialize( $data );
+ }
-/* Version 0.9, 6th April 2003 - Simon Willison ( http://simon.incutio.com/ )
- Manual: http://scripts.incutio.com/httpclient/
-*/
-
-if ( !class_exists('HttpClient') ) :
-class HttpClient {
- // Request vars
- var $host;
- var $port;
- var $path;
- var $method;
- var $postdata = '';
- var $cookies = array();
- var $referer;
- var $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
- var $accept_encoding = 'gzip';
- var $accept_language = 'en-us';
- var $user_agent = 'Incutio HttpClient v0.9';
- // Options
- var $timeout = 20;
- var $use_gzip = true;
- var $no_cache = false;
- var $persist_cookies = true; // If true, received cookies are placed in the $this->cookies array ready for the next request
- // Note: This currently ignores the cookie path (and time) completely. Time is not important,
- // but path could possibly lead to security problems.
- var $persist_referers = true; // For each request, sends path of last request as referer
- var $debug = false;
- var $handle_redirects = true; // Auaomtically redirect if Location or URI header is found
- var $max_redirects = 5;
- var $headers_only = false; // If true, stops receiving once headers have been read.
- // Basic authorization variables
- var $username;
- var $password;
- // Response vars
- var $status;
- var $headers = array();
- var $content = '';
- var $errormsg;
- // Tracker variables
- var $redirect_count = 0;
- var $cookie_host = '';
- function HttpClient($host, $port=80) {
- $this->host = $host;
- $this->port = $port;
- }
- function get($path, $data = false) {
- $this->path = $path;
- $this->method = 'GET';
- if ($data) {
- $this->path .= '?'.$this->buildQueryString($data);
- }
- return $this->doRequest();
- }
- function post($path, $data) {
- $this->path = $path;
- $this->method = 'POST';
- $this->postdata = $this->buildQueryString($data);
- return $this->doRequest();
- }
- function buildQueryString($data) {
- $querystring = '';
- if (is_array($data)) {
- // Change data in to postable data
- foreach ($data as $key => $val) {
- if (is_array($val)) {
- foreach ($val as $val2) {
- $querystring .= urlencode($key).'='.urlencode($val2).'&';
- }
- } else {
- $querystring .= urlencode($key).'='.urlencode($val).'&';
- }
- }
- $querystring = substr($querystring, 0, -1); // Eliminate unnecessary &
- } else {
- $querystring = $data;
- }
- return $querystring;
- }
- function doRequest() {
- // Performs the actual HTTP request, returning true or false depending on outcome
- if (!$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout)) {
- // Set error message
- switch($errno) {
- case -3:
- $this->errormsg = 'Socket creation failed (-3)';
- case -4:
- $this->errormsg = 'DNS lookup failure (-4)';
- case -5:
- $this->errormsg = 'Connection refused or timed out (-5)';
- default:
- $this->errormsg = 'Connection failed ('.$errno.')';
- $this->errormsg .= ' '.$errstr;
- $this->debug($this->errormsg);
- }
- return false;
- }
- socket_set_timeout($fp, $this->timeout);
- $request = $this->buildRequest();
- $this->debug('Request', $request);
- fwrite($fp, $request);
- // Reset all the variables that should not persist between requests
- $this->headers = array();
- $this->content = '';
- $this->errormsg = '';
- // Set a couple of flags
- $inHeaders = true;
- // Now start reading back the response
- $line = fgets($fp, 4096);
- // Deal with first line of returned data
- if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
- $this->errormsg = "Status code line invalid: ".htmlentities($line);
- $this->debug($this->errormsg);
- return false;
- }
- $http_version = $m[1]; // not used
- $this->status = $m[2];
- $status_string = $m[3]; // not used
- $this->debug(trim($line));
- while (!feof($fp)) {
- $line = fgets($fp, 4096);
- if ($inHeaders) {
- if (trim($line) == '') {
- $inHeaders = false;
- $this->debug('Received Headers', $this->headers);
- if ($this->headers_only) {
- break; // Skip the rest of the input
- }
- continue;
- }
- if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) {
- // Skip to the next header
- continue;
- }
- $key = strtolower(trim($m[1]));
- $val = trim($m[2]);
- // Deal with the possibility of multiple headers of same name
- if (isset($this->headers[$key])) {
- if (is_array($this->headers[$key])) {
- $this->headers[$key][] = $val;
- } else {
- $this->headers[$key] = array($this->headers[$key], $val);
- }
- } else {
- $this->headers[$key] = $val;
- }
- continue;
- }
- // We're not in the headers, so append the line to the contents
- $this->content .= $line;
- }
- fclose($fp);
- // If data is compressed, uncompress it
- if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] == 'gzip') {
- $this->debug('Content is gzip encoded, unzipping it');
- $this->content = substr($this->content, 10); // See http://www.php.net/manual/en/function.gzencode.php
- $this->content = gzinflate($this->content);
- }
- // If $persist_cookies, deal with any cookies
- if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
- $cookies = $this->headers['set-cookie'];
- if (!is_array($cookies)) {
- $cookies = array($cookies);
- }
- foreach ($cookies as $cookie) {
- if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) {
- $this->cookies[$m[1]] = $m[2];
- }
- }
- // Record domain of cookies for security reasons
- $this->cookie_host = $this->host;
- }
- // If $persist_referers, set the referer ready for the next request
- if ($this->persist_referers) {
- $this->debug('Persisting referer: '.$this->getRequestURL());
- $this->referer = $this->getRequestURL();
- }
- // Finally, if handle_redirects and a redirect is sent, do that
- if ($this->handle_redirects) {
- if (++$this->redirect_count >= $this->max_redirects) {
- $this->errormsg = 'Number of redirects exceeded maximum ('.$this->max_redirects.')';
- $this->debug($this->errormsg);
- $this->redirect_count = 0;
- return false;
- }
- $location = isset($this->headers['location']) ? $this->headers['location'] : '';
- $uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
- if ($location || $uri) {
- $url = parse_url($location.$uri);
- // This will FAIL if redirect is to a different site
- return $this->get($url['path']);
- }
- }
- return true;
- }
- function buildRequest() {
- $headers = array();
- $headers[] = "{$this->method} {$this->path} HTTP/1.0"; // Using 1.1 leads to all manner of problems, such as "chunked" encoding
- $headers[] = "Host: {$this->host}";
- $headers[] = "User-Agent: {$this->user_agent}";
- $headers[] = "Accept: {$this->accept}";
- if ($this->use_gzip) {
- $headers[] = "Accept-encoding: {$this->accept_encoding}";
- }
- $headers[] = "Accept-language: {$this->accept_language}";
- if ($this->referer) {
- $headers[] = "Referer: {$this->referer}";
- }
- if ($this->no_cache) {
- $headers[] = "Pragma: no-cache";
- $headers[] = "Cache-control: no-cache";
- }
- // Cookies
- if ($this->cookies) {
- $cookie = 'Cookie: ';
- foreach ($this->cookies as $key => $value) {
- $cookie .= "$key=$value; ";
- }
- $headers[] = $cookie;
- }
- // Basic authentication
- if ($this->username && $this->password) {
- $headers[] = 'Authorization: BASIC '.base64_encode($this->username.':'.$this->password);
- }
- // If this is a POST, set the content type and length
- if ($this->postdata) {
- $headers[] = 'Content-Type: application/x-www-form-urlencoded';
- $headers[] = 'Content-Length: '.strlen($this->postdata);
- }
- $request = implode("\r\n", $headers)."\r\n\r\n".$this->postdata;
- return $request;
- }
- function getStatus() {
- return $this->status;
- }
- function getContent() {
- return $this->content;
- }
- function getHeaders() {
- return $this->headers;
- }
- function getHeader($header) {
- $header = strtolower($header);
- if (isset($this->headers[$header])) {
- return $this->headers[$header];
- } else {
- return false;
- }
- }
- function getError() {
- return $this->errormsg;
- }
- function getCookies() {
- return $this->cookies;
- }
- function getRequestURL() {
- $url = 'http://'.$this->host;
- if ($this->port != 80) {
- $url .= ':'.$this->port;
- }
- $url .= $this->path;
- return $url;
- }
- // Setter methods
- function setUserAgent($string) {
- $this->user_agent = $string;
- }
- function setAuthorization($username, $password) {
- $this->username = $username;
- $this->password = $password;
- }
- function setCookies($array) {
- $this->cookies = $array;
- }
- // Option setting methods
- function useGzip($boolean) {
- $this->use_gzip = $boolean;
- }
- function setPersistCookies($boolean) {
- $this->persist_cookies = $boolean;
- }
- function setPersistReferers($boolean) {
- $this->persist_referers = $boolean;
- }
- function setHandleRedirects($boolean) {
- $this->handle_redirects = $boolean;
- }
- function setMaxRedirects($num) {
- $this->max_redirects = $num;
- }
- function setHeadersOnly($boolean) {
- $this->headers_only = $boolean;
- }
- function setDebug($boolean) {
- $this->debug = $boolean;
- }
- // "Quick" static methods
- function quickGet($url) {
- $bits = parse_url($url);
- $host = $bits['host'];
- $port = isset($bits['port']) ? $bits['port'] : 80;
- $path = isset($bits['path']) ? $bits['path'] : '/';
- if (isset($bits['query'])) {
- $path .= '?'.$bits['query'];
- }
- $client = new HttpClient($host, $port);
- if (!$client->get($path)) {
- return false;
- } else {
- return $client->getContent();
- }
- }
- function quickPost($url, $data) {
- $bits = parse_url($url);
- $host = $bits['host'];
- $port = isset($bits['port']) ? $bits['port'] : 80;
- $path = isset($bits['path']) ? $bits['path'] : '/';
- $client = new HttpClient($host, $port);
- if (!$client->post($path, $data)) {
- return false;
- } else {
- return $client->getContent();
- }
- }
- function debug($msg, $object = false) {
- if ($this->debug) {
- print '<div style="border: 1px solid red; padding: 0.5em; margin: 0.5em;"><strong>HttpClient Debug:</strong> '.$msg;
- if ($object) {
- ob_start();
- print_r($object);
- $content = htmlentities(ob_get_contents());
- ob_end_clean();
- print '<pre>'.$content.'</pre>';
- }
- print '</div>';
- }
- }
-}
-endif;
+/*=======================================================================*\
+ Function: file_name
+ Purpose: map url to location in cache
+ Input: url from wich the rss file was fetched
+ Output: a file name
+\*=======================================================================*/
+ function file_name ($url) {
+ return md5( $url );
+ }
-function string_attributes($attrs) {
- return join(' ', array_map(create_function('$k,$v', 'return "$k=\"".htmlspecialchars($v)."\"";'), array_keys($attrs), array_values($attrs) ) );
+/*=======================================================================*\
+ Function: error
+ Purpose: register error
+\*=======================================================================*/
+ function error ($errormsg, $lvl=E_USER_WARNING) {
+ // append PHP's error message if track_errors enabled
+ if ( isset($php_errormsg) ) {
+ $errormsg .= " ($php_errormsg)";
+ }
+ $this->ERROR = $errormsg;
+ if ( MAGPIE_DEBUG ) {
+ trigger_error( $errormsg, $lvl);
+ }
+ else {
+ error_log( $errormsg, 0);
+ }
+ }
+ function debug ($debugmsg, $lvl=E_USER_NOTICE) {
+ if ( MAGPIE_DEBUG ) {
+ $this->error("MagpieRSS [debug] $debugmsg", $lvl);
+ }
+ }
}
-if ( !function_exists('parse_w3cdtf') ) :
function parse_w3cdtf ( $date_str ) {
+
# regex to match wc3dtf
$pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/";
if ( preg_match( $pat, $date_str, $match ) ) {
list( $year, $month, $day, $hours, $minutes, $seconds) =
- array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[7]);
+ array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
# calc epoch for current date assuming GMT
$epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
@@ -1164,7 +793,7 @@ function parse_w3cdtf ( $date_str ) {
}
else {
list( $tz_mod, $tz_hour, $tz_min ) =
- array( $match[8], $match[9], $match[10]);
+ array( $match[8], $match[9], $match[10]);
# zero out the variables
if ( ! $tz_hour ) { $tz_hour = 0; }
@@ -1186,7 +815,40 @@ function parse_w3cdtf ( $date_str ) {
else {
return -1;
}
+ }
+function wp_rss ($url, $num_items) {
+ //ini_set("display_errors", false); uncomment to suppress php errors thrown if the feed is not returned.
+ $rss = fetch_rss($url);
+ if ( $rss ) {
+ echo "<ul>";
+ $rss->items = array_slice($rss->items, 0, $num_items);
+ foreach ($rss->items as $item ) {
+ echo "<li>\n";
+ echo "<a href='$item[link]' title='$item[description]'>";
+ echo htmlentities($item['title']);
+ echo "</a><br />\n";
+ echo "</li>\n";
+ }
+ echo "</ul>";
+ }
+ else {
+ echo "an error has occured the feed is probably down, try again later.";
+ }
}
-endif;
+function get_rss ($url, $num_items = 5) { // Like get posts, but for RSS
+ $rss = fetch_rss($url);
+ if ( $rss ) {
+ $rss->items = array_slice($rss->items, 0, $num_items);
+ foreach ($rss->items as $item ) {
+ echo "<li>\n";
+ echo "<a href='$item[link]' title='$item[description]'>";
+ echo htmlentities($item['title']);
+ echo "</a><br />\n";
+ echo "</li>\n";
+ }
+ } else {
+ return false;
+ }
+}
?>
diff --git a/wp-settings.php b/wp-settings.php
index 482a5fa..f39ec9a 100644
--- a/wp-settings.php
+++ b/wp-settings.php
@@ -15,8 +15,10 @@ function wp_unregister_GLOBALS() {
$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
foreach ( $input as $k => $v )
- if ( !in_array($k, $noUnset) && isset($GLOBALS[$k]) )
+ if ( !in_array($k, $noUnset) && isset($GLOBALS[$k]) ) {
+ $GLOBALS[$k] = NULL;
unset($GLOBALS[$k]);
+ }
}
wp_unregister_GLOBALS();