chore: add tools for manually administrating the configured cache (#3867)

This commit is contained in:
Dag 2024-01-09 20:33:35 +01:00 committed by GitHub
parent 3ce94409ab
commit 0bf5dbbc0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 95 additions and 45 deletions

View file

@ -251,7 +251,7 @@ Browse http://localhost:3000/
[![Deploy to Cloudron](https://cloudron.io/img/button.svg)](https://www.cloudron.io/store/com.rssbridgeapp.cloudronapp.html) [![Deploy to Cloudron](https://cloudron.io/img/button.svg)](https://www.cloudron.io/store/com.rssbridgeapp.cloudronapp.html)
[![Run on PikaPods](https://www.pikapods.com/static/run-button.svg)](https://www.pikapods.com/pods?run=rssbridge) [![Run on PikaPods](https://www.pikapods.com/static/run-button.svg)](https://www.pikapods.com/pods?run=rssbridge)
The Heroku quick deploy currently does not work. It might possibly work if you fork this repo and The Heroku quick deploy currently does not work. It might work if you fork this repo and
modify the `repository` in `scalingo.json`. See https://github.com/RSS-Bridge/rss-bridge/issues/2688 modify the `repository` in `scalingo.json`. See https://github.com/RSS-Bridge/rss-bridge/issues/2688
Learn more in Learn more in
@ -259,11 +259,29 @@ Learn more in
## How-to ## How-to
### How to remove all cache items
As current user:
bin/cache-clear
As user rss-bridge:
sudo -u rss-bridge bin/cache-clear
As root:
sudo bin/cache-clear
### How to remove all expired cache items
bin/cache-clear
### How to fix "PHP Fatal error: Uncaught Exception: The FileCache path is not writable" ### How to fix "PHP Fatal error: Uncaught Exception: The FileCache path is not writable"
```shell ```shell
# Give rssbridge ownership # Give rss-bridge ownership
chown rssbridge:rssbridge -R /var/www/rss-bridge/cache chown rss-bridge:rss-bridge -R /var/www/rss-bridge/cache
# Or, give www-data ownership # Or, give www-data ownership
chown www-data:www-data -R /var/www/rss-bridge/cache chown www-data:www-data -R /var/www/rss-bridge/cache
@ -275,6 +293,16 @@ chmod 777 -R /var/www/rss-bridge/cache
rm -rf /var/www/rss-bridge/cache/ && mkdir /var/www/rss-bridge/cache/ rm -rf /var/www/rss-bridge/cache/ && mkdir /var/www/rss-bridge/cache/
``` ```
### How to fix "attempt to write a readonly database"
The sqlite files (db, wal and shm) are not writeable.
chown -v rss-bridge:rss-bridge cache/*
### How to fix "Unable to prepare statement: 1, no such table: storage"
rm cache/*
### How to create a new bridge from scratch ### How to create a new bridge from scratch
Create the new bridge in e.g. `bridges/BearBlogBridge.php`: Create the new bridge in e.g. `bridges/BearBlogBridge.php`:
@ -389,6 +417,8 @@ These commands require that you have installed the dev dependencies in `composer
./vendor/bin/phpunit ./vendor/bin/phpunit
./vendor/bin/phpcs --standard=phpcs.xml --warning-severity=0 --extensions=php -p ./ ./vendor/bin/phpcs --standard=phpcs.xml --warning-severity=0 --extensions=php -p ./
https://github.com/squizlabs/PHP_CodeSniffer/wiki
### How to spawn a minimal development environment ### How to spawn a minimal development environment
php -S 127.0.0.1:9001 php -S 127.0.0.1:9001

View file

@ -1,9 +1,11 @@
<?php <?php
/**
* Good resource on API return values (Ex: illustType):
* https://hackage.haskell.org/package/pixiv-0.1.0/docs/Web-Pixiv-Types.html
*/
class PixivBridge extends BridgeAbstract class PixivBridge extends BridgeAbstract
{ {
// Good resource on API return values (Ex: illustType):
// https://hackage.haskell.org/package/pixiv-0.1.0/docs/Web-Pixiv-Types.html
const NAME = 'Pixiv Bridge'; const NAME = 'Pixiv Bridge';
const URI = 'https://www.pixiv.net/'; const URI = 'https://www.pixiv.net/';
const DESCRIPTION = 'Returns the tag search from pixiv.net'; const DESCRIPTION = 'Returns the tag search from pixiv.net';
@ -19,7 +21,6 @@ class PixivBridge extends BridgeAbstract
] ]
]; ];
const PARAMETERS = [ const PARAMETERS = [
'global' => [ 'global' => [
'posts' => [ 'posts' => [
@ -251,14 +252,13 @@ class PixivBridge extends BridgeAbstract
$img_url = preg_replace('/https:\/\/i\.pximg\.net/', $proxy_url, $result['url']); $img_url = preg_replace('/https:\/\/i\.pximg\.net/', $proxy_url, $result['url']);
} }
} else { } else {
//else cache and use image. $img_url = $result['url'];
$img_url = $this->cacheImage( // Temporarily disabling caching of the image
$result['url'], //$img_url = $this->cacheImage($result['url'], $result['id'], array_key_exists('illustType', $result));
$result['id'],
array_key_exists('illustType', $result)
);
} }
$item['content'] = "<img src='" . $img_url . "' />";
// Currently, this might result in broken image due to their strict referrer check
$item['content'] = sprintf('<a href="%s"><img src="%s"/></a>', $img_url, $img_url);
// Additional content items // Additional content items
if (array_key_exists('pageCount', $result)) { if (array_key_exists('pageCount', $result)) {
@ -318,7 +318,7 @@ class PixivBridge extends BridgeAbstract
if ( if (
!(strlen($proxy) > 0 && preg_match('/https?:\/\/.*/', $proxy)) !(strlen($proxy) > 0 && preg_match('/https?:\/\/.*/', $proxy))
) { ) {
return returnServerError('Invalid proxy_url value set. The proxy must include the HTTP/S at the beginning of the url.'); returnServerError('Invalid proxy_url value set. The proxy must include the HTTP/S at the beginning of the url.');
} }
} }
@ -326,8 +326,7 @@ class PixivBridge extends BridgeAbstract
if ($cookie) { if ($cookie) {
$isAuth = $this->loadCacheValue('is_authenticated'); $isAuth = $this->loadCacheValue('is_authenticated');
if (!$isAuth) { if (!$isAuth) {
$res = $this->getData('https://www.pixiv.net/ajax/webpush', true, true) $res = $this->getData('https://www.pixiv.net/ajax/webpush', true, true);
or returnServerError('Invalid PHPSESSID cookie provided. Please check the 🍪 and try again.');
if ($res['error'] === false) { if ($res['error'] === false) {
$this->saveCacheValue('is_authenticated', true); $this->saveCacheValue('is_authenticated', true);
} }
@ -374,11 +373,11 @@ class PixivBridge extends BridgeAbstract
if ($cache) { if ($cache) {
$data = $this->loadCacheValue($url); $data = $this->loadCacheValue($url);
if (!$data) { if (!$data) {
$data = getContents($url, $httpHeaders, $curlOptions, true) or returnServerError("Could not load $url"); $data = getContents($url, $httpHeaders, $curlOptions, true);
$this->saveCacheValue($url, $data); $this->saveCacheValue($url, $data);
} }
} else { } else {
$data = getContents($url, $httpHeaders, $curlOptions, true) or returnServerError("Could not load $url"); $data = getContents($url, $httpHeaders, $curlOptions, true);
} }
$this->checkCookie($data['headers']); $this->checkCookie($data['headers']);

View file

@ -2,9 +2,14 @@ PixivBridge
=============== ===============
# Image proxy # Image proxy
As Pixiv requires images to be loaded with the `Referer "https://www.pixiv.net/"` header set, caching or image proxy is required to use this bridge.
To turn off image caching, set the `proxy_url` value in this bridge's configuration section of `config.ini.php` to the url of the proxy. The bridge will then use the proxy in this format (essentially replacing `https://i.pximg.net` with the proxy): As Pixiv requires images to be loaded with the `Referer "https://www.pixiv.net/"` header set,
caching or image proxy is required to use this bridge.
To turn off image caching, set the `proxy_url` value in this bridge's configuration section of `config.ini.php`
to the url of the proxy.
The bridge will then use the proxy in this format (essentially replacing `https://i.pximg.net` with the proxy):
Before: `https://i.pximg.net/img-original/img/0000/00/00/00/00/00/12345678_p0.png` Before: `https://i.pximg.net/img-original/img/0000/00/00/00/00/00/12345678_p0.png`
@ -15,9 +20,11 @@ proxy_url = "https://proxy.example.com"
``` ```
# Authentication # Authentication
Authentication is required to view and search R-18+ and non-public images. To enable this, set the following in this bridge's configuration in `config.ini.php`.
``` Authentication is required to view and search R-18+ and non-public images.
To enable this, set the following in this bridge's configuration in `config.ini.php`.
```ini
; from cookie "PHPSESSID". Recommend to get in incognito browser. ; from cookie "PHPSESSID". Recommend to get in incognito browser.
cookie = "00000000_hashedsessionidhere" cookie = "00000000_hashedsessionidhere"
``` ```

View file

@ -1,33 +1,14 @@
<?php <?php
if (version_compare(\PHP_VERSION, '7.4.0') === -1) {
exit('RSS-Bridge requires minimum PHP version 7.4.0!');
}
require_once __DIR__ . '/lib/bootstrap.php'; require_once __DIR__ . '/lib/bootstrap.php';
$errors = Configuration::checkInstallation();
if ($errors) {
print '<pre>' . implode("\n", $errors) . '</pre>';
exit(1);
}
$customConfig = [];
if (file_exists(__DIR__ . '/config.ini.php')) {
$customConfig = parse_ini_file(__DIR__ . '/config.ini.php', true, INI_SCANNER_TYPED);
}
Configuration::loadConfiguration($customConfig, getenv());
// Consider: ini_set('error_reporting', E_ALL & ~E_DEPRECATED); // Consider: ini_set('error_reporting', E_ALL & ~E_DEPRECATED);
date_default_timezone_set(Configuration::getConfig('system', 'timezone')); date_default_timezone_set(Configuration::getConfig('system', 'timezone'));
$rssBridge = new RssBridge();
set_exception_handler(function (\Throwable $e) { set_exception_handler(function (\Throwable $e) {
http_response_code(500);
print render(__DIR__ . '/templates/exception.html.php', ['e' => $e]);
RssBridge::getLogger()->error('Uncaught Exception', ['e' => $e]); RssBridge::getLogger()->error('Uncaught Exception', ['e' => $e]);
exit(1); http_response_code(500);
exit(render(__DIR__ . '/templates/exception.html.php', ['e' => $e]));
}); });
set_error_handler(function ($code, $message, $file, $line) { set_error_handler(function ($code, $message, $file, $line) {
@ -63,4 +44,6 @@ register_shutdown_function(function () {
} }
}); });
$rssBridge = new RssBridge();
$rssBridge->main($argv ?? []); $rssBridge->main($argv ?? []);

View file

@ -37,6 +37,7 @@ class CacheFactory
if ($index === false) { if ($index === false) {
throw new \InvalidArgumentException(sprintf('Invalid cache name: "%s"', $name)); throw new \InvalidArgumentException(sprintf('Invalid cache name: "%s"', $name));
} }
$className = $cacheNames[$index] . 'Cache'; $className = $cacheNames[$index] . 'Cache';
if (!preg_match('/^[A-Z][a-zA-Z0-9-]*$/', $className)) { if (!preg_match('/^[A-Z][a-zA-Z0-9-]*$/', $className)) {
throw new \InvalidArgumentException(sprintf('Invalid cache classname: "%s"', $className)); throw new \InvalidArgumentException(sprintf('Invalid cache classname: "%s"', $className));

View file

@ -59,7 +59,7 @@ final class Configuration
} }
$config = parse_ini_file(__DIR__ . '/../config.default.ini.php', true, INI_SCANNER_TYPED); $config = parse_ini_file(__DIR__ . '/../config.default.ini.php', true, INI_SCANNER_TYPED);
if (!$config) { if (!$config) {
throw new \Exception('Error parsing config'); throw new \Exception('Error parsing ini config');
} }
foreach ($config as $header => $section) { foreach ($config as $header => $section) {
foreach ($section as $key => $value) { foreach ($section as $key => $value) {

View file

@ -1,5 +1,9 @@
<?php <?php
if (version_compare(\PHP_VERSION, '7.4.0') === -1) {
exit('RSS-Bridge requires minimum PHP version 7.4.0!');
}
// Path to the formats library // Path to the formats library
const PATH_LIB_FORMATS = __DIR__ . '/../formats/'; const PATH_LIB_FORMATS = __DIR__ . '/../formats/';
@ -46,3 +50,14 @@ spl_autoload_register(function ($className) {
} }
} }
}); });
$errors = Configuration::checkInstallation();
if ($errors) {
exit('<pre>' . implode("\n", $errors) . '</pre>');
}
$customConfig = [];
if (file_exists(__DIR__ . '/../config.ini.php')) {
$customConfig = parse_ini_file(__DIR__ . '/../config.ini.php', true, INI_SCANNER_TYPED);
}
Configuration::loadConfiguration($customConfig, getenv());

View file

@ -149,6 +149,7 @@ final class StreamHandler
); );
error_log($text); error_log($text);
if ($record['level'] < Logger::ERROR && Debug::isEnabled()) { if ($record['level'] < Logger::ERROR && Debug::isEnabled()) {
// The record level is INFO or WARNING here
// Not a good idea to print here because http headers might not have been sent // Not a good idea to print here because http headers might not have been sent
print sprintf("<pre>%s</pre>\n", e($text)); print sprintf("<pre>%s</pre>\n", e($text));
} }

View file

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ruleset name="RSS-Bridge Ruleset"> <ruleset name="RSS-Bridge Ruleset">
<description>Created with the PHP Coding Standard Generator. http://edorian.github.com/php-coding-standard-generator/</description> <description>
Originally created with the PHP Coding Standard Generator.
But later manually tweaked.
http://edorian.github.com/php-coding-standard-generator/
</description>
<exclude-pattern>./static</exclude-pattern> <exclude-pattern>./static</exclude-pattern>
<exclude-pattern>./vendor</exclude-pattern> <exclude-pattern>./vendor</exclude-pattern>
<exclude-pattern>./templates</exclude-pattern> <exclude-pattern>./templates</exclude-pattern>
@ -11,6 +16,7 @@
<exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/> <exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
<exclude name="PSR1.Classes.ClassDeclaration.MultipleClasses"/> <exclude name="PSR1.Classes.ClassDeclaration.MultipleClasses"/>
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols"/> <exclude name="PSR1.Files.SideEffects.FoundWithSymbols"/>
<exclude name="PSR2.Files.EndFileNewline"/>
<exclude name="PSR12.Properties.ConstantVisibility.NotFound"/> <exclude name="PSR12.Properties.ConstantVisibility.NotFound"/>
</rule> </rule>

View file

@ -23,6 +23,14 @@
</p> </p>
<?php endif; ?> <?php endif; ?>
<?php if ($e->getCode() === 403): ?>
<h2>403 Forbidden</h2>
<p>
The HTTP 403 Forbidden response status code indicates that the
server understands the request but refuses to authorize it.
</p>
<?php endif; ?>
<?php if ($e->getCode() === 404): ?> <?php if ($e->getCode() === 404): ?>
<h2>404 Page Not Found</h2> <h2>404 Page Not Found</h2>
<p> <p>