forked from RSS-Bridge/rss-bridge
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core: Implement action factory (RSS-Bridge#1002)
- Loading branch information
1 parent
4029e0f
commit 89c2066
Showing
12 changed files
with
705 additions
and
279 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
/** | ||
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and | ||
* Atom feeds for websites that don't have one. | ||
* | ||
* For the full license information, please view the UNLICENSE file distributed | ||
* with this source code. | ||
* | ||
* @package Core | ||
* @license http://unlicense.org/ UNLICENSE | ||
* @link https://github.com/rss-bridge/rss-bridge | ||
*/ | ||
|
||
class DetectAction extends ActionAbstract { | ||
public function execute() { | ||
$targetURL = $this->userData['url'] | ||
or returnClientError('You must specify a url!'); | ||
|
||
$format = $this->userData['format'] | ||
or returnClientError('You must specify a format!'); | ||
|
||
foreach(Bridge::getBridgeNames() as $bridgeName) { | ||
|
||
if(!Bridge::isWhitelisted($bridgeName)) { | ||
continue; | ||
} | ||
|
||
$bridge = Bridge::create($bridgeName); | ||
|
||
if($bridge === false) { | ||
continue; | ||
} | ||
|
||
$bridgeParams = $bridge->detectParameters($targetURL); | ||
|
||
if(is_null($bridgeParams)) { | ||
continue; | ||
} | ||
|
||
$bridgeParams['bridge'] = $bridgeName; | ||
$bridgeParams['format'] = $format; | ||
|
||
header('Location: ?action=display&' . http_build_query($bridgeParams), true, 301); | ||
die(); | ||
|
||
} | ||
|
||
returnClientError('No bridge found for given URL: ' . $targetURL); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
<?php | ||
/** | ||
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and | ||
* Atom feeds for websites that don't have one. | ||
* | ||
* For the full license information, please view the UNLICENSE file distributed | ||
* with this source code. | ||
* | ||
* @package Core | ||
* @license http://unlicense.org/ UNLICENSE | ||
* @link https://github.com/rss-bridge/rss-bridge | ||
*/ | ||
|
||
class DisplayAction extends ActionAbstract { | ||
public function execute() { | ||
$bridge = array_key_exists('bridge', $this->userData) ? $this->userData['bridge'] : null; | ||
|
||
$format = $this->userData['format'] | ||
or returnClientError('You must specify a format!'); | ||
|
||
// DEPRECATED: 'nameFormat' scheme is replaced by 'name' in format parameter values | ||
// this is to keep compatibility until futher complete removal | ||
if(($pos = strpos($format, 'Format')) === (strlen($format) - strlen('Format'))) { | ||
$format = substr($format, 0, $pos); | ||
} | ||
|
||
// whitelist control | ||
if(!Bridge::isWhitelisted($bridge)) { | ||
throw new \Exception('This bridge is not whitelisted', 401); | ||
die; | ||
} | ||
|
||
// Data retrieval | ||
$bridge = Bridge::create($bridge); | ||
|
||
$noproxy = array_key_exists('_noproxy', $this->userData) | ||
&& filter_var($this->userData['_noproxy'], FILTER_VALIDATE_BOOLEAN); | ||
|
||
if(defined('PROXY_URL') && PROXY_BYBRIDGE && $noproxy) { | ||
define('NOPROXY', true); | ||
} | ||
|
||
// Cache timeout | ||
$cache_timeout = -1; | ||
if(array_key_exists('_cache_timeout', $this->userData)) { | ||
|
||
if(!CUSTOM_CACHE_TIMEOUT) { | ||
unset($this->userData['_cache_timeout']); | ||
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) . '?' . http_build_query($this->userData); | ||
header('Location: ' . $uri, true, 301); | ||
die(); | ||
} | ||
|
||
$cache_timeout = filter_var($this->userData['_cache_timeout'], FILTER_VALIDATE_INT); | ||
|
||
} else { | ||
$cache_timeout = $bridge->getCacheTimeout(); | ||
} | ||
|
||
// Remove parameters that don't concern bridges | ||
$bridge_params = array_diff_key( | ||
$this->userData, | ||
array_fill_keys( | ||
array( | ||
'action', | ||
'bridge', | ||
'format', | ||
'_noproxy', | ||
'_cache_timeout', | ||
'_error_time' | ||
), '') | ||
); | ||
|
||
// Remove parameters that don't concern caches | ||
$cache_params = array_diff_key( | ||
$this->userData, | ||
array_fill_keys( | ||
array( | ||
'action', | ||
'format', | ||
'_noproxy', | ||
'_cache_timeout', | ||
'_error_time' | ||
), '') | ||
); | ||
|
||
// Initialize cache | ||
$cache = Cache::create('FileCache'); | ||
$cache->setPath(PATH_CACHE); | ||
$cache->purgeCache(86400); // 24 hours | ||
$cache->setParameters($cache_params); | ||
|
||
$items = array(); | ||
$infos = array(); | ||
$mtime = $cache->getTime(); | ||
|
||
if($mtime !== false | ||
&& (time() - $cache_timeout < $mtime) | ||
&& !Debug::isEnabled()) { // Load cached data | ||
|
||
// Send "Not Modified" response if client supports it | ||
// Implementation based on https://stackoverflow.com/a/10847262 | ||
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { | ||
$stime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); | ||
|
||
if($mtime <= $stime) { // Cached data is older or same | ||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s ', $mtime) . 'GMT', true, 304); | ||
die(); | ||
} | ||
} | ||
|
||
$cached = $cache->loadData(); | ||
|
||
if(isset($cached['items']) && isset($cached['extraInfos'])) { | ||
foreach($cached['items'] as $item) { | ||
$items[] = new \FeedItem($item); | ||
} | ||
|
||
$infos = $cached['extraInfos']; | ||
} | ||
|
||
} else { // Collect new data | ||
|
||
try { | ||
$bridge->setDatas($bridge_params); | ||
$bridge->collectData(); | ||
|
||
$items = $bridge->getItems(); | ||
|
||
// Transform "legacy" items to FeedItems if necessary. | ||
// Remove this code when support for "legacy" items ends! | ||
if(isset($items[0]) && is_array($items[0])) { | ||
$feedItems = array(); | ||
|
||
foreach($items as $item) { | ||
$feedItems[] = new \FeedItem($item); | ||
} | ||
|
||
$items = $feedItems; | ||
} | ||
|
||
$infos = array( | ||
'name' => $bridge->getName(), | ||
'uri' => $bridge->getURI(), | ||
'icon' => $bridge->getIcon() | ||
); | ||
} catch(Error $e) { | ||
error_log($e); | ||
|
||
$item = new \FeedItem(); | ||
|
||
// Create "new" error message every 24 hours | ||
$this->userData['_error_time'] = urlencode((int)(time() / 86400)); | ||
|
||
// Error 0 is a special case (i.e. "trying to get property of non-object") | ||
if($e->getCode() === 0) { | ||
$item->setTitle( | ||
'Bridge encountered an unexpected situation! (' | ||
. $this->userData['_error_time'] | ||
. ')' | ||
); | ||
} else { | ||
$item->setTitle( | ||
'Bridge returned error ' | ||
. $e->getCode() | ||
. '! (' | ||
. $this->userData['_error_time'] | ||
. ')' | ||
); | ||
} | ||
|
||
$item->setURI( | ||
(isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') | ||
. '?' | ||
. http_build_query($this->userData) | ||
); | ||
|
||
$item->setTimestamp(time()); | ||
$item->setContent(buildBridgeException($e, $bridge)); | ||
|
||
$items[] = $item; | ||
} catch(Exception $e) { | ||
error_log($e); | ||
|
||
$item = new \FeedItem(); | ||
|
||
// Create "new" error message every 24 hours | ||
$this->userData['_error_time'] = urlencode((int)(time() / 86400)); | ||
|
||
$item->setURI( | ||
(isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') | ||
. '?' | ||
. http_build_query($this->userData) | ||
); | ||
|
||
$item->setTitle( | ||
'Bridge returned error ' | ||
. $e->getCode() | ||
. '! (' | ||
. $this->userData['_error_time'] | ||
. ')' | ||
); | ||
$item->setTimestamp(time()); | ||
$item->setContent(buildBridgeException($e, $bridge)); | ||
|
||
$items[] = $item; | ||
} | ||
|
||
// Store data in cache | ||
$cache->saveData(array( | ||
'items' => array_map(function($i){ return $i->toArray(); }, $items), | ||
'extraInfos' => $infos | ||
)); | ||
|
||
} | ||
|
||
// Data transformation | ||
try { | ||
$format = Format::create($format); | ||
$format->setItems($items); | ||
$format->setExtraInfos($infos); | ||
$format->setLastModified($cache->getTime()); | ||
$format->display(); | ||
} catch(Error $e) { | ||
error_log($e); | ||
header('Content-Type: text/html', true, $e->getCode()); | ||
die(buildTransformException($e, $bridge)); | ||
} catch(Exception $e) { | ||
error_log($e); | ||
header('Content-Type: text/html', true, $e->getCode()); | ||
die(buildTransformException($e, $bridge)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
/** | ||
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and | ||
* Atom feeds for websites that don't have one. | ||
* | ||
* For the full license information, please view the UNLICENSE file distributed | ||
* with this source code. | ||
* | ||
* @package Core | ||
* @license http://unlicense.org/ UNLICENSE | ||
* @link https://github.com/rss-bridge/rss-bridge | ||
*/ | ||
|
||
class ListAction extends ActionAbstract { | ||
public function execute() { | ||
$list = new StdClass(); | ||
$list->bridges = array(); | ||
$list->total = 0; | ||
|
||
foreach(Bridge::getBridgeNames() as $bridgeName) { | ||
|
||
$bridge = Bridge::create($bridgeName); | ||
|
||
if($bridge === false) { // Broken bridge, show as inactive | ||
|
||
$list->bridges[$bridgeName] = array( | ||
'status' => 'inactive' | ||
); | ||
|
||
continue; | ||
|
||
} | ||
|
||
$status = Bridge::isWhitelisted($bridgeName) ? 'active' : 'inactive'; | ||
|
||
$list->bridges[$bridgeName] = array( | ||
'status' => $status, | ||
'uri' => $bridge->getURI(), | ||
'name' => $bridge->getName(), | ||
'icon' => $bridge->getIcon(), | ||
'parameters' => $bridge->getParameters(), | ||
'maintainer' => $bridge->getMaintainer(), | ||
'description' => $bridge->getDescription() | ||
); | ||
|
||
} | ||
|
||
$list->total = count($list->bridges); | ||
|
||
header('Content-Type: application/json'); | ||
echo json_encode($list, JSON_PRETTY_PRINT); | ||
} | ||
} |
Oops, something went wrong.