diff options
Diffstat (limited to 'formats')
-rw-r--r-- | formats/AtomFormat.php | 356 | ||||
-rw-r--r-- | formats/HtmlFormat.php | 217 | ||||
-rw-r--r-- | formats/JsonFormat.php | 241 | ||||
-rw-r--r-- | formats/MrssFormat.php | 288 | ||||
-rw-r--r-- | formats/PlaintextFormat.php | 31 |
5 files changed, 578 insertions, 555 deletions
diff --git a/formats/AtomFormat.php b/formats/AtomFormat.php index 3d9b7c93..5f564266 100644 --- a/formats/AtomFormat.php +++ b/formats/AtomFormat.php @@ -1,4 +1,5 @@ <?php + /** * AtomFormat - RFC 4287: The Atom Syndication Format * https://tools.ietf.org/html/rfc4287 @@ -6,178 +7,185 @@ * Validator: * https://validator.w3.org/feed/ */ -class AtomFormat extends FormatAbstract{ - const MIME_TYPE = 'application/atom+xml'; - - protected const ATOM_NS = 'http://www.w3.org/2005/Atom'; - protected const MRSS_NS = 'http://search.yahoo.com/mrss/'; - - const LIMIT_TITLE = 140; - - public function stringify(){ - $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; - $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; - $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : ''; - $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; - - $feedUrl = $urlPrefix . $urlHost . $urlRequest; - - $extraInfos = $this->getExtraInfos(); - $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : REPOSITORY; - - $document = new DomDocument('1.0', $this->getCharset()); - $document->formatOutput = true; - $feed = $document->createElementNS(self::ATOM_NS, 'feed'); - $document->appendChild($feed); - $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:media', self::MRSS_NS); - - $title = $document->createElement('title'); - $feed->appendChild($title); - $title->setAttribute('type', 'text'); - $title->appendChild($document->createTextNode($extraInfos['name'])); - - $id = $document->createElement('id'); - $feed->appendChild($id); - $id->appendChild($document->createTextNode($feedUrl)); - - $uriparts = parse_url($uri); - if(!empty($extraInfos['icon'])) { - $iconUrl = $extraInfos['icon']; - } else { - $iconUrl = $uriparts['scheme'] . '://' . $uriparts['host'] . '/favicon.ico'; - } - $icon = $document->createElement('icon'); - $feed->appendChild($icon); - $icon->appendChild($document->createTextNode($iconUrl)); - - $logo = $document->createElement('logo'); - $feed->appendChild($logo); - $logo->appendChild($document->createTextNode($iconUrl)); - - $feedTimestamp = gmdate(DATE_ATOM, $this->lastModified); - $updated = $document->createElement('updated'); - $feed->appendChild($updated); - $updated->appendChild($document->createTextNode($feedTimestamp)); - - // since we can't guarantee that all items have an author, - // a global feed author is mandatory - $feedAuthor = 'RSS-Bridge'; - $author = $document->createElement('author'); - $feed->appendChild($author); - $authorName = $document->createElement('name'); - $author->appendChild($authorName); - $authorName->appendChild($document->createTextNode($feedAuthor)); - - $linkAlternate = $document->createElement('link'); - $feed->appendChild($linkAlternate); - $linkAlternate->setAttribute('rel', 'alternate'); - $linkAlternate->setAttribute('type', 'text/html'); - $linkAlternate->setAttribute('href', $uri); - - $linkSelf = $document->createElement('link'); - $feed->appendChild($linkSelf); - $linkSelf->setAttribute('rel', 'self'); - $linkSelf->setAttribute('type', 'application/atom+xml'); - $linkSelf->setAttribute('href', $feedUrl); - - foreach($this->getItems() as $item) { - $entryTimestamp = $item->getTimestamp(); - $entryTitle = $item->getTitle(); - $entryContent = $item->getContent(); - $entryUri = $item->getURI(); - $entryID = ''; - - if (!empty($item->getUid())) - $entryID = 'urn:sha1:' . $item->getUid(); - - if (empty($entryID)) // Fallback to provided URI - $entryID = $entryUri; - - if (empty($entryID)) // Fallback to title and content - $entryID = 'urn:sha1:' . hash('sha1', $entryTitle . $entryContent); - - if (empty($entryTimestamp)) - $entryTimestamp = $this->lastModified; - - if (empty($entryTitle)) { - $entryTitle = str_replace("\n", ' ', strip_tags($entryContent)); - if (strlen($entryTitle) > self::LIMIT_TITLE) { - $wrapPos = strpos(wordwrap($entryTitle, self::LIMIT_TITLE), "\n"); - $entryTitle = substr($entryTitle, 0, $wrapPos) . '...'; - } - } - - if (empty($entryContent)) - $entryContent = ' '; - - $entry = $document->createElement('entry'); - $feed->appendChild($entry); - - $title = $document->createElement('title'); - $entry->appendChild($title); - $title->setAttribute('type', 'html'); - $title->appendChild($document->createTextNode($entryTitle)); - - $entryTimestamp = gmdate(DATE_ATOM, $entryTimestamp); - $published = $document->createElement('published'); - $entry->appendChild($published); - $published->appendChild($document->createTextNode($entryTimestamp)); - - $updated = $document->createElement('updated'); - $entry->appendChild($updated); - $updated->appendChild($document->createTextNode($entryTimestamp)); - - $id = $document->createElement('id'); - $entry->appendChild($id); - $id->appendChild($document->createTextNode($entryID)); - - if (!empty($entryUri)) { - $entryLinkAlternate = $document->createElement('link'); - $entry->appendChild($entryLinkAlternate); - $entryLinkAlternate->setAttribute('rel', 'alternate'); - $entryLinkAlternate->setAttribute('type', 'text/html'); - $entryLinkAlternate->setAttribute('href', $entryUri); - } - - if (!empty($item->getAuthor())) { - $author = $document->createElement('author'); - $entry->appendChild($author); - $authorName = $document->createElement('name'); - $author->appendChild($authorName); - $authorName->appendChild($document->createTextNode($item->getAuthor())); - } - - $content = $document->createElement('content'); - $content->setAttribute('type', 'html'); - $content->appendChild($document->createTextNode($this->sanitizeHtml($entryContent))); - $entry->appendChild($content); - - foreach($item->getEnclosures() as $enclosure) { - $entryEnclosure = $document->createElement('link'); - $entry->appendChild($entryEnclosure); - $entryEnclosure->setAttribute('rel', 'enclosure'); - $entryEnclosure->setAttribute('type', getMimeType($enclosure)); - $entryEnclosure->setAttribute('href', $enclosure); - } - - foreach($item->getCategories() as $category) { - $entryCategory = $document->createElement('category'); - $entry->appendChild($entryCategory); - $entryCategory->setAttribute('term', $category); - } - - if (!empty($item->thumbnail)) { - $thumbnail = $document->createElementNS(self::MRSS_NS, 'thumbnail'); - $entry->appendChild($thumbnail); - $thumbnail->setAttribute('url', $item->thumbnail); - } - } - - $toReturn = $document->saveXML(); - - // Remove invalid characters - ini_set('mbstring.substitute_character', 'none'); - $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); - return $toReturn; - } +class AtomFormat extends FormatAbstract +{ + const MIME_TYPE = 'application/atom+xml'; + + protected const ATOM_NS = 'http://www.w3.org/2005/Atom'; + protected const MRSS_NS = 'http://search.yahoo.com/mrss/'; + + const LIMIT_TITLE = 140; + + public function stringify() + { + $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; + $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; + $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : ''; + $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; + + $feedUrl = $urlPrefix . $urlHost . $urlRequest; + + $extraInfos = $this->getExtraInfos(); + $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : REPOSITORY; + + $document = new DomDocument('1.0', $this->getCharset()); + $document->formatOutput = true; + $feed = $document->createElementNS(self::ATOM_NS, 'feed'); + $document->appendChild($feed); + $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:media', self::MRSS_NS); + + $title = $document->createElement('title'); + $feed->appendChild($title); + $title->setAttribute('type', 'text'); + $title->appendChild($document->createTextNode($extraInfos['name'])); + + $id = $document->createElement('id'); + $feed->appendChild($id); + $id->appendChild($document->createTextNode($feedUrl)); + + $uriparts = parse_url($uri); + if (!empty($extraInfos['icon'])) { + $iconUrl = $extraInfos['icon']; + } else { + $iconUrl = $uriparts['scheme'] . '://' . $uriparts['host'] . '/favicon.ico'; + } + $icon = $document->createElement('icon'); + $feed->appendChild($icon); + $icon->appendChild($document->createTextNode($iconUrl)); + + $logo = $document->createElement('logo'); + $feed->appendChild($logo); + $logo->appendChild($document->createTextNode($iconUrl)); + + $feedTimestamp = gmdate(DATE_ATOM, $this->lastModified); + $updated = $document->createElement('updated'); + $feed->appendChild($updated); + $updated->appendChild($document->createTextNode($feedTimestamp)); + + // since we can't guarantee that all items have an author, + // a global feed author is mandatory + $feedAuthor = 'RSS-Bridge'; + $author = $document->createElement('author'); + $feed->appendChild($author); + $authorName = $document->createElement('name'); + $author->appendChild($authorName); + $authorName->appendChild($document->createTextNode($feedAuthor)); + + $linkAlternate = $document->createElement('link'); + $feed->appendChild($linkAlternate); + $linkAlternate->setAttribute('rel', 'alternate'); + $linkAlternate->setAttribute('type', 'text/html'); + $linkAlternate->setAttribute('href', $uri); + + $linkSelf = $document->createElement('link'); + $feed->appendChild($linkSelf); + $linkSelf->setAttribute('rel', 'self'); + $linkSelf->setAttribute('type', 'application/atom+xml'); + $linkSelf->setAttribute('href', $feedUrl); + + foreach ($this->getItems() as $item) { + $entryTimestamp = $item->getTimestamp(); + $entryTitle = $item->getTitle(); + $entryContent = $item->getContent(); + $entryUri = $item->getURI(); + $entryID = ''; + + if (!empty($item->getUid())) { + $entryID = 'urn:sha1:' . $item->getUid(); + } + + if (empty($entryID)) { // Fallback to provided URI + $entryID = $entryUri; + } + + if (empty($entryID)) { // Fallback to title and content + $entryID = 'urn:sha1:' . hash('sha1', $entryTitle . $entryContent); + } + + if (empty($entryTimestamp)) { + $entryTimestamp = $this->lastModified; + } + + if (empty($entryTitle)) { + $entryTitle = str_replace("\n", ' ', strip_tags($entryContent)); + if (strlen($entryTitle) > self::LIMIT_TITLE) { + $wrapPos = strpos(wordwrap($entryTitle, self::LIMIT_TITLE), "\n"); + $entryTitle = substr($entryTitle, 0, $wrapPos) . '...'; + } + } + + if (empty($entryContent)) { + $entryContent = ' '; + } + + $entry = $document->createElement('entry'); + $feed->appendChild($entry); + + $title = $document->createElement('title'); + $entry->appendChild($title); + $title->setAttribute('type', 'html'); + $title->appendChild($document->createTextNode($entryTitle)); + + $entryTimestamp = gmdate(DATE_ATOM, $entryTimestamp); + $published = $document->createElement('published'); + $entry->appendChild($published); + $published->appendChild($document->createTextNode($entryTimestamp)); + + $updated = $document->createElement('updated'); + $entry->appendChild($updated); + $updated->appendChild($document->createTextNode($entryTimestamp)); + + $id = $document->createElement('id'); + $entry->appendChild($id); + $id->appendChild($document->createTextNode($entryID)); + + if (!empty($entryUri)) { + $entryLinkAlternate = $document->createElement('link'); + $entry->appendChild($entryLinkAlternate); + $entryLinkAlternate->setAttribute('rel', 'alternate'); + $entryLinkAlternate->setAttribute('type', 'text/html'); + $entryLinkAlternate->setAttribute('href', $entryUri); + } + + if (!empty($item->getAuthor())) { + $author = $document->createElement('author'); + $entry->appendChild($author); + $authorName = $document->createElement('name'); + $author->appendChild($authorName); + $authorName->appendChild($document->createTextNode($item->getAuthor())); + } + + $content = $document->createElement('content'); + $content->setAttribute('type', 'html'); + $content->appendChild($document->createTextNode($this->sanitizeHtml($entryContent))); + $entry->appendChild($content); + + foreach ($item->getEnclosures() as $enclosure) { + $entryEnclosure = $document->createElement('link'); + $entry->appendChild($entryEnclosure); + $entryEnclosure->setAttribute('rel', 'enclosure'); + $entryEnclosure->setAttribute('type', getMimeType($enclosure)); + $entryEnclosure->setAttribute('href', $enclosure); + } + + foreach ($item->getCategories() as $category) { + $entryCategory = $document->createElement('category'); + $entry->appendChild($entryCategory); + $entryCategory->setAttribute('term', $category); + } + + if (!empty($item->thumbnail)) { + $thumbnail = $document->createElementNS(self::MRSS_NS, 'thumbnail'); + $entry->appendChild($thumbnail); + $thumbnail->setAttribute('url', $item->thumbnail); + } + } + + $toReturn = $document->saveXML(); + + // Remove invalid characters + ini_set('mbstring.substitute_character', 'none'); + $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); + return $toReturn; + } } diff --git a/formats/HtmlFormat.php b/formats/HtmlFormat.php index 12b5fc3a..d60c4d81 100644 --- a/formats/HtmlFormat.php +++ b/formats/HtmlFormat.php @@ -1,96 +1,97 @@ <?php -class HtmlFormat extends FormatAbstract { - const MIME_TYPE = 'text/html'; - - public function stringify(){ - $extraInfos = $this->getExtraInfos(); - $title = htmlspecialchars($extraInfos['name']); - $uri = htmlspecialchars($extraInfos['uri']); - $donationUri = htmlspecialchars($extraInfos['donationUri']); - $donationsAllowed = Configuration::getConfig('admin', 'donations'); - - // Dynamically build buttons for all formats (except HTML) - $formatFac = new FormatFactory(); - - $buttons = ''; - $links = ''; - - foreach($formatFac->getFormatNames() as $format) { - if(strcasecmp($format, 'HTML') === 0) { - continue; - } - - $query = str_ireplace('format=Html', 'format=' . $format, htmlentities($_SERVER['QUERY_STRING'])); - $buttons .= $this->buildButton($format, $query) . PHP_EOL; - - $mime = $formatFac->create($format)->getMimeType(); - $links .= $this->buildLink($format, $query, $mime) . PHP_EOL; - } - - if($donationUri !== '' && $donationsAllowed) { - $buttons .= '<a href="' - . $donationUri - . '" target="_blank"><button class="highlight">Donate to maintainer</button></a>' - . PHP_EOL; - $links .= '<link href="' - . $donationUri - . ' target="_blank"" title="Donate to Maintainer" rel="alternate">' - . PHP_EOL; - } - - $entries = ''; - foreach($this->getItems() as $item) { - $entryAuthor = $item->getAuthor() ? '<br /><p class="author">by: ' . $item->getAuthor() . '</p>' : ''; - $entryTitle = $this->sanitizeHtml(strip_tags($item->getTitle())); - $entryUri = $item->getURI() ?: $uri; - - $entryDate = ''; - if($item->getTimestamp()) { - - $entryDate = sprintf( - '<time datetime="%s">%s</time>', - date('Y-m-d H:i:s', $item->getTimestamp()), - date('Y-m-d H:i:s', $item->getTimestamp()) - ); - } - - $entryContent = ''; - if($item->getContent()) { - $entryContent = '<div class="content">' - . $this->sanitizeHtml($item->getContent()) - . '</div>'; - } - - $entryEnclosures = ''; - if(!empty($item->getEnclosures())) { - $entryEnclosures = '<div class="attachments"><p>Attachments:</p>'; - - foreach($item->getEnclosures() as $enclosure) { - $template = '<li class="enclosure"><a href="%s" rel="noopener noreferrer nofollow">%s</a></li>'; - $url = $this->sanitizeHtml($enclosure); - $anchorText = substr($url, strrpos($url, '/') + 1); - - $entryEnclosures .= sprintf($template, $url, $anchorText); - } - - $entryEnclosures .= '</div>'; - } - - $entryCategories = ''; - if(!empty($item->getCategories())) { - $entryCategories = '<div class="categories"><p>Categories:</p>'; - - foreach($item->getCategories() as $category) { - - $entryCategories .= '<li class="category">' - . $this->sanitizeHtml($category) - . '</li>'; - } - - $entryCategories .= '</div>'; - } - - $entries .= <<<EOD + +class HtmlFormat extends FormatAbstract +{ + const MIME_TYPE = 'text/html'; + + public function stringify() + { + $extraInfos = $this->getExtraInfos(); + $title = htmlspecialchars($extraInfos['name']); + $uri = htmlspecialchars($extraInfos['uri']); + $donationUri = htmlspecialchars($extraInfos['donationUri']); + $donationsAllowed = Configuration::getConfig('admin', 'donations'); + + // Dynamically build buttons for all formats (except HTML) + $formatFac = new FormatFactory(); + + $buttons = ''; + $links = ''; + + foreach ($formatFac->getFormatNames() as $format) { + if (strcasecmp($format, 'HTML') === 0) { + continue; + } + + $query = str_ireplace('format=Html', 'format=' . $format, htmlentities($_SERVER['QUERY_STRING'])); + $buttons .= $this->buildButton($format, $query) . PHP_EOL; + + $mime = $formatFac->create($format)->getMimeType(); + $links .= $this->buildLink($format, $query, $mime) . PHP_EOL; + } + + if ($donationUri !== '' && $donationsAllowed) { + $buttons .= '<a href="' + . $donationUri + . '" target="_blank"><button class="highlight">Donate to maintainer</button></a>' + . PHP_EOL; + $links .= '<link href="' + . $donationUri + . ' target="_blank"" title="Donate to Maintainer" rel="alternate">' + . PHP_EOL; + } + + $entries = ''; + foreach ($this->getItems() as $item) { + $entryAuthor = $item->getAuthor() ? '<br /><p class="author">by: ' . $item->getAuthor() . '</p>' : ''; + $entryTitle = $this->sanitizeHtml(strip_tags($item->getTitle())); + $entryUri = $item->getURI() ?: $uri; + + $entryDate = ''; + if ($item->getTimestamp()) { + $entryDate = sprintf( + '<time datetime="%s">%s</time>', + date('Y-m-d H:i:s', $item->getTimestamp()), + date('Y-m-d H:i:s', $item->getTimestamp()) + ); + } + + $entryContent = ''; + if ($item->getContent()) { + $entryContent = '<div class="content">' + . $this->sanitizeHtml($item->getContent()) + . '</div>'; + } + + $entryEnclosures = ''; + if (!empty($item->getEnclosures())) { + $entryEnclosures = '<div class="attachments"><p>Attachments:</p>'; + + foreach ($item->getEnclosures() as $enclosure) { + $template = '<li class="enclosure"><a href="%s" rel="noopener noreferrer nofollow">%s</a></li>'; + $url = $this->sanitizeHtml($enclosure); + $anchorText = substr($url, strrpos($url, '/') + 1); + + $entryEnclosures .= sprintf($template, $url, $anchorText); + } + + $entryEnclosures .= '</div>'; + } + + $entryCategories = ''; + if (!empty($item->getCategories())) { + $entryCategories = '<div class="categories"><p>Categories:</p>'; + + foreach ($item->getCategories() as $category) { + $entryCategories .= '<li class="category">' + . $this->sanitizeHtml($category) + . '</li>'; + } + + $entryCategories .= '</div>'; + } + + $entries .= <<<EOD <section class="feeditem"> <h2><a class="itemtitle" href="{$entryUri}">{$entryTitle}</a></h2> @@ -102,12 +103,12 @@ class HtmlFormat extends FormatAbstract { </section> EOD; - } + } - $charset = $this->getCharset(); + $charset = $this->getCharset(); - /* Data are prepared, now let's begin the "MAGIE !!!" */ - $toReturn = <<<EOD + /* Data are prepared, now let's begin the "MAGIE !!!" */ + $toReturn = <<<EOD <!DOCTYPE html> <html> <head> @@ -130,22 +131,24 @@ EOD; </html> EOD; - // Remove invalid characters - ini_set('mbstring.substitute_character', 'none'); - $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); - return $toReturn; - } + // Remove invalid characters + ini_set('mbstring.substitute_character', 'none'); + $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); + return $toReturn; + } - private function buildButton($format, $query) { - return <<<EOD + private function buildButton($format, $query) + { + return <<<EOD <a href="./?{$query}"><button class="rss-feed">{$format}</button></a> EOD; - } + } - private function buildLink($format, $query, $mime) { - return <<<EOD + private function buildLink($format, $query, $mime) + { + return <<<EOD <link href="./?{$query}" title="{$format}" rel="alternate" type="{$mime}"> EOD; - } + } } diff --git a/formats/JsonFormat.php b/formats/JsonFormat.php index 1efc87fe..3b2a29ab 100644 --- a/formats/JsonFormat.php +++ b/formats/JsonFormat.php @@ -1,4 +1,5 @@ <?php + /** * JsonFormat - JSON Feed Version 1 * https://jsonfeed.org/version/1 @@ -7,122 +8,126 @@ * https://validator.jsonfeed.org * https://github.com/vigetlabs/json-feed-validator */ -class JsonFormat extends FormatAbstract { - const MIME_TYPE = 'application/json'; - - const VENDOR_EXCLUDES = array( - 'author', - 'title', - 'uri', - 'timestamp', - 'content', - 'enclosures', - 'categories', - 'uid', - ); - - public function stringify(){ - $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; - $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; - $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : ''; - $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; - - $extraInfos = $this->getExtraInfos(); - - $data = array( - 'version' => 'https://jsonfeed.org/version/1', - 'title' => (!empty($extraInfos['name'])) ? $extraInfos['name'] : $urlHost, - 'home_page_url' => (!empty($extraInfos['uri'])) ? $extraInfos['uri'] : REPOSITORY, - 'feed_url' => $urlPrefix . $urlHost . $urlRequest - ); - - if (!empty($extraInfos['icon'])) { - $data['icon'] = $extraInfos['icon']; - $data['favicon'] = $extraInfos['icon']; - } - - $items = array(); - foreach ($this->getItems() as $item) { - $entry = array(); - - $entryAuthor = $item->getAuthor(); - $entryTitle = $item->getTitle(); - $entryUri = $item->getURI(); - $entryTimestamp = $item->getTimestamp(); - $entryContent = $item->getContent() ? $this->sanitizeHtml($item->getContent()) : ''; - $entryEnclosures = $item->getEnclosures(); - $entryCategories = $item->getCategories(); - - $vendorFields = $item->toArray(); - foreach (self::VENDOR_EXCLUDES as $key) { - unset($vendorFields[$key]); - } - - $entry['id'] = $item->getUid(); - - if (empty($entry['id'])) { - $entry['id'] = $entryUri; - } - - if (!empty($entryTitle)) { - $entry['title'] = $entryTitle; - } - if (!empty($entryAuthor)) { - $entry['author'] = array( - 'name' => $entryAuthor - ); - } - if (!empty($entryTimestamp)) { - $entry['date_modified'] = gmdate(DATE_ATOM, $entryTimestamp); - } - if (!empty($entryUri)) { - $entry['url'] = $entryUri; - } - if (!empty($entryContent)) { - if ($this->isHTML($entryContent)) { - $entry['content_html'] = $entryContent; - } else { - $entry['content_text'] = $entryContent; - } - } - if (!empty($entryEnclosures)) { - $entry['attachments'] = array(); - foreach ($entryEnclosures as $enclosure) { - $entry['attachments'][] = array( - 'url' => $enclosure, - 'mime_type' => getMimeType($enclosure) - ); - } - } - if (!empty($entryCategories)) { - $entry['tags'] = array(); - foreach ($entryCategories as $category) { - $entry['tags'][] = $category; - } - } - if (!empty($vendorFields)) { - $entry['_rssbridge'] = $vendorFields; - } - - if (empty($entry['id'])) - $entry['id'] = hash('sha1', $entryTitle . $entryContent); - - $items[] = $entry; - } - $data['items'] = $items; - - /** - * The intention here is to discard non-utf8 byte sequences. - * But the JSON_PARTIAL_OUTPUT_ON_ERROR also discards lots of other errors. - * So consider this a hack. - * Switch to JSON_INVALID_UTF8_IGNORE when PHP 7.2 is the latest platform requirement. - */ - $json = json_encode($data, JSON_PRETTY_PRINT | JSON_PARTIAL_OUTPUT_ON_ERROR); - - return $json; - } - - private function isHTML($text) { - return (strlen(strip_tags($text)) != strlen($text)); - } +class JsonFormat extends FormatAbstract +{ + const MIME_TYPE = 'application/json'; + + const VENDOR_EXCLUDES = [ + 'author', + 'title', + 'uri', + 'timestamp', + 'content', + 'enclosures', + 'categories', + 'uid', + ]; + + public function stringify() + { + $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; + $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; + $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : ''; + $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; + + $extraInfos = $this->getExtraInfos(); + + $data = [ + 'version' => 'https://jsonfeed.org/version/1', + 'title' => (!empty($extraInfos['name'])) ? $extraInfos['name'] : $urlHost, + 'home_page_url' => (!empty($extraInfos['uri'])) ? $extraInfos['uri'] : REPOSITORY, + 'feed_url' => $urlPrefix . $urlHost . $urlRequest + ]; + + if (!empty($extraInfos['icon'])) { + $data['icon'] = $extraInfos['icon']; + $data['favicon'] = $extraInfos['icon']; + } + + $items = []; + foreach ($this->getItems() as $item) { + $entry = []; + + $entryAuthor = $item->getAuthor(); + $entryTitle = $item->getTitle(); + $entryUri = $item->getURI(); + $entryTimestamp = $item->getTimestamp(); + $entryContent = $item->getContent() ? $this->sanitizeHtml($item->getContent()) : ''; + $entryEnclosures = $item->getEnclosures(); + $entryCategories = $item->getCategories(); + + $vendorFields = $item->toArray(); + foreach (self::VENDOR_EXCLUDES as $key) { + unset($vendorFields[$key]); + } + + $entry['id'] = $item->getUid(); + + if (empty($entry['id'])) { + $entry['id'] = $entryUri; + } + + if (!empty($entryTitle)) { + $entry['title'] = $entryTitle; + } + if (!empty($entryAuthor)) { + $entry['author'] = [ + 'name' => $entryAuthor + ]; + } + if (!empty($entryTimestamp)) { + $entry['date_modified'] = gmdate(DATE_ATOM, $entryTimestamp); + } + if (!empty($entryUri)) { + $entry['url'] = $entryUri; + } + if (!empty($entryContent)) { + if ($this->isHTML($entryContent)) { + $entry['content_html'] = $entryContent; + } else { + $entry['content_text'] = $entryContent; + } + } + if (!empty($entryEnclosures)) { + $entry['attachments'] = []; + foreach ($entryEnclosures as $enclosure) { + $entry['attachments'][] = [ + 'url' => $enclosure, + 'mime_type' => getMimeType($enclosure) + ]; + } + } + if (!empty($entryCategories)) { + $entry['tags'] = []; + foreach ($entryCategories as $category) { + $entry['tags'][] = $category; + } + } + if (!empty($vendorFields)) { + $entry['_rssbridge'] = $vendorFields; + } + + if (empty($entry['id'])) { + $entry['id'] = hash('sha1', $entryTitle . $entryContent); + } + + $items[] = $entry; + } + $data['items'] = $items; + + /** + * The intention here is to discard non-utf8 byte sequences. + * But the JSON_PARTIAL_OUTPUT_ON_ERROR also discards lots of other errors. + * So consider this a hack. + * Switch to JSON_INVALID_UTF8_IGNORE when PHP 7.2 is the latest platform requirement. + */ + $json = json_encode($data, JSON_PRETTY_PRINT | JSON_PARTIAL_OUTPUT_ON_ERROR); + + return $json; + } + + private function isHTML($text) + { + return (strlen(strip_tags($text)) != strlen($text)); + } } diff --git a/formats/MrssFormat.php b/formats/MrssFormat.php index 386b7d37..45c2181f 100644 --- a/formats/MrssFormat.php +++ b/formats/MrssFormat.php @@ -1,4 +1,5 @@ <?php + /** * MrssFormat - RSS 2.0 + Media RSS * http://www.rssboard.org/rss-specification @@ -24,146 +25,149 @@ * - Since the Media RSS extension has its own namespace, the output is a valid * RSS 2.0 feed that works with feed readers that don't support the extension. */ -class MrssFormat extends FormatAbstract { - const MIME_TYPE = 'application/rss+xml'; - - protected const ATOM_NS = 'http://www.w3.org/2005/Atom'; - protected const MRSS_NS = 'http://search.yahoo.com/mrss/'; - - const ALLOWED_IMAGE_EXT = array( - '.gif', '.jpg', '.png' - ); - - public function stringify(){ - $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; - $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; - $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : ''; - $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; - - $feedUrl = $urlPrefix . $urlHost . $urlRequest; - - $extraInfos = $this->getExtraInfos(); - $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : REPOSITORY; - - $document = new DomDocument('1.0', $this->getCharset()); - $document->formatOutput = true; - $feed = $document->createElement('rss'); - $document->appendChild($feed); - $feed->setAttribute('version', '2.0'); - $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:atom', self::ATOM_NS); - $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:media', self::MRSS_NS); - - $channel = $document->createElement('channel'); - $feed->appendChild($channel); - - $title = $extraInfos['name']; - $channelTitle = $document->createElement('title'); - $channel->appendChild($channelTitle); - $channelTitle->appendChild($document->createTextNode($title)); - - $link = $document->createElement('link'); - $channel->appendChild($link); - $link->appendChild($document->createTextNode($uri)); - - $description = $document->createElement('description'); - $channel->appendChild($description); - $description->appendChild($document->createTextNode($extraInfos['name'])); - - $icon = $extraInfos['icon']; - if (!empty($icon) && in_array(substr($icon, -4), self::ALLOWED_IMAGE_EXT)) { - $feedImage = $document->createElement('image'); - $channel->appendChild($feedImage); - $iconUrl = $document->createElement('url'); - $iconUrl->appendChild($document->createTextNode($icon)); - $feedImage->appendChild($iconUrl); - $iconTitle = $document->createElement('title'); - $iconTitle->appendChild($document->createTextNode($title)); - $feedImage->appendChild($iconTitle); - $iconLink = $document->createElement('link'); - $iconLink->appendChild($document->createTextNode($uri)); - $feedImage->appendChild($iconLink); - } - - $linkAlternate = $document->createElementNS(self::ATOM_NS, 'link'); - $channel->appendChild($linkAlternate); - $linkAlternate->setAttribute('rel', 'alternate'); - $linkAlternate->setAttribute('type', 'text/html'); - $linkAlternate->setAttribute('href', $uri); - - $linkSelf = $document->createElementNS(self::ATOM_NS, 'link'); - $channel->appendChild($linkSelf); - $linkSelf->setAttribute('rel', 'self'); - $linkSelf->setAttribute('type', 'application/atom+xml'); - $linkSelf->setAttribute('href', $feedUrl); - - foreach($this->getItems() as $item) { - $itemTimestamp = $item->getTimestamp(); - $itemTitle = $item->getTitle(); - $itemUri = $item->getURI(); - $itemContent = $item->getContent() ? $this->sanitizeHtml($item->getContent()) : ''; - $entryID = $item->getUid(); - $isPermaLink = 'false'; - - if (empty($entryID) && !empty($itemUri)) { // Fallback to provided URI - $entryID = $itemUri; - $isPermaLink = 'true'; - } - - if (empty($entryID)) // Fallback to title and content - $entryID = hash('sha1', $itemTitle . $itemContent); - - $entry = $document->createElement('item'); - $channel->appendChild($entry); - - if (!empty($itemTitle)) { - $entryTitle = $document->createElement('title'); - $entry->appendChild($entryTitle); - $entryTitle->appendChild($document->createTextNode($itemTitle)); - } - - if (!empty($itemUri)) { - $entryLink = $document->createElement('link'); - $entry->appendChild($entryLink); - $entryLink->appendChild($document->createTextNode($itemUri)); - } - - $entryGuid = $document->createElement('guid'); - $entryGuid->setAttribute('isPermaLink', $isPermaLink); - $entry->appendChild($entryGuid); - $entryGuid->appendChild($document->createTextNode($entryID)); - - if (!empty($itemTimestamp)) { - $entryPublished = $document->createElement('pubDate'); - $entry->appendChild($entryPublished); - $entryPublished->appendChild($document->createTextNode(gmdate(DATE_RFC2822, $itemTimestamp))); - } - - if (!empty($itemContent)) { - $entryDescription = $document->createElement('description'); - $entry->appendChild($entryDescription); - $entryDescription->appendChild($document->createTextNode($itemContent)); - } - - foreach($item->getEnclosures() as $enclosure) { - $entryEnclosure = $document->createElementNS(self::MRSS_NS, 'content'); - $entry->appendChild($entryEnclosure); - $entryEnclosure->setAttribute('url', $enclosure); - $entryEnclosure->setAttribute('type', getMimeType($enclosure)); - } - - $entryCategories = ''; - foreach($item->getCategories() as $category) { - $entryCategory = $document->createElement('category'); - $entry->appendChild($entryCategory); - $entryCategory->appendChild($document->createTextNode($category)); - } - } - - $toReturn = $document->saveXML(); - - // Remove invalid non-UTF8 characters - ini_set('mbstring.substitute_character', 'none'); - $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); - return $toReturn; - } +class MrssFormat extends FormatAbstract +{ + const MIME_TYPE = 'application/rss+xml'; + + protected const ATOM_NS = 'http://www.w3.org/2005/Atom'; + protected const MRSS_NS = 'http://search.yahoo.com/mrss/'; + + const ALLOWED_IMAGE_EXT = [ + '.gif', '.jpg', '.png' + ]; + + public function stringify() + { + $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; + $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; + $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : ''; + $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; + + $feedUrl = $urlPrefix . $urlHost . $urlRequest; + + $extraInfos = $this->getExtraInfos(); + $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : REPOSITORY; + + $document = new DomDocument('1.0', $this->getCharset()); + $document->formatOutput = true; + $feed = $document->createElement('rss'); + $document->appendChild($feed); + $feed->setAttribute('version', '2.0'); + $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:atom', self::ATOM_NS); + $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:media', self::MRSS_NS); + + $channel = $document->createElement('channel'); + $feed->appendChild($channel); + + $title = $extraInfos['name']; + $channelTitle = $document->createElement('title'); + $channel->appendChild($channelTitle); + $channelTitle->appendChild($document->createTextNode($title)); + + $link = $document->createElement('link'); + $channel->appendChild($link); + $link->appendChild($document->createTextNode($uri)); + + $description = $document->createElement('description'); + $channel->appendChild($description); + $description->appendChild($document->createTextNode($extraInfos['name'])); + + $icon = $extraInfos['icon']; + if (!empty($icon) && in_array(substr($icon, -4), self::ALLOWED_IMAGE_EXT)) { + $feedImage = $document->createElement('image'); + $channel->appendChild($feedImage); + $iconUrl = $document->createElement('url'); + $iconUrl->appendChild($document->createTextNode($icon)); + $feedImage->appendChild($iconUrl); + $iconTitle = $document->createElement('title'); + $iconTitle->appendChild($document->createTextNode($title)); + $feedImage->appendChild($iconTitle); + $iconLink = $document->createElement('link'); + $iconLink->appendChild($document->createTextNode($uri)); + $feedImage->appendChild($iconLink); + } + + $linkAlternate = $document->createElementNS(self::ATOM_NS, 'link'); + $channel->appendChild($linkAlternate); + $linkAlternate->setAttribute('rel', 'alternate'); + $linkAlternate->setAttribute('type', 'text/html'); + $linkAlternate->setAttribute('href', $uri); + + $linkSelf = $document->createElementNS(self::ATOM_NS, 'link'); + $channel->appendChild($linkSelf); + $linkSelf->setAttribute('rel', 'self'); + $linkSelf->setAttribute('type', 'application/atom+xml'); + $linkSelf->setAttribute('href', $feedUrl); + + foreach ($this->getItems() as $item) { + $itemTimestamp = $item->getTimestamp(); + $itemTitle = $item->getTitle(); + $itemUri = $item->getURI(); + $itemContent = $item->getContent() ? $this->sanitizeHtml($item->getContent()) : ''; + $entryID = $item->getUid(); + $isPermaLink = 'false'; + + if (empty($entryID) && !empty($itemUri)) { // Fallback to provided URI + $entryID = $itemUri; + $isPermaLink = 'true'; + } + + if (empty($entryID)) { // Fallback to title and content + $entryID = hash('sha1', $itemTitle . $itemContent); + } + + $entry = $document->createElement('item'); + $channel->appendChild($entry); + + if (!empty($itemTitle)) { + $entryTitle = $document->createElement('title'); + $entry->appendChild($entryTitle); + $entryTitle->appendChild($document->createTextNode($itemTitle)); + } + + if (!empty($itemUri)) { + $entryLink = $document->createElement('link'); + $entry->appendChild($entryLink); + $entryLink->appendChild($document->createTextNode($itemUri)); + } + + $entryGuid = $document->createElement('guid'); + $entryGuid->setAttribute('isPermaLink', $isPermaLink); + $entry->appendChild($entryGuid); + $entryGuid->appendChild($document->createTextNode($entryID)); + + if (!empty($itemTimestamp)) { + $entryPublished = $document->createElement('pubDate'); + $entry->appendChild($entryPublished); + $entryPublished->appendChild($document->createTextNode(gmdate(DATE_RFC2822, $itemTimestamp))); + } + + if (!empty($itemContent)) { + $entryDescription = $document->createElement('description'); + $entry->appendChild($entryDescription); + $entryDescription->appendChild($document->createTextNode($itemContent)); + } + + foreach ($item->getEnclosures() as $enclosure) { + $entryEnclosure = $document->createElementNS(self::MRSS_NS, 'content'); + $entry->appendChild($entryEnclosure); + $entryEnclosure->setAttribute('url', $enclosure); + $entryEnclosure->setAttribute('type', getMimeType($enclosure)); + } + + $entryCategories = ''; + foreach ($item->getCategories() as $category) { + $entryCategory = $document->createElement('category'); + $entry->appendChild($entryCategory); + $entryCategory->appendChild($document->createTextNode($category)); + } + } + + $toReturn = $document->saveXML(); + + // Remove invalid non-UTF8 characters + ini_set('mbstring.substitute_character', 'none'); + $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); + return $toReturn; + } } diff --git a/formats/PlaintextFormat.php b/formats/PlaintextFormat.php index a1ef9e7f..a1e125c7 100644 --- a/formats/PlaintextFormat.php +++ b/formats/PlaintextFormat.php @@ -1,24 +1,27 @@ <?php + /** * Plaintext * Returns $this->items as raw php data. */ -class PlaintextFormat extends FormatAbstract { - const MIME_TYPE = 'text/plain'; +class PlaintextFormat extends FormatAbstract +{ + const MIME_TYPE = 'text/plain'; - public function stringify(){ - $items = $this->getItems(); - $data = array(); + public function stringify() + { + $items = $this->getItems(); + $data = []; - foreach($items as $item) { - $data[] = $item->toArray(); - } + foreach ($items as $item) { + $data[] = $item->toArray(); + } - $toReturn = print_r($data, true); + $toReturn = print_r($data, true); - // Remove invalid non-UTF8 characters - ini_set('mbstring.substitute_character', 'none'); - $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); - return $toReturn; - } + // Remove invalid non-UTF8 characters + ini_set('mbstring.substitute_character', 'none'); + $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8'); + return $toReturn; + } } |