diff --git a/htdocs/includes/boxes/box_external_rss.php b/htdocs/includes/boxes/box_external_rss.php index 46bdf76faa491173c3d1e5f956628fa555946b1c..b39a512f2132a4dea4fffb506649659010d11ce4 100644 --- a/htdocs/includes/boxes/box_external_rss.php +++ b/htdocs/includes/boxes/box_external_rss.php @@ -29,7 +29,7 @@ \version $Revision$ */ -include_once(DOL_DOCUMENT_ROOT."/includes/magpierss/rss_fetch.inc"); +include_once(MAGPIERSS_PATH."rss_fetch.inc"); include_once(DOL_DOCUMENT_ROOT."/includes/boxes/modules_boxes.php"); diff --git a/htdocs/includes/magpierss/README b/htdocs/includes/magpierss/README new file mode 100644 index 0000000000000000000000000000000000000000..6af7edb07c858d144449675c762351acf68b4d8f --- /dev/null +++ b/htdocs/includes/magpierss/README @@ -0,0 +1,48 @@ +NAME + + MagpieRSS - a simple RSS integration tool + +SYNOPSIS + + require_once(rss_fetch.inc); + $url = $_GET['url']; + $rss = fetch_rss( $url ); + + echo "Channel Title: " . $rss->channel['title'] . "<p>"; + echo "<ul>"; + foreach ($rss->items as $item) { + $href = $item['link']; + $title = $item['title']; + echo "<li><a href=$href>$title</a></li>"; + } + echo "</ul>"; + +DESCRIPTION + + MapieRSS is an XML-based RSS parser in PHP. It attempts to be "PHP-like", + and simple to use. + + Some features include: + + * supports RSS 0.9 - 1.0, with limited RSS 2.0 support + * supports namespaces, and modules, including mod_content and mod_event + * open minded [1] + * simple, functional interface, to object oriented backend parser + * automatic caching of parsed RSS objects makes its easy to integrate + * supports conditional GET with Last-Modified, and ETag + * uses constants for easy override of default behaviour + * heavily commented + + +1. By open minded I mean Magpie will accept any tag it finds in good faith that + it was supposed to be here. For strict validation, look elsewhere. + + +GETTING STARTED + + + +COPYRIGHT: + Copyright(c) 2002 kellan@protest.net. All rights reserved. + This software is released under the GNU General Public License. + Please read the disclaimer at the top of the Snoopy.class.inc file. diff --git a/htdocs/includes/magpierss/extlib/Snoopy.class.inc b/htdocs/includes/magpierss/extlib/Snoopy.class.inc index e0b3e0cf65c5e48ebf84f9db157a6d698bd4c6d5..cf832d0b2ab0bdb9bad500eb830a991ac6a9902a 100644 --- a/htdocs/includes/magpierss/extlib/Snoopy.class.inc +++ b/htdocs/includes/magpierss/extlib/Snoopy.class.inc @@ -198,8 +198,10 @@ class Snoopy return true; break; case "https": - if(!$this->curl_path || (!is_executable($this->curl_path))) + if(!$this->curl_path || (!is_executable($this->curl_path))) { + $this->error = "Bad curl ($this->curl_path), can't fetch HTTPS \n"; return false; + } $this->host = $URI_PARTS["host"]; if(!empty($URI_PARTS["port"])) $this->port = $URI_PARTS["port"]; @@ -258,325 +260,6 @@ class Snoopy return true; } -/*======================================================================*\ - Function: submit - Purpose: submit an http form - Input: $URI the location to post the data - $formvars the formvars to use. - format: $formvars["var"] = "val"; - Output: $this->results the text output from the post -\*======================================================================*/ - - function submit($URI, $formvars="", $formfiles="") - { - unset($postdata); - - $postdata = $this->_prepare_post_body($formvars, $formfiles); - - $URI_PARTS = parse_url($URI); - if (!empty($URI_PARTS["user"])) - $this->user = $URI_PARTS["user"]; - if (!empty($URI_PARTS["pass"])) - $this->pass = $URI_PARTS["pass"]; - - switch($URI_PARTS["scheme"]) - { - case "http": - $this->host = $URI_PARTS["host"]; - if(!empty($URI_PARTS["port"])) - $this->port = $URI_PARTS["port"]; - if($this->_connect($fp)) - { - if($this->_isproxy) - { - // using proxy, send entire URI - $this->_httprequest($URI,$fp,$URI,$this->_submit_method,$this->_submit_type,$postdata); - } - else - { - $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); - // no proxy, send only the path - $this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata); - } - - $this->_disconnect($fp); - - if($this->_redirectaddr) - { - /* url was redirected, check if we've hit the max depth */ - if($this->maxredirs > $this->_redirectdepth) - { - if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) - $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); - - // only follow redirect if it's on this site, or offsiteok is true - if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) - { - /* follow the redirect */ - $this->_redirectdepth++; - $this->lastredirectaddr=$this->_redirectaddr; - $this->submit($this->_redirectaddr,$formvars, $formfiles); - } - } - } - - if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) - { - $frameurls = $this->_frameurls; - $this->_frameurls = array(); - - while(list(,$frameurl) = each($frameurls)) - { - if($this->_framedepth < $this->maxframes) - { - $this->fetch($frameurl); - $this->_framedepth++; - } - else - break; - } - } - - } - else - { - return false; - } - return true; - break; - case "https": - if(!$this->curl_path || (!is_executable($this->curl_path))) - return false; - $this->host = $URI_PARTS["host"]; - if(!empty($URI_PARTS["port"])) - $this->port = $URI_PARTS["port"]; - if($this->_isproxy) - { - // using proxy, send entire URI - $this->_httpsrequest($URI, $URI, $this->_submit_method, $this->_submit_type, $postdata); - } - else - { - $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); - // no proxy, send only the path - $this->_httpsrequest($path, $URI, $this->_submit_method, $this->_submit_type, $postdata); - } - - if($this->_redirectaddr) - { - /* url was redirected, check if we've hit the max depth */ - if($this->maxredirs > $this->_redirectdepth) - { - if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) - $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); - - // only follow redirect if it's on this site, or offsiteok is true - if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) - { - /* follow the redirect */ - $this->_redirectdepth++; - $this->lastredirectaddr=$this->_redirectaddr; - $this->submit($this->_redirectaddr,$formvars, $formfiles); - } - } - } - - if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) - { - $frameurls = $this->_frameurls; - $this->_frameurls = array(); - - while(list(,$frameurl) = each($frameurls)) - { - if($this->_framedepth < $this->maxframes) - { - $this->fetch($frameurl); - $this->_framedepth++; - } - else - break; - } - } - return true; - break; - - default: - // not a valid protocol - $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; - return false; - break; - } - return true; - } - -/*======================================================================*\ - Function: fetchlinks - Purpose: fetch the links from a web page - Input: $URI where you are fetching from - Output: $this->results an array of the URLs -\*======================================================================*/ - - function fetchlinks($URI) - { - if ($this->fetch($URI)) - { - - if(is_array($this->results)) - { - for($x=0;$x<count($this->results);$x++) - $this->results[$x] = $this->_striplinks($this->results[$x]); - } - else - $this->results = $this->_striplinks($this->results); - - if($this->expandlinks) - $this->results = $this->_expandlinks($this->results, $URI); - return true; - } - else - return false; - } - -/*======================================================================*\ - Function: fetchform - Purpose: fetch the form elements from a web page - Input: $URI where you are fetching from - Output: $this->results the resulting html form -\*======================================================================*/ - - function fetchform($URI) - { - - if ($this->fetch($URI)) - { - - if(is_array($this->results)) - { - for($x=0;$x<count($this->results);$x++) - $this->results[$x] = $this->_stripform($this->results[$x]); - } - else - $this->results = $this->_stripform($this->results); - - return true; - } - else - return false; - } - - -/*======================================================================*\ - Function: fetchtext - Purpose: fetch the text from a web page, stripping the links - Input: $URI where you are fetching from - Output: $this->results the text from the web page -\*======================================================================*/ - - function fetchtext($URI) - { - if($this->fetch($URI)) - { - if(is_array($this->results)) - { - for($x=0;$x<count($this->results);$x++) - $this->results[$x] = $this->_striptext($this->results[$x]); - } - else - $this->results = $this->_striptext($this->results); - return true; - } - else - return false; - } - -/*======================================================================*\ - Function: submitlinks - Purpose: grab links from a form submission - Input: $URI where you are submitting from - Output: $this->results an array of the links from the post -\*======================================================================*/ - - function submitlinks($URI, $formvars="", $formfiles="") - { - if($this->submit($URI,$formvars, $formfiles)) - { - if(is_array($this->results)) - { - for($x=0;$x<count($this->results);$x++) - { - $this->results[$x] = $this->_striplinks($this->results[$x]); - if($this->expandlinks) - $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); - } - } - else - { - $this->results = $this->_striplinks($this->results); - if($this->expandlinks) - $this->results = $this->_expandlinks($this->results,$URI); - } - return true; - } - else - return false; - } - -/*======================================================================*\ - Function: submittext - Purpose: grab text from a form submission - Input: $URI where you are submitting from - Output: $this->results the text from the web page -\*======================================================================*/ - - function submittext($URI, $formvars = "", $formfiles = "") - { - if($this->submit($URI,$formvars, $formfiles)) - { - if(is_array($this->results)) - { - for($x=0;$x<count($this->results);$x++) - { - $this->results[$x] = $this->_striptext($this->results[$x]); - if($this->expandlinks) - $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); - } - } - else - { - $this->results = $this->_striptext($this->results); - if($this->expandlinks) - $this->results = $this->_expandlinks($this->results,$URI); - } - return true; - } - else - return false; - } - - - -/*======================================================================*\ - Function: set_submit_multipart - Purpose: Set the form submission content type to - multipart/form-data -\*======================================================================*/ - function set_submit_multipart() - { - $this->_submit_type = "multipart/form-data"; - } - - -/*======================================================================*\ - Function: set_submit_normal - Purpose: Set the form submission content type to - application/x-www-form-urlencoded -\*======================================================================*/ - function set_submit_normal() - { - $this->_submit_type = "application/x-www-form-urlencoded"; - } - - /*======================================================================*\ @@ -812,7 +495,8 @@ class Snoopy return false; } - if($currentHeader == "\r\n") + // if($currentHeader == "\r\n") + if(preg_match("/^\r?\n$/", $currentHeader) ) break; // if a header begins with Location: or URI:, set the redirect @@ -970,6 +654,8 @@ class Snoopy $headerfile = uniqid(time()); + # accept self-signed certs + $cmdline_params .= " -k"; exec($this->curl_path." -D \"/tmp/$headerfile\"".$cmdline_params." ".$URI,$results,$return); if($return) @@ -1010,8 +696,13 @@ class Snoopy } if(preg_match("|^HTTP/|",$result_headers[$currentHeader])) + { $this->response_code = $result_headers[$currentHeader]; - + if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$this->response_code, $match)) + { + $this->status= $match[1]; + } + } $this->headers[] = $result_headers[$currentHeader]; } diff --git a/htdocs/includes/magpierss/rss_cache.inc b/htdocs/includes/magpierss/rss_cache.inc index 3dc39cbf36b2569efa04de37217840e4e276352d..fdfa5dd2591dda38d4bd9fbc37d5eb2c2499ef6c 100644 --- a/htdocs/includes/magpierss/rss_cache.inc +++ b/htdocs/includes/magpierss/rss_cache.inc @@ -2,10 +2,10 @@ /* * Project: MagpieRSS: a simple RSS integration tool * File: rss_cache.inc, a simple, rolling(no GC), cache - * for RSS objects, keyed on URL. + * for RSS objects, keyed on URL. * Author: Kellan Elliott-McCrea <kellan@protest.net> - * Version: 0.51 - * License: GPL + * Version: 0.51 + * License: GPL * * The lastest version of MagpieRSS can be obtained from: * http://magpierss.sourceforge.net @@ -17,167 +17,167 @@ */ class RSSCache { - var $BASE_CACHE = './cache'; // where the cache files are stored - var $MAX_AGE = 3600; // when are files stale, default one hour - var $ERROR = ""; // accumulate error messages - - function RSSCache ($base='', $age='') { - if ( $base ) { - $this->BASE_CACHE = $base; - } - if ( $age ) { - $this->MAX_AGE = $age; - } - - // attempt to make the cache directory - if ( ! file_exists( $this->BASE_CACHE ) ) { - $status = @mkdir( $this->BASE_CACHE, 0755 ); - - // if make failed - if ( ! $status ) { - $this->error( - "Cache couldn't make dir '" . $this->BASE_CACHE . "'." - ); - } - } - } - + var $BASE_CACHE = './cache'; // where the cache files are stored + var $MAX_AGE = 3600; // when are files stale, default one hour + var $ERROR = ""; // accumulate error messages + + function RSSCache ($base='', $age='') { + if ( $base ) { + $this->BASE_CACHE = $base; + } + if ( $age ) { + $this->MAX_AGE = $age; + } + + // attempt to make the cache directory + if ( ! file_exists( $this->BASE_CACHE ) ) { + $status = @mkdir( $this->BASE_CACHE, 0755 ); + + // if make failed + if ( ! $status ) { + $this->error( + "Cache couldn't make dir '" . $this->BASE_CACHE . "'." + ); + } + } + } + /*=======================================================================*\ - 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 + 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) { - $this->ERROR = ""; - $cache_file = $this->file_name( $url ); - $fp = @fopen( $cache_file, 'w' ); - - if ( ! $fp ) { - $this->error( - "Cache unable to open file for writing: $cache_file" - ); - return 0; - } - - - $data = $this->serialize( $rss ); - fwrite( $fp, $data ); - fclose( $fp ); - - return $cache_file; - } - + function set ($url, $rss) { + $this->ERROR = ""; + $cache_file = $this->file_name( $url ); + $fp = @fopen( $cache_file, 'w' ); + + if ( ! $fp ) { + $this->error( + "Cache unable to open file for writing: $cache_file" + ); + return 0; + } + + + $data = $this->serialize( $rss ); + fwrite( $fp, $data ); + fclose( $fp ); + + return $cache_file; + } + /*=======================================================================*\ - 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_file = $this->file_name( $url ); - - if ( ! file_exists( $cache_file ) ) { - $this->debug( - "Cache doesn't contain: $url (cache file: $cache_file)" - ); - return 0; - } - - $fp = @fopen($cache_file, 'r'); - if ( ! $fp ) { - $this->error( - "Failed to open cache file for reading: $cache_file" - ); - return 0; - } - - $data = fread( $fp, filesize($cache_file) ); - $rss = $this->unserialize( $data ); - - return $rss; - } + 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_file = $this->file_name( $url ); + + if ( ! file_exists( $cache_file ) ) { + $this->debug( + "Cache doesn't contain: $url (cache file: $cache_file)" + ); + return 0; + } + + $fp = @fopen($cache_file, 'r'); + if ( ! $fp ) { + $this->error( + "Failed to open cache file for reading: $cache_file" + ); + return 0; + } + + $data = fread( $fp, filesize($cache_file) ); + $rss = $this->unserialize( $data ); + + return $rss; + } /*=======================================================================*\ - 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 = ""; - $filename = $this->file_name( $url ); - - if ( file_exists( $filename ) ) { - // find how long ago the file was added to the cache - // and whether that is longer then MAX_AGE - $mtime = filemtime( $filename ); - $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'; - } - } + 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 = ""; + $filename = $this->file_name( $url ); + + if ( file_exists( $filename ) ) { + // find how long ago the file was added to the cache + // and whether that is longer then MAX_AGE + $mtime = filemtime( $filename ); + $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'; + } + } /*=======================================================================*\ - Function: serialize -\*=======================================================================*/ - function serialize ( $rss ) { - return serialize( $rss ); - } + Function: serialize +\*=======================================================================*/ + function serialize ( $rss ) { + return serialize( $rss ); + } /*=======================================================================*\ - Function: unserialize -\*=======================================================================*/ - function unserialize ( $data ) { - return unserialize( $data ); - } - + Function: unserialize +\*=======================================================================*/ + function unserialize ( $data ) { + return unserialize( $data ); + } + /*=======================================================================*\ - 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) { - $filename = md5( $url ); - return join( DIRECTORY_SEPARATOR, array( $this->BASE_CACHE, $filename ) ); - } + 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) { + $filename = md5( $url ); + return join( DIRECTORY_SEPARATOR, array( $this->BASE_CACHE, $filename ) ); + } /*=======================================================================*\ - 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); - } - } + 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); + } + } } diff --git a/htdocs/includes/magpierss/rss_fetch.inc b/htdocs/includes/magpierss/rss_fetch.inc index 29d4b0bb89032ee54840bda8f6f1852939694bd9..8a919811e65ab40506403c384f58dd9688cdce9e 100644 --- a/htdocs/includes/magpierss/rss_fetch.inc +++ b/htdocs/includes/magpierss/rss_fetch.inc @@ -5,7 +5,7 @@ to fetching and parsing RSS files, via the function fetch_rss() * Author: Kellan Elliott-McCrea <kellan@protest.net> - * Version: 0.51 + * Modified by Laurent Destailleur <eldy@users.sourceforge.net> for Dolibarr * License: GPL * * The lastest version of MagpieRSS can be obtained from: @@ -82,7 +82,7 @@ require_once( MAGPIE_EXTLIB . 'Snoopy.class.inc'); version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off) \*=======================================================================*/ -define('MAGPIE_VERSION', '0.51'); +define('MAGPIE_VERSION', '0.7'); $MAGPIE_ERROR = ""; @@ -117,10 +117,8 @@ function fetch_rss ($url) { $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE ); - if ($cache->ERROR) { - // Erreur - print $cache->ERROR; - if (MAGPIE_DEBUG) { debug($cache->ERROR, E_USER_WARNING); } + if (MAGPIE_DEBUG and $cache->ERROR) { + debug($cache->ERROR, E_USER_WARNING); } @@ -129,15 +127,20 @@ function fetch_rss ($url) { $rss = 0; // parsed RSS object $errormsg = 0; // errors, if any + // store parsed XML by desired output encoding + // as character munging happens at parse time + $cache_key = $url . MAGPIE_OUTPUT_ENCODING; + if (!$cache->ERROR) { // return cache HIT, MISS, or STALE - $cache_status = $cache->check_cache( $url ); + $cache_status = $cache->check_cache( $cache_key); } // if object cached, and cache is fresh, return cached obj if ( $cache_status == 'HIT' ) { - $rss = $cache->get( $url ); + $rss = $cache->get( $cache_key ); if ( isset($rss) and $rss ) { + // should be cache age $rss->from_cache = 1; if ( MAGPIE_DEBUG > 1) { debug("MagpieRSS: Cache HIT", E_USER_NOTICE); @@ -150,8 +153,8 @@ function fetch_rss ($url) { // setup headers if ( $cache_status == 'STALE' ) { - $rss = $cache->get( $url ); - if ( $rss->etag and $rss->last_modified ) { + $rss = $cache->get( $cache_key ); + if ( $rss and $rss->etag and $rss->last_modified ) { $request_headers['If-None-Match'] = $rss->etag; $request_headers['If-Last-Modified'] = $rss->last_modified; } @@ -166,7 +169,7 @@ function fetch_rss ($url) { debug("Got 304 for $url"); } // reset cache on 304 (at minutillo insistent prodding) - $cache->set($url, $rss); + $cache->set($cache_key, $rss); return $rss; } elseif ( is_success( $resp->status ) ) { @@ -176,18 +179,22 @@ function fetch_rss ($url) { debug("Fetch successful"); } // add object to cache - $cache->set( $url, $rss ); + $cache->set( $cache_key, $rss ); return $rss; } } else { - $errormsg = "Failed to fetch $url. "; - if ( $resp->error ) { + $errormsg = "Failed to fetch $url "; + if ( $resp->status == '-100' ) { + $errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)"; + } + elseif ( $resp->error ) { # compensate for Snoopy's annoying habbit to tacking # on '\n' + $http_error = substr($resp->error, 0, -2); - // LDR FIX BUG - $http_error = eregi_replace("\n","",$resp->error); + // LDR FIX BUG (plus necessaire car corrig� par ligne du dessus) + //$http_error = eregi_replace("\n","",$resp->error); $errormsg .= "(HTTP Error: $http_error)"; } @@ -198,7 +205,7 @@ function fetch_rss ($url) { // LDR FIX BUG Si echec recup http mais cache bien lu, on stock erreur dans object rss if ($rss) { $rss->ERROR=$errormsg; - if ($cache && $url) $rss->date=filemtime($cache->file_name($url)); + if ($cache && $cache_key) $rss->date=filemtime($cache->file_name($url)); } } } @@ -290,7 +297,7 @@ function _fetch_remote_file ($url, $headers = "" ) { Output: parsed RSS object (see rss_parse) \*=======================================================================*/ function _response_to_rss ($resp) { - $rss = new MagpieRSS( $resp->results ); + $rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING ); // if RSS parsed successfully if ( $rss and !$rss->ERROR) { @@ -339,11 +346,11 @@ function init () { return; } else { - define('MAGPIE_INITALIZED', 1); + define('MAGPIE_INITALIZED', true); } if ( !defined('MAGPIE_CACHE_ON') ) { - define('MAGPIE_CACHE_ON', 1); + define('MAGPIE_CACHE_ON', true); } if ( !defined('MAGPIE_CACHE_DIR') ) { @@ -372,9 +379,21 @@ function init () { } if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) { - define('MAGPIE_CACHE_FRESH_ONLY', 0); + define('MAGPIE_CACHE_FRESH_ONLY', false); } + if ( !defined('MAGPIE_OUTPUT_ENCODING') ) { + define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1'); + } + + if ( !defined('MAGPIE_INPUT_ENCODING') ) { + define('MAGPIE_INPUT_ENCODING', null); + } + + if ( !defined('MAGPIE_DETECT_ENCODING') ) { + define('MAGPIE_DETECT_ENCODING', true); + } + if ( !defined('MAGPIE_DEBUG') ) { define('MAGPIE_DEBUG', 0); } diff --git a/htdocs/includes/magpierss/rss_parse.inc b/htdocs/includes/magpierss/rss_parse.inc index 5566ecc53c328c69d0a4e9ab7d299534571e14b1..af4020ebfb49a4a91dc90a438f726831e4636970 100644 --- a/htdocs/includes/magpierss/rss_parse.inc +++ b/htdocs/includes/magpierss/rss_parse.inc @@ -1,338 +1,589 @@ <?php -/* - * Project: MagpieRSS: a simple RSS integration tool - * File: rss_parse.inc includes code for parsing - * RSS, and returning an RSS object - * Author: Kellan Elliott-McCrea <kellan@protest.net> - * Version: 0.51 - * License: GPL - * - * The lastest version of MagpieRSS can be obtained from: - * http://magpierss.sourceforge.net - * - * For questions, help, comments, discussion, etc., please join the - * Magpie mailing list: - * magpierss-general@lists.sourceforge.net - * - */ - -/* - * NOTES ON RSS PARSING PHILOSOPHY (moderately important): - * MagpieRSS parse all versions of RSS with a few limitation (mod_content, and - * mod_taxonomy support is shaky) into a simple object, with 2 fields, - * the hash 'channel', and the array 'items'. - * - * MagpieRSS is a forgiving and inclusive parser. It currently makes no - * attempt to enforce the validity on an RSS feed. It will include any - * properly formatted tags it finds, allowing to you to mix RSS 0.93, with RSS - * 1.0, with tags or your own imagining. This sort of witches brew is a bad - * bad idea! But Magpie is less pendantic then I am. - * - * RSS validators are readily available on the web at: - * http://feeds.archive.org/validator/ - * http://www.ldodds.com/rss_validator/1.0/validator.html - * - */ +/** +* Project: MagpieRSS: a simple RSS integration tool +* 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 +* +* The lastest version of MagpieRSS can be obtained from: +* http://magpierss.sourceforge.net +* +* For questions, help, comments, discussion, etc., please join the +* Magpie mailing list: +* magpierss-general@lists.sourceforge.net +* +* @author Kellan Elliott-McCrea <kellan@protest.net> +* @version 0.7a +* @license GPL +* +*/ -/* - * EXAMPLE PARSE RESULTS: - * - * Magpie tries to parse RSS into ease to use PHP datastructures. - * - * For example, Magpie on encountering RSS 1.0 item entry: - * - * <item rdf:about="http://protest.net/NorthEast/calendrome.cgi?span=event&ID=210257"> - * <title>Weekly Peace Vigil</title> - * <link>http://protest.net/NorthEast/calendrome.cgi?span=event&ID=210257</link> - * <description>Wear a white ribbon</description> - * <dc:subject>Peace</dc:subject> - * <ev:startdate>2002-06-01T11:00:00</ev:startdate> - * <ev:location>Northampton, MA</ev:location> - * <ev:enddate>2002-06-01T12:00:00</ev:enddate> - * <ev:type>Protest</ev:type> - * </item> - * - * Would transform it into the following associative array, and push it - * onto the array $rss-items - * - * array( - * title => 'Weekly Peace Vigil', - * link => - * 'http://protest.net/NorthEast/calendrome.cgi?span=event&ID=210257', - * description => 'Wear a white ribbon', - * dc => array ( - * subject => 'Peace' - * ), - * ev => array ( - * startdate => '2002-06-01T11:00:00', - * enddate => '2002-06-01T12:00:00', - * type => 'Protest', - * location => 'Northampton, MA' - * ) - * ) - * - */ +define('RSS', 'RSS'); +define('ATOM', 'Atom'); +require_once (MAGPIE_DIR . 'rss_utils.inc'); + +/** +* Hybrid parser, and object, takes RSS as a string and returns a simple object. +* +* see: rss_fetch.inc for a simpler interface with integrated caching support +* +*/ class MagpieRSS { - /* - * Hybrid parser, and object. (probably a bad idea! :) - * - * Useage Example: - * - * $some_rss = "<?xml version="1.0"...... - * - * $rss = new MagpieRSS( $some_rss ); - * - * // print rss chanel title - * echo $rss->channel['title']; - * - * // print the title of each item - * foreach ($rss->items as $item ) { - * echo $item[title]; - * } - * - * see rss_fetch.inc for a simpler interface - */ - - 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 $parent_field = array('RDF'); - var $current_field = ''; - var $current_namespace = false; - - var $ERROR = ""; - -/*======================================================================*\ - Function: MagpieRSS - Purpose: Constructor, sets up XML parser,parses source, - and populates object.. - Input: String containing the RSS to be parsed -\*======================================================================*/ - function MagpieRSS ($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 ); - } - - $parser = @xml_parser_create(); - - 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 ); - } + 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; + var $encoding = ''; // output encoding of parsed rss + + var $_source_encoding = ''; // only set if we have to parse xml prolog + + var $ERROR = ""; + var $WARNING = ""; + + // define some constants + + var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright'); + 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 <content mode="xml"> field + var $intextinput = false; + var $inimage = false; + var $current_field = ''; + var $current_namespace = false; + + + /** + * Set up XML parser, parse source, and return populated RSS object.. + * + * @param string $source string containing the RSS to be parsed + * + * NOTE: Probably a good idea to leave the encoding options alone unless + * you know what you're doing as PHP's character set support is + * a little weird. + * + * NOTE: A lot of this is unnecessary but harmless with PHP5 + * + * + * @param string $output_encoding output the parsed RSS in this character + * set defaults to ISO-8859-1 as this is PHP's + * default. + * + * NOTE: might be changed to UTF-8 in future + * versions. + * + * @param string $input_encoding the character set of the incoming RSS source. + * Leave blank and Magpie will try to figure it + * out. + * + * + * @param bool $detect_encoding if false Magpie won't attempt to detect + * source encoding. (caveat emptor) + * + */ + function MagpieRSS ($source, $output_encoding='ISO-8859-1', + $input_encoding=null, $detect_encoding=true) + { + # 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 ); + } + + list($parser, $source) = $this->create_parser($source, + $output_encoding, $input_encoding, $detect_encoding); + + + 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 ); + } + + + $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, + 'feed_start_element', 'feed_end_element' ); + + xml_set_character_data_handler( $this->parser, 'feed_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 ); + } + } + + xml_parser_free( $this->parser ); + + $this->normalize(); + } + + function feed_start_element($p, $element, &$attrs) { + $el = $element = strtolower($element); + $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; + } + + # 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; + } + + 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 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; + } + + elseif ( + $this->feed_type == RSS and + $this->current_namespace == '' and + $el == 'image' ) + { + $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); + } + } + + + + function feed_cdata ($p, $text) { + + if ($this->feed_type == ATOM and $this->incontent) + { + $this->append_content( $text ); + } + else { + $current_el = join('_', array_reverse($this->stack)); + $this->append($current_el, $text); + } + } + + function feed_end_element ($p, $el) { + $el = strtolower($el); + + if ( $el == 'item' or $el == 'entry' ) + { + $this->items[] = $this->current_item; + $this->current_item = array(); + $this->initem = false; + } + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) + { + $this->intextinput = false; + } + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' ) + { + $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("</$el>"); + } + else { + $this->append_content("<$el />"); + } - - $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"; + array_shift( $this->stack ); + } + else { + array_shift( $this->stack ); + } + + $this->current_namespace = false; + } + + function concat (&$str1, $str2="") { + if (!isset($str1) ) { + $str1=""; + } + $str1 .= $str2; + } + + + + function append_content($text) { + if ( $this->initem ) { + $this->concat( $this->current_item[ $this->incontent ], $text ); + } + elseif ( $this->inchannel ) { + $this->concat( $this->channel[ $this->incontent ], $text ); + } + } + + // smart append - field and namespace aware + function append($el, $text) { + if (!$el) { + return; + } + if ( $this->current_namespace ) + { + if ( $this->initem ) { + $this->concat( + $this->current_item[ $this->current_namespace ][ $el ], $text); + } + 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 ); + } + + } + } + + function normalize () { + // if atom populate rss fields + 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($item['modified']); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $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']; + + if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) { + $epoch = @parse_w3cdtf($item['dc']['date']); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + elseif ( isset($item['pubdate']) ) { + $epoch = @strtotime($item['pubdate']); + if ($epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $this->items[$i] = $item; + } + } + } + + + function is_rss () { + if ( $this->feed_type == RSS ) { + return $this->feed_version; + } + else { + return false; + } + } + + function is_atom() { + if ( $this->feed_type == ATOM ) { + return $this->feed_version; + } + else { + return false; + } + } - $this->error( $errormsg ); - } - } - - xml_parser_free( $this->parser ); - } - - function start_element ($p, $element, &$attrs) { - $element = strtolower( $element ); - - # check for a namespace, and split if found - # - $namespace = false; - if ( strpos( $element, ':' ) ) { - list($namespace, $element) = split( ':', $element, 2); - } - $this->current_field = $element; - if ( $namespace and $namespace != 'rdf' ) { - $this->current_namespace = $namespace; - } - - if ( $element == 'channel' ) { - array_unshift( $this->parent_field, 'channel' ); - } - elseif ( $element == 'items' ) { - array_unshift( $this->parent_field, 'items' ); - } - elseif ( $element == 'item' ) { - array_unshift( $this->parent_field, 'item' ); - } - elseif ( $element == 'textinput' ) { - array_unshift( $this->parent_field, 'textinput' ); - } - elseif ( $element == 'image' ) { - array_unshift( $this->parent_field, 'image' ); - } - - } - - function end_element ($p, $element) { - $element = strtolower($element); - - if ( $element == 'item' ) { - $this->items[] = $this->current_item; - $this->current_item = array(); - array_shift( $this->parent_field ); - } - elseif ( $element == 'channel' or $element == 'items' or - $element == 'textinput' or $element == 'image' ) { - array_shift( $this->parent_field ); - } - - $this->current_field = ''; - $this->current_namespace = false; - } - - function cdata ($p, $text) { - # skip item, channel, items first time we see them - # - if ( $this->parent_field[0] == $this->current_field or - ! $this->current_field ) { - return; - } - elseif ( $this->parent_field[0] == 'channel') { - if ( $this->current_namespace ) { - $this->append( - $this->channel[ $this->current_namespace ][ $this->current_field ], - $text); - } - else { - $this->append($this->channel[ $this->current_field ], $text); - } - - } - elseif ( $this->parent_field[0] == 'item' ) { - if ( $this->current_namespace ) { - $this->append( - $this->current_item[ $this->current_namespace ][$this->current_field ], - $text); - } - else { - $this->append( - $this->current_item[ $this->current_field ], - $text ); - } - } - elseif ( $this->parent_field[0] == 'textinput' ) { - if ( $this->current_namespace ) { - $this->append( - $this->textinput[ $this->current_namespace ][ $this->current_field ], - $text ); - } - else { - $this->append( - $this->textinput[ $this->current_field ], - $text ); - } - } - elseif ( $this->parent_field[0] == 'image' ) { - if ( $this->current_namespace ) { - $this->append( - $this->image[ $this->current_namespace ][ $this->current_field ], - $text ); - } - else { - $this->append( - $this->image[ $this->current_field ], - $text ); - } - } - } - - function append (&$str1, $str2="") { - if (!isset($str1) ) { - $str1=""; - } - $str1 .= $str2; - } - - function error ($errormsg, $lvl=E_USER_WARNING) { - // append PHP's error message if track_errors enabled - if ( $php_errormsg ) { - $errormsg .= " ($php_errormsg)"; - } - $this->ERROR = $errormsg; - if ( MAGPIE_DEBUG ) { - trigger_error( $errormsg, $lvl); - } - else { - error_log( $errormsg, 0); - } - } - + /** + * return XML parser, and possibly re-encoded source + * + */ + 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); + } + + return array($parser, $source); + } + + /** + * Instantiate an XML parser under PHP5 + * + * PHP5 will do a fine job of detecting input encoding + * if passed an empty string as the encoding. + * + * All hail libxml2! + * + */ + 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); + } + else { + return xml_parser_create(''); + } + } + + /** + * 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); + } + + if (!$in_enc) { + if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) { + $in_enc = strtoupper($m[1]); + $this->source_encoding = $in_enc; + } + else { + $in_enc = 'UTF-8'; + } + } + + 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 + + if (function_exists('iconv')) { + $encoded_source = iconv($in_enc,'UTF-8', $source); + if ($encoded_source) { + return array(xml_parser_create('UTF-8'), $encoded_source); + } + } + + // 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); + } + } + + // 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 known_encoding($enc) { + $enc = strtoupper($enc); + if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) { + return $enc; + } + else { + return false; + } + } -/*======================================================================*\ - EVERYTHING BELOW HERE IS FOR DEBUGGING PURPOSES -\*======================================================================*/ - function show_list () { - echo "<ol>\n"; - foreach ($this->items as $item) { - echo "<li>", $this->show_item( $item ); - } - echo "</ol>"; - } - - function show_channel () { - echo "channel:<br>"; - echo "<ul>"; - while ( list($key, $value) = each( $this->channel ) ) { - echo "<li> $key: $value"; - } - echo "</ul>"; - } - - function show_item ($item) { - echo "item: $item[title]"; - echo "<ul>"; - while ( list($key, $value) = each($item) ) { - if ( is_array($value) ) { - echo "<br><b>$key</b>"; - echo "<ul>"; - while ( list( $ns_key, $ns_value) = each( $value ) ) { - echo "<li>$ns_key: $ns_value"; - } - echo "</ul>"; - } - else { - echo "<li> $key: $value"; - } - } - echo "</ul>"; - } + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( $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; + } else { + $this->ERROR = $errormsg; + } + } + + +} // end class RSS -/*======================================================================*\ - END DEBUGGING FUNCTIONS -\*======================================================================*/ - +function map_attrs($k, $v) { + return "$k=\"$v\""; +} -} # end class RSS ?> diff --git a/htdocs/includes/magpierss/rss_utils.inc b/htdocs/includes/magpierss/rss_utils.inc index 655db8a1921dfd997682a98048f9238c34976218..2a29e72a9696598bd8f1eca21aa4f955ebf4b243 100644 --- a/htdocs/includes/magpierss/rss_utils.inc +++ b/htdocs/includes/magpierss/rss_utils.inc @@ -3,8 +3,8 @@ * Project: MagpieRSS: a simple RSS integration tool * File: rss_utils.inc, utility methods for working with RSS * Author: Kellan Elliott-McCrea <kellan@protest.net> - * Version: 0.51 - * License: GPL + * Version: 0.51 + * License: GPL * * The lastest version of MagpieRSS can be obtained from: * http://magpierss.sourceforge.net @@ -19,49 +19,49 @@ Function: parse_w3cdtf Purpose: parse a W3CDTF date into unix epoch - NOTE: http://www.w3.org/TR/NOTE-datetime + NOTE: http://www.w3.org/TR/NOTE-datetime \*======================================================================*/ 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[6]); - - # calc epoch for current date assuming GMT - $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year); - - $offset = 0; - if ( $match[10] == 'Z' ) { - # zulu time, aka GMT - } - else { - list( $tz_mod, $tz_hour, $tz_min ) = - array( $match[8], $match[9], $match[10]); - - # zero out the variables - if ( ! $tz_hour ) { $tz_hour = 0; } - if ( ! $tz_min ) { $tz_min = 0; } - - $offset_secs = (($tz_hour*60)+$tz_min)*60; - - # is timezone ahead of GMT? then subtract offset - # - if ( $tz_mod == '+' ) { - $offset_secs = $offset_secs * -1; - } - - $offset = $offset_secs; - } - $epoch = $epoch + $offset; - return $epoch; - } - else { - return -1; - } + + # 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[6]); + + # calc epoch for current date assuming GMT + $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year); + + $offset = 0; + if ( $match[10] == 'Z' ) { + # zulu time, aka GMT + } + else { + list( $tz_mod, $tz_hour, $tz_min ) = + array( $match[8], $match[9], $match[10]); + + # zero out the variables + if ( ! $tz_hour ) { $tz_hour = 0; } + if ( ! $tz_min ) { $tz_min = 0; } + + $offset_secs = (($tz_hour*60)+$tz_min)*60; + + # is timezone ahead of GMT? then subtract offset + # + if ( $tz_mod == '+' ) { + $offset_secs = $offset_secs * -1; + } + + $offset = $offset_secs; + } + $epoch = $epoch + $offset; + return $epoch; + } + else { + return -1; + } } ?>