1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-23 09:02:41 +00:00
Arsse/lib/Conf.php

213 lines
12 KiB
PHP
Raw Normal View History

2016-09-27 13:00:02 +00:00
<?php
/** @license MIT
* Copyright 2017 J. King, Dustin Wilson et al.
* See LICENSE and AUTHORS files for details */
/** Conf class */
2016-09-27 13:00:02 +00:00
declare(strict_types=1);
2017-03-28 04:12:12 +00:00
namespace JKingWeb\Arsse;
2016-09-27 13:00:02 +00:00
/** Class for loading, saving, and querying configuration
2017-08-29 14:50:31 +00:00
*
* The Conf class serves both as a means of importing and querying configuration information, as well as a source for default parameters when a configuration file does not specify a value.
* All public properties are configuration parameters that may be set by the server administrator. */
2016-09-27 13:00:02 +00:00
class Conf {
/** @var string Default language to use for logging and errors */
2017-02-16 20:29:42 +00:00
public $lang = "en";
/** @var string Class of the database driver in use (SQLite3 by default) */
public $dbDriver = Db\SQLite3\Driver::class;
/** @var boolean Whether to attempt to automatically update the database when updated to a new version with schema changes */
public $dbAutoUpdate = true;
/** @var float Number of seconds to wait before returning a timeout error when connecting to a database (zero waits forever; not applicable to SQLite) */
public $dbTimeoutConnect = 5.0;
/** @var float Number of seconds to wait before returning a timeout error when executing a database operation (zero waits forever; not applicable to SQLite) */
public $dbTimeoutExec = 0.0;
/** @var string|null Full path and file name of SQLite database (if using SQLite) */
public $dbSQLite3File = null;
/** @var string Encryption key to use for SQLite database (if using a version of SQLite with SEE) */
2017-02-16 20:29:42 +00:00
public $dbSQLite3Key = "";
/** @var float Number of seconds for SQLite to wait before returning a timeout error when trying to acquire a write lock on the database (zero does not wait) */
public $dbSQLite3Timeout = 60.0;
/** @var string Host name, address, or socket path of PostgreSQL database server (if using PostgreSQL) */
public $dbPostgreSQLHost = "";
/** @var string Log-in user name for PostgreSQL database server (if using PostgreSQL) */
public $dbPostgreSQLUser = "arsse";
/** @var string Log-in password for PostgreSQL database server (if using PostgreSQL) */
public $dbPostgreSQLPass = "";
/** @var integer Listening port for PostgreSQL database server (if using PostgreSQL over TCP) */
public $dbPostgreSQLPort = 5432;
/** @var string Database name on PostgreSQL database server (if using PostgreSQL) */
public $dbPostgreSQLDb = "arsse";
2018-11-17 02:20:54 +00:00
/** @var string Schema name in PostgreSQL database (if using PostgreSQL) */
public $dbPostgreSQLSchema = "";
2018-11-17 02:20:54 +00:00
/** @var string Service file entry to use (if using PostgreSQL); if using a service entry all above parameters except schema are ignored */
public $dbPostgreSQLService = "";
/** @var string Host name, address, or socket path of MySQL/MariaDB database server (if using MySQL/MariaDB) */
public $dbMySQLHost = "localhost";
/** @var string Log-in user name for MySQL/MariaDB database server (if using MySQL/MariaDB) */
public $dbMySQLUser = "arsse";
/** @var string Log-in password for MySQL/MariaDB database server (if using MySQL/MariaDB) */
public $dbMySQLPass = "";
/** @var integer Listening port for MySQL/MariaDB database server (if using MySQL/MariaDB over TCP) */
public $dbMySQLPort = 3306;
/** @var string Database name on MySQL/MariaDB database server (if using MySQL/MariaDB) */
public $dbMySQLDb = "arsse";
/** @var string Class of the user management driver in use (Internal by default) */
public $userDriver = User\Internal\Driver::class;
/** @var boolean Whether users are already authenticated by the Web server before the application is executed */
public $userPreAuth = false;
/** @var boolean Whether to require successful HTTP authentication before processing API-level authentication for protocols which have any. Normally the Tiny Tiny RSS relies on its own session-token authentication scheme, for example */
public $userHTTPAuthRequired = false;
/** @var integer Desired length of temporary user passwords */
public $userTempPasswordLength = 20;
/** @var boolean Whether invalid or expired API session tokens should prevent logging in when HTTP authentication is used, for protocol which implement their own authentication */
public $userSessionEnforced = true;
/** @var string Period of inactivity after which log-in sessions should be considered invalid, as an ISO 8601 duration (default: 24 hours)
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
public $userSessionTimeout = "PT24H";
/** @var string Maximum lifetime of log-in sessions regardless of activity, as an ISO 8601 duration (default: 7 days);
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
public $userSessionLifetime = "P7D";
2016-09-27 13:00:02 +00:00
/** @var string Class of the background feed update service driver in use (Forking by default) */
public $serviceDriver = Service\Forking\Driver::class;
/** @var string The interval between checks for new articles, as an ISO 8601 duration
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
public $serviceFrequency = "PT2M";
/** @var integer Number of concurrent feed updates to perform */
public $serviceQueueWidth = 5;
/** @var string The base server address (with scheme, host, port if necessary, and terminal slash) to connect to the server when performing feed updates using cURL */
public $serviceCurlBase = "http://localhost/";
/** @var string The user name to use when performing feed updates using cURL; if none is provided, a temporary name and password will be stored in the database (this is not compatible with pre-authentication) */
public $serviceCurlUser = null;
/** @var string The password to use when performing feed updates using cURL */
public $serviceCurlPassword = null;
2018-10-26 18:58:04 +00:00
/** @var integer Number of seconds to wait for data when fetching feeds from foreign servers */
2017-05-27 22:15:52 +00:00
public $fetchTimeout = 10;
/** @var integer Maximum size, in bytes, of data when fetching feeds from foreign servers */
2017-05-27 22:15:52 +00:00
public $fetchSizeLimit = 2 * 1024 * 1024;
/** @var boolean Whether to allow the possibility of fetching full article contents using an item's URL. Whether fetching will actually happen is also governed by a per-feed setting */
public $fetchEnableScraping = true;
/** @var string|null User-Agent string to use when fetching feeds from foreign servers */
2017-05-27 22:15:52 +00:00
public $fetchUserAgentString;
2016-09-27 13:00:02 +00:00
/** @var string When to delete a feed from the database after all its subscriptions have been deleted, as an ISO 8601 duration (default: 24 hours; empty string for never)
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
public $purgeFeeds = "PT24H";
/** @var string When to delete an unstarred article in the database after it has been marked read by all users, as an ISO 8601 duration (default: 7 days; empty string for never)
2017-08-18 02:36:15 +00:00
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
public $purgeArticlesRead = "P7D";
/** @var string When to delete an unstarred article in the database regardless of its read state, as an ISO 8601 duration (default: 21 days; empty string for never)
2017-08-18 02:36:15 +00:00
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
2017-08-29 14:50:31 +00:00
public $purgeArticlesUnread = "P21D";
/** @var string Application name to present to clients during authentication */
public $httpRealm = "The Advanced RSS Environment";
2018-01-09 17:31:40 +00:00
/** @var string Space-separated list of origins from which to allow cross-origin resource sharing */
public $httpOriginsAllowed = "*";
/** @var string Space-separated list of origins from which to deny cross-origin resource sharing */
public $httpOriginsDenied = "";
2018-01-09 17:31:40 +00:00
/** Creates a new configuration object
* @param string $import_file Optional file to read configuration data from
* @see self::importFile() */
2017-02-16 20:29:42 +00:00
public function __construct(string $import_file = "") {
2017-08-29 14:50:31 +00:00
if ($import_file != "") {
$this->importFile($import_file);
}
2017-02-16 20:29:42 +00:00
}
2017-08-29 14:50:31 +00:00
/** Layers configuration data from a file into an existing object
*
* The file must be a PHP script which return an array with keys that match the properties of the Conf class. Malformed files will throw an exception; unknown keys are silently ignored. Files may be imported is succession, though this is not currently used.
* @param string $file Full path and file name for the file to import */
2017-02-16 20:29:42 +00:00
public function importFile(string $file): self {
2017-08-29 14:50:31 +00:00
if (!file_exists($file)) {
throw new Conf\Exception("fileMissing", $file);
2017-08-29 14:50:31 +00:00
} elseif (!is_readable($file)) {
throw new Conf\Exception("fileUnreadable", $file);
}
2017-02-16 20:29:42 +00:00
try {
ob_start();
$arr = (@include $file);
2017-08-29 14:50:31 +00:00
} catch (\Throwable $e) {
2017-02-16 20:29:42 +00:00
$arr = null;
} finally {
ob_end_clean();
}
2017-08-29 14:50:31 +00:00
if (!is_array($arr)) {
throw new Conf\Exception("fileCorrupt", $file);
}
2017-02-16 20:29:42 +00:00
return $this->import($arr);
}
2016-09-27 13:00:02 +00:00
2017-08-29 14:50:31 +00:00
/** Layers configuration data from an associative array into an existing object
*
* The input array must have keys that match the properties of the Conf class; unknown keys are silently ignored. Arrays may be imported is succession, though this is not currently used.
* @param mixed[] $arr Array of configuration parameters to export */
2017-02-16 20:29:42 +00:00
public function import(array $arr): self {
2017-08-29 14:50:31 +00:00
foreach ($arr as $key => $value) {
2017-02-16 20:29:42 +00:00
$this->$key = $value;
}
return $this;
}
2016-09-27 13:00:02 +00:00
/** Outputs configuration settings, either non-default ones or all, as an associative array
* @param bool $full Whether to output all configuration options rather than only changed ones */
public function export(bool $full = false): array {
$ref = new self;
$out = [];
$conf = new \ReflectionObject($this);
2017-08-29 14:50:31 +00:00
foreach ($conf->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
$name = $prop->name;
2017-08-30 03:17:57 +00:00
// add the property to the output if the value is scalar (or null) and either:
// 1. full output has been requested
// 2. the property is not defined in the class
// 3. it differs from the default
2017-08-30 03:17:57 +00:00
if ((is_scalar($this->$name) || is_null($this->$name)) && ($full || !$prop->isDefault() || $this->$name !== $ref->$name)) {
$out[$name] = $this->$name;
}
}
return $out;
2017-02-16 20:29:42 +00:00
}
/** Outputs configuration settings, either non-default ones or all, to a file in a format suitable for later import
* @param string $file Full path and file name for the file to import to; the containing directory must already exist
* @param bool $full Whether to output all configuration options rather than only changed ones */
public function exportFile(string $file, bool $full = false): bool {
$arr = $this->export($full);
$conf = new \ReflectionObject($this);
$out = "<?php return [".PHP_EOL;
2017-08-29 14:50:31 +00:00
foreach ($arr as $prop => $value) {
$match = null;
$doc = $comment = "";
// retrieve the property's docblock, if it exists
try {
$doc = (new \ReflectionProperty(self::class, $prop))->getDocComment();
2017-08-29 14:50:31 +00:00
} catch (\ReflectionException $e) {
}
if ($doc) {
// parse the docblock to extract the property description
2017-08-29 14:50:31 +00:00
if (preg_match("<@var\s+\S+\s+(.+?)(?:\s*\*/)?$>m", $doc, $match)) {
$comment = $match[1];
}
}
// append the docblock description if there is one, or an empty comment otherwise
$out .= " // ".$comment.PHP_EOL;
// append the property and an export of its value to the output
2017-08-29 14:50:31 +00:00
$out .= " ".var_export($prop, true)." => ".var_export($value, true).",".PHP_EOL;
}
$out .= "];".PHP_EOL;
// write the configuration representation to the requested file
2017-08-29 14:50:31 +00:00
if (!@file_put_contents($file, $out)) {
// if it fails throw an exception
$err = file_exists($file) ? "fileUnwritable" : "fileUncreatable";
throw new Conf\Exception($err, $file);
}
return true;
2017-02-16 20:29:42 +00:00
}
2017-08-29 14:50:31 +00:00
}