Skip to content

Commit

Permalink
Added RSS & Atom Feeds for PHP
Browse files Browse the repository at this point in the history
  • Loading branch information
TomaszQr committed Nov 2, 2016
1 parent 92b1f69 commit 5b4d42a
Show file tree
Hide file tree
Showing 3 changed files with 274 additions and 4 deletions.
2 changes: 1 addition & 1 deletion config/version.php
@@ -1,6 +1,6 @@
<?php
return [
'appVersion' => '3.4.381',
'appVersion' => '3.4.382',
'patchVersion' => '2016.11.02',
'lib_mPDF' => '0.0.0',
'lib_roundcube' => '0.0.5',
Expand Down
256 changes: 256 additions & 0 deletions libraries/RSSFeeds/Feed.php
@@ -0,0 +1,256 @@
<?php

/**
* RSS for PHP - small and easy-to-use library for consuming an RSS Feed
*
* @copyright Copyright (c) 2008 David Grudl
* @license New BSD License
* @version 1.2
*/
class Feed
{
/** @var int */
public static $cacheExpire = '1 day';

/** @var string */
public static $cacheDir;

/** @var SimpleXMLElement */
protected $xml;


/**
* Loads RSS or Atom feed.
* @param string
* @param string
* @param string
* @return Feed
* @throws FeedException
*/
public static function load($url, $user = NULL, $pass = NULL)
{
$xml = self::loadXml($url, $user, $pass);
if ($xml->channel) {
return self::fromRss($xml);
} else {
return self::fromAtom($xml);
}
}


/**
* Loads RSS feed.
* @param string RSS feed URL
* @param string optional user name
* @param string optional password
* @return Feed
* @throws FeedException
*/
public static function loadRss($url, $user = NULL, $pass = NULL)
{
return self::fromRss(self::loadXml($url, $user, $pass));
}


/**
* Loads Atom feed.
* @param string Atom feed URL
* @param string optional user name
* @param string optional password
* @return Feed
* @throws FeedException
*/
public static function loadAtom($url, $user = NULL, $pass = NULL)
{
return self::fromAtom(self::loadXml($url, $user, $pass));
}


private static function fromRss(SimpleXMLElement $xml)
{
if (!$xml->channel) {
throw new FeedException('Invalid feed.');
}

self::adjustNamespaces($xml);

foreach ($xml->channel->item as $item) {
// converts namespaces to dotted tags
self::adjustNamespaces($item);

// generate 'timestamp' tag
if (isset($item->{'dc:date'})) {
$item->timestamp = strtotime($item->{'dc:date'});
} elseif (isset($item->pubDate)) {
$item->timestamp = strtotime($item->pubDate);
}
}
$feed = new self;
$feed->xml = $xml->channel;
return $feed;
}


private static function fromAtom(SimpleXMLElement $xml)
{
if (!in_array('http://www.w3.org/2005/Atom', $xml->getDocNamespaces(), TRUE)
&& !in_array('http://purl.org/atom/ns#', $xml->getDocNamespaces(), TRUE)
) {
throw new FeedException('Invalid feed.');
}

// generate 'timestamp' tag
foreach ($xml->entry as $entry) {
$entry->timestamp = strtotime($entry->updated);
}
$feed = new self;
$feed->xml = $xml;
return $feed;
}


/**
* Returns property value. Do not call directly.
* @param string tag name
* @return SimpleXMLElement
*/
public function __get($name)
{
return $this->xml->{$name};
}


/**
* Sets value of a property. Do not call directly.
* @param string property name
* @param mixed property value
* @return void
*/
public function __set($name, $value)
{
throw new Exception("Cannot assign to a read-only property '$name'.");
}


/**
* Converts a SimpleXMLElement into an array.
* @param SimpleXMLElement
* @return array
*/
public function toArray(SimpleXMLElement $xml = NULL)
{
if ($xml === NULL) {
$xml = $this->xml;
}

if (!$xml->children()) {
return (string) $xml;
}

$arr = array();
foreach ($xml->children() as $tag => $child) {
if (count($xml->$tag) === 1) {
$arr[$tag] = $this->toArray($child);
} else {
$arr[$tag][] = $this->toArray($child);
}
}

return $arr;
}


/**
* Load XML from cache or HTTP.
* @param string
* @param string
* @param string
* @return SimpleXMLElement
* @throws FeedException
*/
private static function loadXml($url, $user, $pass)
{
$e = self::$cacheExpire;
$cacheFile = self::$cacheDir . '/feed.' . md5(serialize(func_get_args())) . '.xml';

if (self::$cacheDir
&& (time() - @filemtime($cacheFile) <= (is_string($e) ? strtotime($e) - time() : $e))
&& $data = @file_get_contents($cacheFile)
) {
// ok
} elseif ($data = trim(self::httpRequest($url, $user, $pass))) {
if (self::$cacheDir) {
file_put_contents($cacheFile, $data);
}
} elseif (self::$cacheDir && $data = @file_get_contents($cacheFile)) {
// ok
} else {
throw new FeedException('Cannot load feed.');
}

return new SimpleXMLElement($data, LIBXML_NOWARNING | LIBXML_NOERROR);
}


/**
* Process HTTP request.
* @param string
* @param string
* @param string
* @return string|FALSE
* @throws FeedException
*/
private static function httpRequest($url, $user, $pass)
{
if (extension_loaded('curl')) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
if ($user !== NULL || $pass !== NULL) {
curl_setopt($curl, CURLOPT_USERPWD, "$user:$pass");
}
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_TIMEOUT, 20);
curl_setopt($curl, CURLOPT_ENCODING , '');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); // no echo, just return result
if (!ini_get('open_basedir')) {
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE); // sometime is useful :)
}
$result = curl_exec($curl);
return curl_errno($curl) === 0 && curl_getinfo($curl, CURLINFO_HTTP_CODE) === 200
? $result
: FALSE;

} elseif ($user === NULL && $pass === NULL) {
return file_get_contents($url);

} else {
throw new FeedException('PHP extension CURL is not loaded.');
}
}


/**
* Generates better accessible namespaced tags.
* @param SimpleXMLElement
* @return void
*/
private static function adjustNamespaces($el)
{
foreach ($el->getNamespaces(TRUE) as $prefix => $ns) {
$children = $el->children($ns);
foreach ($children as $tag => $content) {
$el->{$prefix . ':' . $tag} = $content;
}
}
}

}



/**
* An exception generated by Feed.
*/
class FeedException extends Exception
{
}
20 changes: 17 additions & 3 deletions licenses/Credits.html
Expand Up @@ -1997,15 +1997,29 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<a class="pull-right homepage_link" href="http://magpierss.sourceforge.net/">homepage</a>
<a class="pull-right homepage_link" href="https://github.com/dg/rss-php">homepage</a>
<a data-toggle="collapse" data-parent="#accordions" href="#p69">
MagpieRSS - v0.72
RSS & Atom Feeds for PHP - [BSD] v1.2
</a>
</div>
</div>
<div id="p69" class="panel-collapse collapse">
<div class="panel-body">
Magpie is distributed under the GPL license.
Copyright (c) 2008, Copyright (c) 2008 David Grudl All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of David Grudl nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</div>
</div>
</div>
Expand Down

0 comments on commit 5b4d42a

Please sign in to comment.