2016-09-27 13:00:02 +00:00
< ? php
2017-11-17 01:23:18 +00:00
/** @ license MIT
* Copyright 2017 J . King , Dustin Wilson et al .
* See LICENSE and AUTHORS files for details */
2017-07-17 02:27:55 +00:00
/** 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
2017-07-17 02:27:55 +00:00
/** Class for loading , saving , and querying configuration
2017-08-29 14:50:31 +00:00
*
2017-07-27 13:09:39 +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 {
2017-07-17 02:27:55 +00:00
/** @var string Default language to use for logging and errors */
2017-02-16 20:29:42 +00:00
public $lang = " en " ;
2016-10-15 13:45:23 +00:00
2017-07-17 02:27:55 +00:00
/** @var string Class of the database driver in use (SQLite3 by default) */
2017-03-07 23:01:13 +00:00
public $dbDriver = Db\SQLite3\Driver :: class ;
2017-07-17 02:27:55 +00:00
/** @var boolean Whether to attempt to automatically update the database when updated to a new version with schema changes */
2017-07-12 00:27:37 +00:00
public $dbAutoUpdate = true ;
2018-11-22 18:30:13 +00:00
/** @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 ;
2017-08-28 23:38:58 +00:00
/** @var string|null Full path and file name of SQLite database (if using SQLite) */
public $dbSQLite3File = null ;
2017-07-17 02:27:55 +00:00
/** @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 = " " ;
2018-11-22 18:30:13 +00:00
/** @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 ;
2018-11-10 05:02:38 +00:00
/** @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) */
2018-11-10 05:02:38 +00:00
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 = " " ;
2018-12-20 23:06:28 +00:00
/** @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 " ;
2016-10-15 13:45:23 +00:00
2017-07-17 02:27:55 +00:00
/** @var string Class of the user management driver in use (Internal by default) */
2017-03-07 23:01:13 +00:00
public $userDriver = User\Internal\Driver :: class ;
2017-07-17 02:27:55 +00:00
/** @var boolean Whether users are already authenticated by the Web server before the application is executed */
2017-08-18 14:20:43 +00:00
public $userPreAuth = false ;
2018-10-26 18:40:20 +00:00
/** @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 ;
2017-07-17 02:27:55 +00:00
/** @var integer Desired length of temporary user passwords */
2017-02-20 22:04:13 +00:00
public $userTempPasswordLength = 20 ;
2018-10-26 18:40:20 +00:00
/** @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 ;
2018-01-01 17:31:42 +00:00
/** @ var string Period of inactivity after which log - in sessions should be considered invalid , as an ISO 8601 duration ( default : 24 hours )
2017-09-16 23:57:33 +00:00
* @ see https :// en . wikipedia . org / wiki / ISO_8601 #Durations */
2018-10-26 18:40:20 +00:00
public $userSessionTimeout = " PT24H " ;
2018-01-01 17:31:42 +00:00
/** @ var string Maximum lifetime of log - in sessions regardless of activity , as an ISO 8601 duration ( default : 7 days );
2017-09-16 23:57:33 +00:00
* @ see https :// en . wikipedia . org / wiki / ISO_8601 #Durations */
2018-01-01 17:31:42 +00:00
public $userSessionLifetime = " P7D " ;
2016-09-27 13:00:02 +00:00
2017-07-17 02:27:55 +00:00
/** @var string Class of the background feed update service driver in use (Forking by default) */
2017-07-21 21:15:43 +00:00
public $serviceDriver = Service\Forking\Driver :: class ;
2017-09-16 23:57:33 +00:00
/** @ var string The interval between checks for new articles , as an ISO 8601 duration
2017-07-27 13:09:39 +00:00
* @ see https :// en . wikipedia . org / wiki / ISO_8601 #Durations */
2017-07-12 00:27:37 +00:00
public $serviceFrequency = " PT2M " ;
2017-07-17 02:27:55 +00:00
/** @var integer Number of concurrent feed updates to perform */
2017-07-15 17:33:17 +00:00
public $serviceQueueWidth = 5 ;
2017-07-17 02:27:55 +00:00
/** @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 */
2017-07-12 00:27:37 +00:00
public $serviceCurlBase = " http://localhost/ " ;
2017-07-17 02:27:55 +00:00
/** @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) */
2017-07-12 00:27:37 +00:00
public $serviceCurlUser = null ;
2017-07-17 02:27:55 +00:00
/** @var string The password to use when performing feed updates using cURL */
2017-07-12 00:27:37 +00:00
public $serviceCurlPassword = null ;
2018-10-26 18:58:04 +00:00
2017-07-17 02:27:55 +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 ;
2017-07-17 02:27:55 +00:00
/** @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 ;
2017-07-17 18:56:50 +00:00
/** @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 ;
2017-08-02 22:27:04 +00:00
/** @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
2017-08-20 19:46:35 +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 )
2017-08-02 22:27:04 +00:00
* @ see https :// en . wikipedia . org / wiki / ISO_8601 #Durations */
2018-10-26 18:40:20 +00:00
public $purgeFeeds = " PT24H " ;
2017-08-20 19:46:35 +00:00
/** @ 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 */
2018-10-26 18:40:20 +00:00
public $purgeArticlesRead = " P7D " ;
2017-08-20 19:46:35 +00:00
/** @ 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 " ;
2017-08-02 22:27:04 +00:00
2018-01-11 20:48:29 +00:00
/** @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 */
2018-01-11 20:48:29 +00:00
public $httpOriginsDenied = " " ;
2018-01-09 17:31:40 +00:00
2017-07-17 02:27:55 +00:00
/** Creates a new configuration object
2017-07-27 13:09:39 +00:00
* @ 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 = " " ) {
2019-01-11 15:38:06 +00:00
if ( $import_file !== " " ) {
2017-07-21 21:15:43 +00:00
$this -> importFile ( $import_file );
}
2017-02-16 20:29:42 +00:00
}
2016-09-30 01:58:09 +00:00
2017-08-29 14:50:31 +00:00
/** Layers configuration data from a file into an existing object
2017-07-27 13:09:39 +00:00
*
* 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 )) {
2017-07-21 21:15:43 +00:00
throw new Conf\Exception ( " fileMissing " , $file );
2017-08-29 14:50:31 +00:00
} elseif ( ! is_readable ( $file )) {
2017-07-21 21:15:43 +00:00
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 )) {
2017-07-21 21:15:43 +00:00
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
2017-07-27 13:09:39 +00:00
*
* 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
2017-07-27 13:09:39 +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 ) {
2017-07-27 13:09:39 +00:00
$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:
2017-07-27 13:09:39 +00:00
// 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 )) {
2017-07-27 13:09:39 +00:00
$out [ $name ] = $this -> $name ;
}
}
return $out ;
2017-02-16 20:29:42 +00:00
}
2017-07-27 13:09:39 +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 ) {
2017-07-27 13:09:39 +00:00
$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 ) {
2017-07-27 13:09:39 +00:00
// 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 )) {
2017-07-27 13:09:39 +00:00
$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 ;
2017-07-27 13:09:39 +00:00
}
$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 )) {
2017-07-27 13:09:39 +00:00
// 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
}