00001 <?PHP
00002
00003 #
00004 # Axis--RSS.php
00005 # An Object to Support RSS 0.92 (Rich Site Summary) Output
00006 #
00007 # Copyright 2002 Axis Data
00008 # This code is free software that can be used or redistributed under the
00009 # terms of Version 2 of the GNU General Public License, as published by the
00010 # Free Software Foundation (http://www.fsf.org).
00011 #
00012 # Author: Edward Almasy (almasy@axisdata.com)
00013 #
00014 # Part of the AxisPHP library v1.2.5
00015 # For more information see http://www.axisdata.com/AxisPHP/
00016 #
00017
00018
00019 class RSS {
00020
00021 # ---- PUBLIC INTERFACE --------------------------------------------------
00022
00023 function RSS()
00024 {
00025 $this->ChannelCount = -1;
00026
00027 # default encoding is UTF-8
00028 $this->Encoding = "UTF-8";
00029 }
00030
00031 # required channel values
00032 function AddChannel($Title, $Link, $Description, $RssLink)
00033 {
00034 $this->ChannelCount++;
00035 $this->ItemCounts[$this->ChannelCount] = -1;
00036 $this->Channels[$this->ChannelCount]["Title"] = $Title;
00037 $this->Channels[$this->ChannelCount]["Link"] = $Link;
00038 $this->Channels[$this->ChannelCount]["Description"] = $Description;
00039 $this->Channels[$this->ChannelCount]["RssLink"] = $RssLink;
00040 }
00041 function SetImage($Url, $Height = NULL, $Width = NULL, $Description = NULL)
00042 {
00043 $this->Channels[$this->ChannelCount]["ImageUrl"] = $Url;
00044 $this->Channels[$this->ChannelCount]["ImageHeight"] = $Height;
00045 $this->Channels[$this->ChannelCount]["ImageWidth"] = $Width;
00046 $this->Channels[$this->ChannelCount]["ImageDescription"] = $Description;
00047 }
00048
00049 # optional channel values
00050 function SetEncoding($Value) { $this->Encoding = $Value; }
00051 function SetLanguage($Value) { $this->Channels[$this->ChannelCount]["Language"] = $Value; }
00052 function SetCopyright($Value) { $this->Channels[$this->ChannelCount]["Copyright"] = $Value; }
00053 function SetManagingEditor($Value) { $this->Channels[$this->ChannelCount]["ManagingEditor"] = $Value; }
00054 function SetWebmaster($Value) { $this->Channels[$this->ChannelCount]["Webmaster"] = $Value; }
00055 function SetPicsRating($Value) { $this->Channels[$this->ChannelCount]["PicsRating"] = $Value; }
00056 function SetPublicationDate($Value) { $this->Channels[$this->ChannelCount]["PublicationDate"] = $this->FormatDate($Value); }
00057 function SetLastChangeDate($Value) { $this->Channels[$this->ChannelCount]["LastChangeDate"] = $this->FormatDate($Value); }
00058 function SetTextInput($Title, $Description, $Name)
00059 {
00060 $this->Channels[$this->ChannelCount]["TextInputTitle"] = $Title;
00061 $this->Channels[$this->ChannelCount]["TextInputDescription"] = $Description;
00062 $this->Channels[$this->ChannelCount]["TextInputName"] = $Name;
00063 }
00064 function SetSkipTimes($Days, $Hours)
00065 {
00066 # ???
00067 }
00068 function SetCloud($Domain, $Port, $Path, $Procedure, $Protocol)
00069 {
00070 # ???
00071 }
00072
00073 # add item to channel
00074 function AddItem($Title = NULL, $Link = NULL, $Description = NULL, $Date = NULL)
00075 {
00076 $this->ItemCounts[$this->ChannelCount]++;
00077 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["Title"] = $Title;
00078 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["Link"] = $Link;
00079 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["Description"] = $Description;
00080 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["Date"] = $this->FormatDate($Date);
00081 }
00082 function AddItemCategory($Category, $Url)
00083 {
00084 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["Category"] = $Category;
00085 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["CategoryUrl"] = $Url;
00086 }
00087 function AddItemEnclosure($Url, $Length, $Type)
00088 {
00089 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["EnclosureUrl"] = $Url;
00090 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["EnclosureLength"] = $Length;
00091 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["EnclosureType"] = $Type;
00092 }
00093 function AddItemSource($Source, $Url)
00094 {
00095 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["Source"] = $Source;
00096 $this->Items[$this->ChannelCount][$this->ItemCounts[$this->ChannelCount]]["SourceUrl"] = $Url;
00097 }
00098
00099 # write out and RSS page
00100 function PrintRSS()
00101 {
00102 # print opening elements
00103 header("Content-type: application/rss+xml; charset=".$this->Encoding, TRUE);
00104 FTOut("<?xml version='1.0' encoding='".$this->Encoding."' ?>");
00105 FTOut("<rss version='2.0' xmlns:atom='http://www.w3.org/2005/Atom'>", 0);
00106
00107 # for each channel
00108 for ($this->ChannelIndex = 0; $this->ChannelIndex <= $this->ChannelCount; $this->ChannelIndex++)
00109 {
00110 # open channel element
00111 FTOut("<channel>");
00112
00113 # print required channel elements
00114 $this->PrintChannelElement("Title", "title");
00115 $this->PrintChannelElement("Link", "link");
00116 $this->PrintChannelElement("Description", "description");
00117 FTOut(
00118 "<atom:link href='"
00119 .$this->Channels[$this->ChannelCount]["RssLink"]
00120 ."' rel='self' type='application/rss+xml' />");
00121
00122 # print image element if set (url, title, link required)
00123 # title and link should be the same as those for the channel
00124 if ($this->IsChannelElementSet("ImageUrl"))
00125 {
00126 FTOut("<image>");
00127 $this->PrintChannelElement("ImageUrl", "url");
00128 $this->PrintChannelElement("Title", "title");
00129 $this->PrintChannelElement("Link", "link");
00130 $this->PrintChannelElement("ImageWidth", "width");
00131 $this->PrintChannelElement("ImageHeight", "height");
00132 $this->PrintChannelElement("ImageDescription", "description");
00133 FTOut("</image>");
00134 }
00135
00136 # print optional channel elements
00137 $this->PrintChannelElement("Language", "language");
00138 $this->PrintChannelElement("Copyright", "copyright");
00139 $this->PrintChannelElement("ManagingEditor", "managingEditor");
00140 $this->PrintChannelElement("Webmaster", "webMaster");
00141 $this->PrintChannelElement("PicsRating", "rating");
00142 $this->PrintChannelElement("PublicationDate", "pubDate");
00143 $this->PrintChannelElement("LastChangeDate", "lastBuildDate");
00144 # ??? STILL TO DO: SkipDays, SkipHours, Cloud
00145 FTOut("<docs>http://www.rssboard.org/rss-2-0-1</docs>");
00146
00147 # for each item in this channel
00148 for ($this->ItemIndex = 0; $this->ItemIndex <= $this->ItemCounts[$this->ChannelCount]; $this->ItemIndex++)
00149 {
00150 # open item element
00151 FTOut("<item>");
00152
00153 # print item elements
00154 $this->PrintItemElement("Title", "title");
00155 $this->PrintItemElement("Link", "link");
00156 $this->PrintItemElement("Link", "guid");
00157 $this->PrintItemElement("Description", "description");
00158 $this->PrintItemElement("Date", "pubDate");
00159 if (isset($this->Items[$this->ChannelIndex][$this->ItemIndex]["Category"])
00160 && ($this->Items[$this->ChannelIndex][$this->ItemIndex]["Category"] != NULL))
00161 {
00162 FTOut("<category url='".$this->Items[$this->ChannelIndex][$this->ItemIndex]["CategoryUrl"]."'>");
00163 FTOut($this->Items[$this->ChannelIndex][$this->ItemIndex]["Category"]);
00164 FTOut("</category>");
00165 }
00166 if (isset($this->Items[$this->ChannelIndex][$this->ItemIndex]["EnclosureUrl"])
00167 && ($this->Items[$this->ChannelIndex][$this->ItemIndex]["EnclosureUrl"] != NULL))
00168 {
00169 FTOut("<enclosure "
00170 ."url='".$this->Items[$this->ChannelIndex][$this->ItemIndex]["EnclosureUrl"]."' "
00171 ."length='".$this->Items[$this->ChannelIndex][$this->ItemIndex]["EnclosureLength"]."' "
00172 ."type='".$this->Items[$this->ChannelIndex][$this->ItemIndex]["EnclosureType"]."' />");
00173 }
00174 if (isset($this->Items[$this->ChannelIndex][$this->ItemIndex]["Source"])
00175 && ($this->Items[$this->ChannelIndex][$this->ItemIndex]["Source"] != NULL))
00176 {
00177 FTOut("<source url='".$this->Items[$this->ChannelIndex][$this->ItemIndex]["SourceUrl"]."'>");
00178 FTOut($this->Items[$this->ChannelIndex][$this->ItemIndex]["Source"]);
00179 FTOut("</source>");
00180 }
00181
00182 # close item element
00183 FTOut("</item>");
00184 }
00185
00186 # close channel element
00187 FTOut("</channel>");
00188 }
00189
00190 # print closing elements
00191 FTOut("</rss>");
00192 }
00193
00194
00195 # ---- PRIVATE INTERFACE -------------------------------------------------
00196
00197 var $Encoding;
00198 var $Channels;
00199 var $Items;
00200 var $ChannelCount;
00201 var $ItemCounts;
00202 var $ChannelIndex;
00203 var $ItemIndex;
00204
00210 private function IsChannelElementSet($VarName)
00211 {
00212 return (isset($this->Channels[$this->ChannelIndex][$VarName])
00213 && $this->Channels[$this->ChannelIndex][$VarName] != NULL
00214 && strlen($this->Channels[$this->ChannelIndex][$VarName]));
00215 }
00216
00222 private function IsItemElementSet($VarName)
00223 {
00224 return (isset($this->Items[$this->ChannelIndex][$this->ItemIndex][$VarName])
00225 && $this->Items[$this->ChannelIndex][$this->ItemIndex][$VarName] != NULL);
00226 }
00227
00233 private function PrintChannelElement($VarName, $TagName)
00234 {
00235 # only print channel elements if set
00236 if (!$this->IsChannelElementSet($VarName))
00237 {
00238 return;
00239 }
00240
00241 $InnerText = $this->EscapeInnerText(
00242 $this->Channels[$this->ChannelIndex][$VarName]);
00243
00244 FTOut("<${TagName}>".$InnerText."</${TagName}>");
00245 }
00246
00252 private function PrintItemElement($VarName, $TagName)
00253 {
00254 # only print elements that are set
00255 if (!$this->IsItemElementSet($VarName))
00256 {
00257 return;
00258 }
00259
00260 $InnerText = $this->EscapeInnerText(
00261 $this->Items[$this->ChannelIndex][$this->ItemIndex][$VarName]);
00262
00263 FTOut("<${TagName}>".$InnerText."</${TagName}>");
00264 }
00265
00273 private function FormatDate($Value)
00274 {
00275 return date("D, j M Y h:i:s O", strtotime($Value));
00276 }
00277
00284 private function EscapeInnerText($Text)
00285 {
00286 # remove control characters
00287 $Intermediate = preg_replace("/[\\x00-\\x1F]+/", "", $Text);
00288
00289 # escape XML special characters for PHP version < 5.2.3
00290 if (version_compare(phpversion(), "5.2.3", "<"))
00291 {
00292 $Intermediate = htmlspecialchars(
00293 $Intermediate, ENT_QUOTES, $this->Encoding);
00294 }
00295
00296 # escape XML special characters for PHP version >= 5.2.3
00297 else
00298 {
00299 $Intermediate = htmlspecialchars(
00300 $Intermediate, ENT_QUOTES, $this->Encoding, FALSE);
00301 }
00302
00303 # map named entities to their hex references
00304 $Replacements = array(
00305 "&" => "&",
00306 "<" => "<",
00307 ">" => ">",
00308 """ => """,
00309 "'" => "'");
00310
00311 # replace named entities with hex references for compatibility as
00312 # specified by the RSS spec/best practices
00313 $Intermediate = str_replace(
00314 array_keys($Replacements),
00315 array_values($Replacements),
00316 $Intermediate);
00317
00318 return $Intermediate;
00319 }
00320
00321 }
00322
00323 # (FTOut == Formatted Tag Output)
00324 function FTOut($String, $NewIndent = NULL)
00325 {
00326 static $Indent = 0;
00327
00328 $IndentSize = 4;
00329
00330 # decrease indent if string contains end tag and does not start with begin tag
00331 if (preg_match("/<\/[A-Za-z0-9]+>/", $String) && !preg_match("/^<[^\/]+/", $String)) { $Indent--; }
00332
00333 # reset indent if value is supplied
00334 if ($NewIndent != NULL) { $Indent = $NewIndent; }
00335
00336 # print string
00337 print(substr(" ",
00338 0, ($Indent * $IndentSize)).$String."\n");
00339
00340 # inrease indent if string starts with begin tag and does not contain end tag
00341 if (preg_match("/^<[^\/]+/", $String)
00342 && !preg_match("/<\/[A-Za-z0-9]+>/", $String)
00343 && !preg_match("/\/>$/", $String))
00344 {
00345 $Indent++;
00346 }
00347 }