index.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. require_once __DIR__ . '/lib/RssBridge.php';
  3. include __DIR__ . '/config.defines.php';
  4. if(!defined('PHP_VERSION_REQUIRED'))
  5. define('PHP_VERSION_REQUIRED', '5.6.0');
  6. // Specify directory for cached files (using FileCache)
  7. if(!defined('CACHE_DIR'))
  8. define('CACHE_DIR', __DIR__ . '/cache');
  9. // Specify path for whitelist file
  10. if(!defined('WHITELIST_FILE'))
  11. define('WHITELIST_FILE', __DIR__ . '/whitelist.txt');
  12. Configuration::verifyInstallation();
  13. Configuration::loadConfiguration();
  14. Authentication::showPromptIfNeeded();
  15. date_default_timezone_set('UTC');
  16. error_reporting(0);
  17. /*
  18. Move the CLI arguments to the $_GET array, in order to be able to use
  19. rss-bridge from the command line
  20. */
  21. parse_str(implode('&', array_slice($argv, 1)), $cliArgs);
  22. $params = array_merge($_GET, $cliArgs);
  23. /*
  24. Create a file named 'DEBUG' for enabling debug mode.
  25. For further security, you may put whitelisted IP addresses in the file,
  26. one IP per line. Empty file allows anyone(!).
  27. Debugging allows displaying PHP error messages and bypasses the cache: this
  28. can allow a malicious client to retrieve data about your server and hammer
  29. a provider throught your rss-bridge instance.
  30. */
  31. if(file_exists('DEBUG')) {
  32. $debug_whitelist = trim(file_get_contents('DEBUG'));
  33. $debug_enabled = empty($debug_whitelist)
  34. || in_array($_SERVER['REMOTE_ADDR'], explode("\n", $debug_whitelist));
  35. if($debug_enabled) {
  36. ini_set('display_errors', '1');
  37. error_reporting(E_ALL);
  38. define('DEBUG', true);
  39. }
  40. }
  41. // FIXME : beta test UA spoofing, please report any blacklisting by PHP-fopen-unfriendly websites
  42. $userAgent = 'Mozilla/5.0(X11; Linux x86_64; rv:30.0)';
  43. $userAgent .= ' Gecko/20121202 Firefox/30.0(rss-bridge/0.1;';
  44. $userAgent .= '+https://github.com/RSS-Bridge/rss-bridge)';
  45. ini_set('user_agent', $userAgent);
  46. // default whitelist
  47. $whitelist_default = array(
  48. 'BandcampBridge',
  49. 'CryptomeBridge',
  50. 'DansTonChatBridge',
  51. 'DuckDuckGoBridge',
  52. 'FacebookBridge',
  53. 'FlickrExploreBridge',
  54. 'GooglePlusPostBridge',
  55. 'GoogleSearchBridge',
  56. 'IdenticaBridge',
  57. 'InstagramBridge',
  58. 'OpenClassroomsBridge',
  59. 'PinterestBridge',
  60. 'ScmbBridge',
  61. 'TwitterBridge',
  62. 'WikipediaBridge',
  63. 'YoutubeBridge');
  64. try {
  65. Bridge::setDir(__DIR__ . '/bridges/');
  66. Format::setDir(__DIR__ . '/formats/');
  67. Cache::setDir(__DIR__ . '/caches/');
  68. if(!file_exists(WHITELIST_FILE)) {
  69. $whitelist_selection = $whitelist_default;
  70. $whitelist_write = implode("\n", $whitelist_default);
  71. file_put_contents(WHITELIST_FILE, $whitelist_write);
  72. } else {
  73. $whitelist_file_content = file_get_contents(WHITELIST_FILE);
  74. if($whitelist_file_content != "*\n") {
  75. $whitelist_selection = explode("\n", $whitelist_file_content);
  76. } else {
  77. $whitelist_selection = Bridge::listBridges();
  78. }
  79. // Prepare for case-insensitive match
  80. $whitelist_selection = array_map('strtolower', $whitelist_selection);
  81. }
  82. $showInactive = filter_input(INPUT_GET, 'show_inactive', FILTER_VALIDATE_BOOLEAN);
  83. $action = array_key_exists('action', $params) ? $params['action'] : null;
  84. $bridge = array_key_exists('bridge', $params) ? $params['bridge'] : null;
  85. // Return list of bridges as JSON formatted text
  86. if($action === 'list') {
  87. $list = new StdClass();
  88. $list->bridges = array();
  89. $list->total = 0;
  90. foreach(Bridge::listBridges() as $bridgeName) {
  91. $bridge = Bridge::create($bridgeName);
  92. if($bridge === false) { // Broken bridge, show as inactive
  93. $list->bridges[$bridgeName] = array(
  94. 'status' => 'inactive'
  95. );
  96. continue;
  97. }
  98. $status = Bridge::isWhitelisted($whitelist_selection, strtolower($bridgeName)) ? 'active' : 'inactive';
  99. $list->bridges[$bridgeName] = array(
  100. 'status' => $status,
  101. 'uri' => $bridge->getURI(),
  102. 'name' => $bridge->getName(),
  103. 'parameters' => $bridge->getParameters(),
  104. 'maintainer' => $bridge->getMaintainer(),
  105. 'description' => $bridge->getDescription()
  106. );
  107. }
  108. $list->total = count($list->bridges);
  109. header('Content-Type: application/json');
  110. echo json_encode($list, JSON_PRETTY_PRINT);
  111. } elseif($action === 'display' && !empty($bridge)) {
  112. // DEPRECATED: 'nameBridge' scheme is replaced by 'name' in bridge parameter values
  113. // this is to keep compatibility until futher complete removal
  114. if(($pos = strpos($bridge, 'Bridge')) === (strlen($bridge) - strlen('Bridge'))) {
  115. $bridge = substr($bridge, 0, $pos);
  116. }
  117. $format = $params['format']
  118. or returnClientError('You must specify a format!');
  119. // DEPRECATED: 'nameFormat' scheme is replaced by 'name' in format parameter values
  120. // this is to keep compatibility until futher complete removal
  121. if(($pos = strpos($format, 'Format')) === (strlen($format) - strlen('Format'))) {
  122. $format = substr($format, 0, $pos);
  123. }
  124. // whitelist control
  125. if(!Bridge::isWhitelisted($whitelist_selection, strtolower($bridge))) {
  126. throw new \HttpException('This bridge is not whitelisted', 401);
  127. die;
  128. }
  129. // Data retrieval
  130. $bridge = Bridge::create($bridge);
  131. $noproxy = array_key_exists('_noproxy', $params) && filter_var($params['_noproxy'], FILTER_VALIDATE_BOOLEAN);
  132. if(defined('PROXY_URL') && PROXY_BYBRIDGE && $noproxy) {
  133. define('NOPROXY', true);
  134. }
  135. // Custom cache timeout
  136. $cache_timeout = -1;
  137. if(array_key_exists('_cache_timeout', $params)) {
  138. if(!CUSTOM_CACHE_TIMEOUT) {
  139. throw new \HttpException('This server doesn\'t support "_cache_timeout"!');
  140. }
  141. $cache_timeout = filter_var($params['_cache_timeout'], FILTER_VALIDATE_INT);
  142. }
  143. // Initialize cache
  144. $cache = Cache::create('FileCache');
  145. $cache->setPath(CACHE_DIR);
  146. $cache->purgeCache(86400); // 24 hours
  147. $cache->setParameters($params);
  148. unset($params['action']);
  149. unset($params['bridge']);
  150. unset($params['format']);
  151. unset($params['_noproxy']);
  152. unset($params['_cache_timeout']);
  153. // Load cache & data
  154. try {
  155. $bridge->setCache($cache);
  156. $bridge->setCacheTimeout($cache_timeout);
  157. $bridge->setDatas($params);
  158. } catch(Error $e) {
  159. http_response_code($e->getCode());
  160. header('Content-Type: text/html');
  161. die(buildBridgeException($e, $bridge));
  162. } catch(Exception $e) {
  163. http_response_code($e->getCode());
  164. header('Content-Type: text/html');
  165. die(buildBridgeException($e, $bridge));
  166. }
  167. // Data transformation
  168. try {
  169. $format = Format::create($format);
  170. $format->setItems($bridge->getItems());
  171. $format->setExtraInfos($bridge->getExtraInfos());
  172. $format->display();
  173. } catch(Error $e) {
  174. http_response_code($e->getCode());
  175. header('Content-Type: text/html');
  176. die(buildTransformException($e, $bridge));
  177. } catch(Exception $e) {
  178. http_response_code($e->getCode());
  179. header('Content-Type: text/html');
  180. die(buildBridgeException($e, $bridge));
  181. }
  182. } else {
  183. echo BridgeList::create($whitelist_selection, $showInactive);
  184. }
  185. } catch(HttpException $e) {
  186. http_response_code($e->getCode());
  187. header('Content-Type: text/plain');
  188. die($e->getMessage());
  189. } catch(\Exception $e) {
  190. die($e->getMessage());
  191. }