* @since 1.4 */ abstract class FeedCreator extends HtmlDescribable { /** * Mandatory attributes of a feed. */ public $title, $description, $link; public $format = 'BASE'; /** * 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 = ""; public $cssStyleSheet = ""; /** @var FeedItem[] */ public $items = Array(); /** * Generator string */ public $generator = "info@mypapit.net"; /** * This feed's MIME content type. * * @since 1.4 * @access private */ protected $contentType = "application/xml"; /** * This feed's character encoding. * * @since 1.6.1 */ protected $encoding = "UTF-8"; //"ISO-8859-1"; protected $_timeout; # lib/Creator/FeedCreator.php line 238 /** * Any additional elements to include as an associated 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 = Array(); /** * Adds a FeedItem to the feed. * * @param FeedItem $item The FeedItem to add to the feed. */ public function addItem($item) { $this->items[] = $item; } /** * Get the version string for the generator * * @return string */ public 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. * * @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. */ protected 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 */ protected function _createAdditionalElements($elements, $indentString = "") { $ae = ""; if (is_array($elements)) { foreach ($elements AS $key => $value) { $ae .= $indentString."<$key>$value\n"; } } return $ae; } protected function _createStylesheetReferences() { $xml = ""; if (!empty($this->cssStyleSheet)) { $xml .= "cssStyleSheet."\" type=\"text/css\"?>\n"; } if (!empty($this->xslStyleSheet)) { $xml .= "xslStyleSheet."\" type=\"text/xsl\"?>\n"; } return $xml; } /** * Builds the feed's text. * * @return string the feed's complete text */ abstract 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["SCRIPT_NAME"]."\n"; echo FeedCreator::_generateFilename(); would produce: * /rss/latestnews.php * latestnews.xml * * @return string the feed cache filename * @since 1.4 * @access private */ protected function _generateFilename() { $fileInfo = pathinfo($_SERVER["SCRIPT_NAME"]); return substr($fileInfo["basename"], 0, -(strlen($fileInfo["extension"]) + 1)).".xml"; } /** * Send given file to Browser * * @since 1.4 * @param string $filename */ protected 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); header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); if (preg_match('/\.(kml|gpx)$/', $filename)) { header("Content-Disposition: attachment; filename=".basename($filename)); } else { header("Content-Disposition: inline; filename=".basename($filename)); } readfile($filename); exit(); } /** * 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 bool $displayContents 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(); } $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.
"; } } }