* @since 1.4 */ class FeedCreator extends HtmlDescribable { /** * Mandatory attributes of a feed. */ public $title, $description, $link; /** * Optional attributes of a feed. */ public $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays; /** * The url of the external xsl stylesheet used to format the naked rss feed. * Ignored in the output when empty. */ public $xslStyleSheet = ""; /** * The url of the external css stylesheet used to format the naked syndication feed. * Ignored in the output when empty. */ public $cssStyleSheet = ''; /** * @access private */ public $items = []; /** * This feed's MIME content type. * @since 1.4 * @access private */ public $contentType = "application/xml"; /** * This feed's character encoding. * @since 1.6.1 * * public $encoding = "ISO-8859-1"; //original :p */ public $encoding = "utf-8"; /* * Generator string * */ public $generator = "support@rdmcloud.uk"; /** * Any additional elements to include as an assiciated array. All $key => $value pairs * will be included unencoded in the feed in the form * <$key>$value * Again: No encoding will be used! This means you can invalidate or enhance the feed * if $value contains markup. This may be abused to embed tags not implemented by * the FeedCreator class used. */ public $additionalElements = []; /** * Adds an FeedItem to the feed. * * @param object FeedItem $item The FeedItem to add to the feed. * @access public */ public function addItem($item) { $this->items[] = $item; } /** * * * **/ function version() { return FEEDCREATOR_VERSION." (".$this->generator.")"; } /** * Truncates a string to a certain length at the most sensible point. * First, if there's a '.' character near the end of the string, the string is truncated after this character. * If there is no '.', the string is truncated after the last ' ' character. * If the string is truncated, " ..." is appended. * If the string is already shorter than $length, it is returned unchanged. * * @static * @param string string A string to be truncated. * @param int length the maximum length the string should be truncated to * @return string the truncated string */ public static function iTrunc($string, $length) { if (strlen($string)<=$length) { return $string; } $pos = strrpos($string,"."); if ($pos>=$length-4) { $string = substr($string,0,$length-4); $pos = strrpos($string,"."); } if ($pos>=$length*0.4) { return substr($string,0,$pos+1)." ..."; } $pos = strrpos($string," "); if ($pos>=$length-4) { $string = substr($string,0,$length-4); $pos = strrpos($string," "); } if ($pos>=$length*0.4) { return substr($string,0,$pos)." ..."; } return substr($string,0,$length-4)." ..."; } /** * Creates a comment indicating the generator of this feed. * The format of this comment seems to be recognized by * Syndic8.com. */ public function _createGeneratorComment() { return "\n"; } /** * Creates a string containing all additional elements specified in * $additionalElements. * @param array elements an associative array containing key => value pairs * @param string indentString a string that will be inserted before every generated line * @return string the XML tags corresponding to $additionalElements */ public function _createAdditionalElements($elements, $indentString="") { $ae = ""; if (\is_array( $elements )) { foreach ( $elements as $key => $value ) { $ae .= $indentString . "<$key>$value\n"; } } return $ae; } public function _createStylesheetReferences() { $xml = ""; if ($this->cssStyleSheet) $xml .= "cssStyleSheet."\" type=\"text/css\"?>\n"; if ($this->xslStyleSheet) $xml .= "xslStyleSheet."\" type=\"text/xsl\"?>\n"; return $xml; } /** * Builds the feed's text. * @abstract * @return string|void the feed's complete text */ public function createFeed() { } /** * Generate a filename for the feed cache file. The result will be $_SERVER["SCRIPT_NAME"] with the extension changed to .xml. * For example: * * echo $_SERVER["PHP_SELF"]."\n"; * echo FeedCreator::_generateFilename(); * * would produce: * * /rss/latestnews.php * latestnews.xml * * @return string the feed cache filename * @since 1.4 * @access private */ public function _generateFilename() { $fileInfo = pathinfo($_SERVER["PHP_SELF"]); return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; } /** * @since 1.4 * @access private */ public function _redirect($filename) { // attention, heavily-commented-out-area // maybe use this in addition to file time checking //Header("Expires: ".date("r",time()+$this->_timeout)); /* no caching at all, doesn't seem to work as good: Header("Cache-Control: no-cache"); Header("Pragma: no-cache"); */ // HTTP redirect, some feed readers' simple HTTP implementations don't follow it //Header("Location: ".$filename); // {{{ BITMOD //Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); Header( "Content-Type: " . $this->contentType . "; charset=" . $this->encoding . ";" ); // BITMOD }}} Header("Content-Disposition: inline; filename=".basename($filename)); readfile($filename ); die(); } /** * Turns on caching and checks if there is a recent version of this feed in the cache. * If there is, an HTTP redirect header is sent. * To effectively use caching, you should create the FeedCreator object and call this method * before anything else, especially before you do the time consuming task to build the feed * (web fetching, for example). * @since 1.4 * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["SCRIPT_NAME"] with the extension changed to .xml (see _generateFilename()). * @param int timeout optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) */ public function useCached($filename="", $timeout=3600) { $this->_timeout = $timeout; if ($filename == "") { $filename = $this->_generateFilename(); } if (file_exists( $filename ) AND ( time() - filemtime( $filename ) < $timeout )) { $this->_redirect( $filename ); } } /** * Saves this feed as a file on the local disk. After the file is saved, a redirect * header may be sent to redirect the user to the newly created file. * @since 1.4 * * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["SCRIPT_NAME"] with the extension changed to .xml (see _generateFilename()). * @param boolean redirect optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file. */ public function saveFeed($filename="", $displayContents=true) { if ($filename=="") { $filename = $this->_generateFilename(); } if (!is_dir( dirname( $filename ) )) { KernelTools::mkdir_p( dirname( $filename ) ); } $feedFile = fopen( $filename, "w+" ); if ($feedFile) { fputs( $feedFile, $this->createFeed() ); fclose( $feedFile ); if ($displayContents) { $this->_redirect( $filename ); } } else { echo "
Error creating feed file, please check write permissions.
"; } } /** * Outputs this feed directly to the browser - for on-the-fly feed generation * @since 1.7.2-mod * * still missing: proper header output - currently you have to add it manually */ public function outputFeed() { echo $this->createFeed(); } public function setEncoding($encoding="utf-8") { $this->encoding = "utf-8"; } /** * Creates a string containing all additional namespace specified */ public function addNamespace($ns,$uri) { $array = array_combine( [ $ns ], [ $uri ] ); $this->namespace = array_merge($array,$this->namespace); } public function _createNamespace() { $ns = ""; if (\is_array($this->namespace)) { foreach($this->namespace AS $key => $value) { $ns.= " xmlns:$key=\"$value\""; } } return $ns; } /** * * Additional namespace for custom modules and tags * * $key=>$value pair will match namespace xmlns:$key="$value" in tags * EXPERIMENTAL! * */ public $namespace = []; } /** * @package rss * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0. * * @see http://www.purl.org/rss/1.0/ * @since 1.3 * @author Kai Blankenhorn */ class RSSCreator10 extends FeedCreator { /** * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. * The feed will contain all items previously added in the same order. * @return string the feed's complete text */ public function createFeed() { $feed = "encoding."\"?>\n"; $feed.= $this->_createGeneratorComment(); if ($this->cssStyleSheet=="") { $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css"; } $feed.= $this->_createStylesheetReferences(); $feed.= "\n"; $feed.= " syndicationURL."\">\n"; $feed.= " ".htmlspecialchars($this->title)."\n"; $feed.= " ".htmlspecialchars($this->description)."\n"; $feed.= " ".$this->link."\n"; if ($this->image!=null) { $feed.= " image->url."\" />\n"; } $now = new FeedDate(); $feed .= " " . htmlspecialchars( $now->iso8601() ) . "\n"; $feed .= " \n"; $feed .= " \n"; for ( $i = 0; $i < count( $this->items ); $i++ ) { $feed .= " items[$i]->link ) . "\"/>\n"; } $feed .= " \n"; $feed .= " \n"; $feed .= " \n"; if ($this->image != null) { $feed .= " image->url . "\">\n"; $feed .= " " . $this->image->title . "\n"; $feed .= " " . $this->image->link . "\n"; $feed .= " " . $this->image->url . "\n"; $feed .= " \n"; } $feed .= $this->_createAdditionalElements( $this->additionalElements, " " ); for ( $i = 0; $i < count( $this->items ); $i++ ) { $feed .= " items[$i]->link ) . "\">\n"; //$feed.= " Posting\n"; $feed .= " text/html\n"; if ($this->items[$i]->date != null) { $itemDate = new FeedDate( $this->items[$i]->date ); $feed .= " " . htmlspecialchars( $itemDate->iso8601() ) . "\n"; } if ($this->items[$i]->source != "") { $feed .= " " . htmlspecialchars( $this->items[$i]->source ) . "\n"; } if ($this->items[$i]->author != "") { $feed .= " " . htmlspecialchars( $this->items[$i]->author ) . "\n"; } $feed.= " ".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."\n"; $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); $feed.= " \n"; } $feed .= "\n"; return $feed; } } /** * @package rss * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3. * * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html * @since 1.3 * @author Kai Blankenhorn */ class RSSCreator091 extends FeedCreator { /** * Stores this RSS feed's version number. * @access private */ public $RSSVersion; public $itunes; public $_timeout; public function addNamespace($ns,$uri) { parent::addNamespace($ns,$uri); } public function RSSCreator091() { $this->_setRSSVersion("0.91"); $this->contentType = "application/rss+xml"; } /** * Sets this RSS feed's version number. * @access private */ public function _setRSSVersion($version) { $this->RSSVersion = $version; } /** * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. * The feed will contain all items previously added in the same order. * @return string the feed's complete text */ public function createFeed() { $feed = "encoding."\"?>\n"; $feed.= $this->_createGeneratorComment(); $feed.= $this->_createStylesheetReferences(); if ($this->RSSVersion == "2.0" || $this->RSSVersion == "1.0" ) { $feed.= "RSSVersion."\" ". $this->_createNamespace(). ">\n"; } else { $feed.= "RSSVersion."\""; } // handler references for our rss tag if (isset( $this->media )) { $feed .= " xmlns:media=\"http://search.yahoo.com/mrss/\""; } if (isset( $this->itunes )) { $feed .= " xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\""; } // we're done with our rss tag $feed .= ">\n"; $feed .= " \n"; $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->title ), 100 ) . "\n"; $this->descriptionTruncSize = 500; $feed .= " " . $this->getDescription() . "\n"; $feed .= " " . $this->link . "\n"; $now = new FeedDate(); $feed .= " " . htmlspecialchars( $now->rfc822() ) . "\n"; $feed.= " ". $this->version()."\n"; if ($this->image != null) { $feed .= " \n"; $feed .= " " . $this->image->url . "\n"; $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->image->title ), 100 ) . "\n"; $feed .= " " . $this->image->link . "\n"; if ($this->image->width != "") { $feed .= " " . $this->image->width . "\n"; } if ($this->image->height != "") { $feed .= " " . $this->image->height . "\n"; } if ($this->image->description != "") { $feed .= " " . $this->image->getDescription() . "\n"; } $feed .= " \n"; } if ($this->language != "") { $feed .= " " . $this->language . "\n"; } if ($this->copyright != "") { $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->copyright ), 100 ) . "\n"; } if ($this->editor != "") { $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->editor ), 100 ) . "\n"; } if ($this->webmaster != "") { $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->webmaster ), 100 ) . "\n"; } if ($this->pubDate != "") { $pubDate = new FeedDate( $this->pubDate ); $feed .= " " . htmlspecialchars( $pubDate->rfc822() ) . "\n"; } if ($this->category != "") { $feed .= " " . htmlspecialchars( $this->category ) . "\n"; } if ($this->docs != "") { $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->docs ), 500 ) . "\n"; } if ($this->ttl != "") { $feed .= " " . htmlspecialchars( $this->ttl ) . "\n"; } if ($this->rating != "") { $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( $this->rating ), 500 ) . "\n"; } if ($this->skipHours != "") { $feed .= " " . htmlspecialchars( $this->skipHours ) . "\n"; } if ($this->skipDays != "") { $feed .= " " . htmlspecialchars( $this->skipDays ) . "\n"; } if (isset( $this->media ) && \is_array( $this->media )) { if (isset( $this->media['thumbnail'] )) { $feed .= " \n"; } } if (isset( $this->itunes ) && \is_array( $this->itunes )) { if (isset( $this->itunes['thumbnail'] )) { $feed .= " \n"; } // itunes expects an explicit setting. we default to no because we're not into this facist crap, but if you need to set it to yes you can. $itunesExplicit = $this->itunes['explicit'] ?? "no"; $feed .= " " . $itunesExplicit . "\n"; } if ($this->RSSVersion == "2.0" || $this->RSSVersion == "1.0" ) { $feed.= $this->_createAdditionalElements($this->additionalElements, " "); } for ( $i = 0; $i < count( $this->items ); $i++ ) { $feed .= " \n"; $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( strip_tags( $this->items[$i]->title ) ), 100 ) . "\n"; $feed .= " " . htmlspecialchars( $this->items[$i]->link ) . "\n"; $feed .= " " . $this->items[$i]->getDescription() . "\n"; if ($this->items[$i]->author!="") { if ($this->items[$i]->authorEmail!="") { $feed.= " " . htmlspecialchars($this->items[$i]->authorEmail) . " (".htmlspecialchars($this->items[$i]->author).")\n"; } else { $feed.= " no_email@example.com (".htmlspecialchars($this->items[$i]->author).")\n"; } } /* // on hold if ($this->items[$i]->source!="") { $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; } */ if ($this->items[$i]->category!="") { $feed.= " items[$i]->categoryScheme)) { $feed.=" domain=\"". htmlspecialchars($this->items[$i]->categoryScheme)."\""; } $feed.=">".htmlspecialchars($this->items[$i]->category)."\n"; } if ($this->items[$i]->comments != "") { $feed .= " " . htmlspecialchars( $this->items[$i]->comments ) . "\n"; } if ($this->items[$i]->date != "") { $itemDate = new FeedDate( $this->items[$i]->date ); $feed .= " " . htmlspecialchars( $itemDate->rfc822() ) . "\n"; } if ($this->items[$i]->guid!="") { $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; } else { $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; } if ($this->RSSVersion == "2.0" || $this->RSSVersion == "1.0" ) { $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); } if ($this->RSSVersion == "2.0" && $this->items[$i]->enclosure != NULL) { $feed.= " items[$i]->enclosure->url; $feed.= "\" length=\""; $feed.= $this->items[$i]->enclosure->length; $feed.= "\" type=\""; $feed.= $this->items[$i]->enclosure->type; $feed.= "\"/>\n"; } $feed.= " \n"; } $feed .= " \n"; $feed .= "\n"; return $feed; } } /** * @package rss * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0. * * @see http://backend.userland.com/rss * @since 1.3 * @author Kai Blankenhorn */ class RSSCreator20 extends RSSCreator091 { function RSSCreator20() { parent::_setRSSVersion("2.0"); } } /** * @package rss * PIECreator01 is a FeedCreator that implements the emerging PIE specification, * as in http://intertwingly.net/wiki/pie/Syntax. * * @deprecated * @since 1.3 * @author Scott Reynen and Kai Blankenhorn */ class PIECreator01 extends FeedCreator { public function PIECreator01() { $this->encoding = "utf-8"; } public function createFeed() { $feed = "encoding."\"?>\n"; $feed.= $this->_createStylesheetReferences(); $feed.= "\n"; $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; $this->truncSize = 500; $feed .= " " . $this->getDescription() . "\n"; $feed .= " " . $this->link . "\n"; for ( $i = 0; $i < count( $this->items ); $i++ ) { $feed .= " \n"; $feed .= " " . FeedCreator::iTrunc( htmlspecialchars( strip_tags( $this->items[$i]->title ) ), 100 ) . "\n"; $feed .= " " . htmlspecialchars( $this->items[$i]->link ) . "\n"; $itemDate = new FeedDate( $this->items[$i]->date ); $feed .= " " . htmlspecialchars( $itemDate->iso8601() ) . "\n"; $feed .= " " . htmlspecialchars( $itemDate->iso8601() ) . "\n"; $feed .= " " . htmlspecialchars( $itemDate->iso8601() ) . "\n"; $feed .= " " . htmlspecialchars( $this->items[$i]->guid ) . "\n"; if ($this->items[$i]->author != "") { $feed .= " \n"; $feed .= " " . htmlspecialchars( $this->items[$i]->author ) . "\n"; if ($this->items[$i]->authorEmail != "") { $feed .= " " . $this->items[$i]->authorEmail . "\n"; } $feed .= " \n"; } $feed .= " \n"; $feed .= "
" . $this->items[$i]->getDescription() . "
\n"; $feed .= "
\n"; $feed .= "
\n"; } $feed .= "
\n"; return $feed; } } /** * AtomCreator10 is a FeedCreator that implements the atom specification, * as in http://www.atomenabled.org/developers/syndication/atom-format-spec.php * Please note that just by using AtomCreator10 you won't automatically * produce valid atom files. For example, you have to specify either an editor * for the feed or an author for every single feed item. * * Some elements have not been implemented yet. These are (incomplete list): * author URL, item author's email and URL, item contents, alternate links, * other link content types than text/html. Some of them may be created with * AtomCreator10::additionalElements. * * @see FeedCreator#additionalElements * @since 1.7.2-mod (modified) * @author Mohammad Hafiz Ismail (mypapit@gmail.com) */ class AtomCreator10 extends FeedCreator { public function AtomCreator10() { $this->contentType = "application/atom+xml"; $this->encoding = "utf-8"; } public function createFeed() { $feed = "encoding."\"?>\n"; $feed.= $this->_createGeneratorComment(); $feed.= $this->_createStylesheetReferences(); $feed.= "language!="") { $feed.= " xml:lang=\"".$this->language."\""; } $feed.= ">\n"; $feed.= " ".htmlspecialchars($this->title)."\n"; $feed.= " ".htmlspecialchars($this->description)."\n"; $feed.= " link)."\"/>\n"; $feed.= " ".htmlspecialchars($this->link)."\n"; $now = new FeedDate(); $feed.= " ".htmlspecialchars($now->iso8601())."\n"; if ($this->editor!="") { $feed.= " \n"; $feed.= " ".$this->editor."\n"; if ($this->editorEmail!="") { $feed.= " ".$this->editorEmail."\n"; } $feed.= " \n"; } if ($this->category!="") { $feed.= " category) . "\" />\n"; } if ($this->copyright!="") { $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."\n"; } $feed.= " ".$this->version()."\n"; $feed.= " syndicationURL). "\" />\n"; $feed.= $this->_createAdditionalElements($this->additionalElements, " "); for ($i=0;$iitems);$i++) { $feed.= " \n"; $feed.= " ".htmlspecialchars(strip_tags($this->items[$i]->title))."\n"; $feed.= " items[$i]->link)."\"/>\n"; if ($this->items[$i]->date=="") { $this->items[$i]->date = time(); } $itemDate = new FeedDate($this->items[$i]->date); $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; $tempguid = $this->items[$i]->link; if ($this->items[$i]->guid!="") { $tempguid = $this->items[$i]->guid; } $feed.= " ". htmlspecialchars($tempguid)."\n"; $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); if ($this->items[$i]->author!="") { $feed.= " \n"; $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; if ($this->items[$i]->authorEmail!="") { $feed.= " ".htmlspecialchars($this->items[$i]->authorEmail)."\n"; } if ($this->items[$i]->authorURL!="") { $feed.= " ".htmlspecialchars($this->items[$i]->authorURL)."\n"; } $feed.= " \n"; } if ($this->items[$i]->category!="") { $feed.= " items[$i]->categoryScheme!="") { $feed.=" scheme=\"".htmlspecialchars($this->items[$i]->categoryScheme)."\" "; } $feed.=" term=\"" . htmlspecialchars($this->items[$i]->category) . "\" />\n"; } if ($this->items[$i]->description!="") { /* * ATOM should have at least summary tag, however this implementation may be inaccurate */ $tempdesc = $this->items[$i]->getDescription(); $temptype=""; if ($this->items[$i]->descriptionHtmlSyndicated){ $temptype=" type=\"html\""; $tempdesc = $this->items[$i]->getDescription(); } if (empty($this->items[$i]->descriptionTruncSize)) { $feed.= " ". $tempdesc ."\n"; } $feed.= " ". $tempdesc ."\n"; } else { $feed.= " no summary\n"; } if ($this->items[$i]->enclosure != NULL) { $feed.=" items[$i]->enclosure->url ."\" type=\"". $this->items[$i]->enclosure->type."\" length=\"". $this->items[$i]->enclosure->length ."\""; if ($this->items[$i]->enclosure->language != ""){ $feed .=" xml:lang=\"". $this->items[$i]->enclosure->language . "\" "; } if ($this->items[$i]->enclosure->title != ""){ $feed .=" title=\"". $this->items[$i]->enclosure->title . "\" "; } $feed .=" /> \n"; } $feed.= " \n"; } $feed.= "\n"; return $feed; } } /** * @package rss * AtomCreator03 is a FeedCreator that implements the atom specification, * as in http://www.intertwingly.net/wiki/pie/FrontPage. * Please note that just by using AtomCreator03 you won't automatically * produce valid atom files. For example, you have to specify either an editor * for the feed or an author for every single feed item. * * Some elements have not been implemented yet. These are (incomplete list): * author URL, item author's email and URL, item contents, alternate links, * other link content types than text/html. Some of them may be created with * AtomCreator03::additionalElements. * * @see FeedCreator#additionalElements * @since 1.6 * @author Kai Blankenhorn , Scott Reynen */ class AtomCreator03 extends FeedCreator { public function AtomCreator03() { $this->contentType = "application/atom+xml"; $this->encoding = "utf-8"; } public function createFeed() { $feed = "encoding."\"?>\n"; $feed.= $this->_createGeneratorComment(); $feed.= $this->_createStylesheetReferences(); $feed.= "language!="") { $feed.= " xml:lang=\"".$this->language."\""; } $feed .= ">\n"; $feed .= " " . htmlspecialchars( $this->title ) . "\n"; $feed .= " " . htmlspecialchars( $this->description ) . "\n"; $feed .= " link ) . "\"/>\n"; $feed .= " " . htmlspecialchars( $this->link ) . "\n"; $now = new FeedDate(); $feed .= " " . htmlspecialchars( $now->iso8601() ) . "\n"; if ($this->editor != "") { $feed .= " \n"; $feed .= " " . $this->editor . "\n"; if ($this->editorEmail != "") { $feed .= " " . $this->editorEmail . "\n"; } $feed .= " \n"; } $feed.= " ".$this->version()."\n"; $feed.= $this->_createAdditionalElements($this->additionalElements, " "); for ($i=0;$iitems);$i++) { $feed.= " \n"; $feed.= " ".htmlspecialchars(strip_tags($this->items[$i]->title))."\n"; $feed.= " items[$i]->link)."\"/>\n"; if ($this->items[$i]->date=="") { $this->items[$i]->date = time(); } $itemDate = new FeedDate($this->items[$i]->date); $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); if ($this->items[$i]->author!="") { $feed.= " \n"; $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; $feed.= " \n"; } if ($this->items[$i]->description!="") { $feed.= " ".htmlspecialchars( strip_tags($this->items[$i]->description) )."\n"; } $feed .= " \n"; } $feed .= "\n"; return $feed; } } /** * @package rss * MBOXCreator is a FeedCreator that implements the mbox format * as described in http://www.qmail.org/man/man5/mbox.html * * @since 1.3 * @author Kai Blankenhorn */ class MBOXCreator extends FeedCreator { public function MBOXCreator() { $this->contentType = "text/plain"; $this->encoding = "ISO-8859-15"; } public function qp_enc($input = "", $line_max = 76) { $hex = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ]; $lines = preg_split("/(?:\r\n|\r|\n)/", $input); $eol = "\r\n"; $escape = "="; $output = ""; foreach ( $lines as $line ) { //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary $linlen = strlen( $line ); $newline = ""; for ( $i = 0; $i < $linlen; $i++ ) { $c = substr( $line, $i, 1 ); $dec = ord( $c ); if (( $dec == 32 ) && ( $i == ( $linlen - 1 ) )) { // convert space at eol only $c = "=20"; } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required $h2 = floor( $dec / 16 ); $h1 = floor( $dec % 16 ); $c = $escape . $hex["$h2"] . $hex["$h1"]; } if (( strlen( $newline ) + strlen( $c ) ) >= $line_max) { // CRLF is not counted $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay $newline = ""; } $newline .= $c; } // end of for $output .= $newline . $eol; } return trim( $output ); } /** * Builds the MBOX contents. * @return string the feed's complete text */ public function createFeed() { for ( $i = 0; $i < count( $this->items ); $i++ ) { $from = ( $this->items[$i]->author != "" ) ? $this->items[$i]->author : $this->title; $itemDate = new FeedDate( $this->items[$i]->date ); $feed = "From " . strtr( MBOXCreator::qp_enc( $from ), " ", "_" ) . " " . date( "D M d H:i:s Y", $itemDate->unix() ) . "\n"; $feed .= "Content-Type: text/plain;\n"; $feed .= " charset=\"" . $this->encoding . "\"\n"; $feed .= "Content-Transfer-Encoding: quoted-printable\n"; $feed .= "Content-Type: text/plain\n"; $feed .= "From: \"" . MBOXCreator::qp_enc( $from ) . "\"\n"; $feed .= "Date: " . $itemDate->rfc822() . "\n"; $feed .= "Subject: " . MBOXCreator::qp_enc( FeedCreator::iTrunc( $this->items[$i]->title, 100 ) ) . "\n"; $feed .= "\n"; $body = chunk_split( MBOXCreator::qp_enc( $this->items[$i]->description ) ); $feed .= preg_replace( "~\nFrom ([^\n]*)(\n?)~", "\n>From $1$2\n", $body ); $feed .= "\n"; $feed .= "\n"; } return $feed; } /** * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types. * @return string the feed cache filename * @since 1.4 */ public function _generateFilename() { $fileInfo = pathinfo($_SERVER["PHP_SELF"]); return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox"; } } /** * @package rss * OPMLCreator is a FeedCreator that implements OPML 1.0. * * @see http://opml.scripting.com/spec * @author Dirk Clemens, Kai Blankenhorn * @since 1.5 */ class OPMLCreator extends FeedCreator { public function OPMLCreator() { $this->encoding = "utf-8"; } public function createFeed() { $feed = "encoding."\"?>\n"; $feed.= $this->_createGeneratorComment(); $feed.= $this->_createStylesheetReferences(); $feed.= "\n"; $feed.= " \n"; $feed.= " ".htmlspecialchars($this->title)."\n"; if ($this->pubDate!="") { $date = new FeedDate($this->pubDate); $feed.= " ".$date->rfc822()."\n"; } if ($this->lastBuildDate != "") { $date = new FeedDate( $this->lastBuildDate ); $feed .= " " . $date->rfc822() . "\n"; } if ($this->editor != "") { $feed .= " " . $this->editor . "\n"; } if ($this->editorEmail != "") { $feed .= " " . $this->editorEmail . "\n"; } $feed .= " \n"; $feed .= " \n"; for ( $i = 0; $i < count( $this->items ); $i++ ) { $feed .= " items[$i]->title, "\n\r", " " ) ) ); $feed .= " title=\"" . $title . "\""; $feed .= " text=\"" . $title . "\""; //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\""; $feed .= " url=\"" . htmlspecialchars( $this->items[$i]->link ) . "\""; if ($this->items[$i]->syndicationURL !="") { $feed.= " xmlUrl=\"" . $this->items[$i]->syndicationURL . "\""; } $feed .= "/>\n"; } $feed .= " \n"; $feed .= "\n"; return $feed; } }