<?PHP

#
#   FILE:  Scout--RSSClient.php
#
#   METHODS PROVIDED:
#       RSSClient()
#           - constructor
#       SomeMethod($SomeParameter, $AnotherParameter)
#           - short description of method
#
#   AUTHOR:  Edward Almasy
#
#   Copyright 2005 Internet Scout Project
#   http://scout.wisc.edu
#

class RSSClient {

    # ---- PUBLIC INTERFACE --------------------------------------------------

    # object constructor
    function RSSClient($ServerUrl, $CacheDB = NULL, $CacheTablePrefix = "", $RefreshTime = 600, $DebugLevel = 0)
    {
        # set default debug level
        $this->DebugLevel = $DebugLevel;
        
        # query server (or cache) for XML text
        $this->XmlText = $this->QueryServerWithCaching($ServerUrl, $CacheDB, $CacheTablePrefix, $RefreshTime);

        # create XML parser and parse text
        $this->Parser = new XMLParser();
        if ($this->DebugLevel > 3) {  $Parser->SetDebugLevel($this->DebugLevel - 3);  }
        $this->Parser->ParseText($this->XmlText);

        if ($this->DebugLevel) {  print("RSSClient->RSSClient() returned ".strlen($this->XmlText)." characters from server query<br>\n");  }
    }

    # get/set server URL
    function ServerUrl($NewValue = NULL) 
    {  
        # if new RSS server URL supplied
        if (($NewValue != NULL) && ($NewValue != $this->ServerUrl))
        {  
            # save new value
            $this->ServerUrl = $NewValue;  

            # re-read XML from server at new URL
            $this->XmlText = $this->QueryServerWithCaching($NewValue);

            # create new XML parser and parse text
            $this->Parser = new XMLParser();
            if ($this->DebugLevel > 3) {  $Parser->SetDebugLevel($this->DebugLevel - 3);  }
            $this->Parser->ParseText($this->XmlText);
        }

        # return RSS server URL to caller
        return $this->ServerUrl;  
    }

    # retrieve RSS items (from first channel if not otherwise specified)
    function GetItems($NumberOfItems = NULL, $ChannelName = NULL)
    {
        # start by assuming no items will be found
        $Items = array();

        # move parser to area in XML with items
        $Parser = $this->Parser;
        $Parser->SeekToRoot();
        $Result = $Parser->SeekTo("rss");
        if ($Result === NULL)
        {  
            $Result = $Parser->SeekTo("rdf:RDF");  
        }
        else
        {
            $Parser->SeekTo("channel");
        }

        # if items are found
        $ItemCount = $Parser->SeekTo("item");
        if ($ItemCount)
        {
            # for each record
            $Index = 0;
            do
            {
                # retrieve item info
                $Items[$Index]["title"] = $Parser->GetData("title");
                $Items[$Index]["description"] = $Parser->GetData("description");
                $Items[$Index]["link"] = $Parser->GetData("link");
                $Items[$Index]["enclosure"] = $Parser->GetAttributes("enclosure");

                $Index++;
            }
            while ($Parser->NextItem() && (($NumberOfItems == NULL) || ($Index < $NumberOfItems)));
        }

        # return records to caller
        return $Items;
    }

    # retrieve site name as given in feed
    function GetChannelTitle()
    {
        if (!isset($this->ChannelTitle)) {  $this->LoadChannelInfo();  }
        return $this->ChannelTitle;
    }

    # retrieve site link as given in feed
    function GetChannelLink()
    {
        if (!isset($this->ChannelLink)) {  $this->LoadChannelInfo();  }
        return $this->ChannelLink;
    }
 
    # retrieve site description as given in feed
    function GetChannelDescription()
    {
        if (!isset($this->ChannelDescription)) {  $this->LoadChannelInfo();  }
        return $this->ChannelDescription;
    }

    # tell caller whether client is using cached data
    function UsedCachedData()
    {
        return $this->CachedDataWasUsed;
    }
 

    # ---- PRIVATE INTERFACE -------------------------------------------------

    var $ServerUrl;
    var $MetadataPrefix;
    var $SetSpec;
    var $DebugLevel;
    var $XmlText;
    var $Parser;
    var $ChannelTitle;
    var $ChannelLink;
    var $ChannelDescription;
    var $CachedDataWasUsed;
    
    # set current debug output level (0-9)
    function SetDebugLevel($NewLevel)
    {
        $this->DebugLevel = $NewLevel;
    }

    # load RSS XML from server or cache
    function QueryServerWithCaching($ServerUrl, $CacheDB, $CacheTablePrefix, $RefreshTime)
    {
        # save RSS server URL
        $this->ServerUrl = $ServerUrl;

        # save caching info (if any)
        if ($CacheDB)
        {
            $this->CacheDB = $CacheDB;
        }
        $this->CacheTablePrefix = $CacheTablePrefix;

        # if caching info was supplied
        if ($this->CacheDB)
        {
            # create cache table if it doesn't exist
            $DB = $this->CacheDB;
            $TableName = $CacheTablePrefix."RSSClientCache";
            $DB->Query("CREATE TABLE IF NOT EXISTS ".$TableName." ("
                    ."ServerUrl      TEXT,"
                    ."CachedXml      TEXT,"
                    ."LastQueryTime  DATETIME"
                    .");");

            # look up cached information for this server
            $QueryTimeCutoff = date("Y-m-d H:i:s", (time() - $RefreshTime));
            $DB->Query("SELECT * FROM ".$TableName." WHERE ServerUrl = '".addslashes($ServerUrl)."'"
                    ." AND LastQueryTime > '".$QueryTimeCutoff."'");

            # if we have cached info that has not expired
            if ($CachedXml = $DB->FetchField("CachedXml"))
            {
                # use cached info
                $QueryResult = $CachedXml;
                $this->CachedDataWasUsed = TRUE;
            }
            else
            {
                # query server for XML text
                $QueryResult = $this->QueryServer($ServerUrl);
                $this->CachedDataWasUsed = FALSE;

                # if query was successful
                if (strlen($QueryResult))
                {
                    # clear out any old cache entries
                    $DB->Query("DELETE FROM ".$TableName." WHERE ServerUrl = '".addslashes($ServerUrl)."'");

                    # save info in cache
                    $DB->Query("INSERT INTO ".$TableName." (ServerUrl, CachedXml, LastQueryTime)"
                            ." VALUES ('".addslashes($ServerUrl)."', '".addslashes($QueryResult)."', NOW())");
                }
            }
        }

        # return query result to caller
        return $QueryResult;
    }
    
    # perform RSS query and return resulting data to caller
    function QueryServer()
    {
        # open stream to RSS server
        $QueryUrl = $this->ServerUrl;
        $FHndl = fopen($QueryUrl, "r");

        # while lines left in response
        $Text = "";
        while (!feof($FHndl))
        {
            # read line from server and add it to text to be parsed
            $Text .= fgets($FHndl, 2000000);
        }

        # close RSS server stream
        fclose($FHndl);

        # return query result data to caller
        return $Text;
    }

    function LoadChannelInfo()
    {
        $Parser = $this->Parser;
        $Parser->SeekToRoot();
        $Result = $Parser->SeekTo("rss");
        if ($Result === NULL)
        {  
            $Result = $Parser->SeekTo("rdf:RDF");  
        }
        $Parser->SeekTo("channel");
        $this->ChannelTitle = $Parser->GetData("title");
        $this->ChannelLink = $Parser->GetData("link");
        $this->ChannelDescription = $Parser->GetData("description");
    }
}


?>
