2004-12-30 18:27:40 +00:00
|
|
|
<?php //$Id$
|
|
|
|
|
|
|
|
/**
|
2004-12-17 02:45:21 +00:00
|
|
|
* Project: MagpieRSS: a simple RSS integration tool
|
|
|
|
* File: rss_parse.inc includes code for parsing
|
2004-12-30 18:27:40 +00:00
|
|
|
* RSS, and returning an RSS object
|
2004-12-17 02:45:21 +00:00
|
|
|
* Author: Kellan Elliott-McCrea <kellan@protest.net>
|
2004-12-30 18:27:40 +00:00
|
|
|
* Version: 0.51
|
|
|
|
* License: GPL
|
2004-12-17 02:45:21 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2004-12-30 18:27:40 +00:00
|
|
|
/**
|
2004-12-17 02:45:21 +00:00
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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(
|
2004-12-30 18:27:40 +00:00
|
|
|
* 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'
|
|
|
|
* )
|
2004-12-17 02:45:21 +00:00
|
|
|
* )
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2004-12-30 18:27:40 +00:00
|
|
|
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();
|
2004-12-17 02:45:21 +00:00
|
|
|
|
2004-12-30 18:27:40 +00:00
|
|
|
var $parent_field = array('RDF');
|
|
|
|
var $current_field = '';
|
|
|
|
var $current_namespace = false;
|
2004-12-17 02:45:21 +00:00
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xml_parser_free( $this->parser );
|
|
|
|
}
|
|
|
|
|
|
|
|
function start_element ($p, $element, &$attrs) {
|
2004-12-30 18:27:40 +00:00
|
|
|
$element = strtolower( $element );
|
2004-12-17 02:45:21 +00:00
|
|
|
# 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 ( isset($php_errormsg) ) {
|
|
|
|
$errormsg .= " ($php_errormsg)";
|
|
|
|
}
|
|
|
|
$this->ERROR = $errormsg;
|
|
|
|
//if ( MAGPIE_DEBUG ) {
|
|
|
|
// trigger_error( $errormsg, $lvl);
|
|
|
|
//}
|
|
|
|
//else {
|
|
|
|
error_log( $errormsg, 0);
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*======================================================================*\
|
|
|
|
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>";
|
|
|
|
}
|
|
|
|
|
|
|
|
/*======================================================================*\
|
|
|
|
END DEBUGGING FUNCTIONS
|
|
|
|
\*======================================================================*/
|
|
|
|
|
|
|
|
} # end class RSS
|
|
|
|
?>
|