Fixed Broken Shit
After Width: | Height: | Size: 84 B |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 338 B |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
@ -1,37 +1,37 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 378.303 378.303" style="enable-background:new 0 0 378.303 378.303;" xml:space="preserve">
|
||||
<polygon style="fill:#7289DA;" points="378.303,28.285 350.018,0 189.151,160.867 28.285,0 0,28.285 160.867,189.151 0,350.018
|
||||
28.285,378.302 189.151,217.436 350.018,378.302 378.303,350.018 217.436,189.151 "/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 378.303 378.303" style="enable-background:new 0 0 378.303 378.303;" xml:space="preserve">
|
||||
<polygon style="fill:#7289DA;" points="378.303,28.285 350.018,0 189.151,160.867 28.285,0 0,28.285 160.867,189.151 0,350.018
|
||||
28.285,378.302 189.151,217.436 350.018,378.302 378.303,350.018 217.436,189.151 "/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 758 B After Width: | Height: | Size: 721 B |
After Width: | Height: | Size: 366 KiB |
After Width: | Height: | Size: 207 KiB |
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 105 KiB |
|
@ -21,6 +21,7 @@
|
|||
<meta name="twitter:image" content="https://sop.wtf/frontend/assets/img/cover.png">
|
||||
<title><?php echo title ?></title>
|
||||
<link rel="stylesheet" href="<?php $YOURLS_SITE ?>/frontend/dist/styles.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css" integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
|
||||
|
||||
<?php if (defined('backgroundImage')) : ?>
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Define the YOURLS config
|
||||
*/
|
||||
|
||||
namespace YOURLS\Config;
|
||||
|
||||
use YOURLS\Exceptions\ConfigException;
|
||||
|
||||
class Config {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @param string $config Optional user defined config path
|
||||
*/
|
||||
public function __construct($config = '') {
|
||||
$this->set_root( $this->fix_win32_path( dirname( dirname( __DIR__ ) ) ) );
|
||||
$this->set_config($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert antislashes to slashes
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @param string $path
|
||||
* @return string path with \ converted to /
|
||||
*/
|
||||
public function fix_win32_path($path) {
|
||||
return str_replace('\\', '/', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @param string $config path to config file
|
||||
* @return void
|
||||
*/
|
||||
public function set_config($config) {
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @param string $root path to YOURLS root directory
|
||||
* @return void
|
||||
*/
|
||||
public function set_root($root) {
|
||||
$this->root = $root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find config.php, either user defined or from standard location
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return string path to found config file
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function find_config() {
|
||||
|
||||
$config = $this->fix_win32_path($this->config);
|
||||
|
||||
if (!empty($config) && is_readable($config)) {
|
||||
return $config;
|
||||
}
|
||||
|
||||
if (!empty($config) && !is_readable($config)) {
|
||||
throw new ConfigException("User defined config not found at '$config'");
|
||||
}
|
||||
|
||||
// config.php in /user/
|
||||
if (file_exists($this->root . '/user/config.php')) {
|
||||
return $this->root . '/user/config.php';
|
||||
}
|
||||
|
||||
// config.php in /includes/
|
||||
if (file_exists($this->root . '/includes/config.php')) {
|
||||
return $this->root . '/includes/config.php';
|
||||
}
|
||||
|
||||
// config.php not found :(
|
||||
|
||||
throw new ConfigException('Cannot find config.php. Please read the readme.html to learn how to install YOURLS');
|
||||
}
|
||||
|
||||
/**
|
||||
* Define core constants that have not been user defined in config.php
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function define_core_constants() {
|
||||
// Check minimal config job has been properly done
|
||||
$must_haves = array('YOURLS_DB_USER', 'YOURLS_DB_PASS', 'YOURLS_DB_NAME', 'YOURLS_DB_HOST', 'YOURLS_DB_PREFIX', 'YOURLS_SITE');
|
||||
foreach($must_haves as $must_have) {
|
||||
if (!defined($must_have)) {
|
||||
throw new ConfigException('Config is incomplete (missing at least '.$must_have.') Check config-sample.php and edit your config accordingly');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The following has an awful CRAP index and it would be much shorter reduced to something like
|
||||
* defining an array of ('YOURLS_SOMETHING' => 'default value') and then a simple loop over the
|
||||
* array, checking if $current is defined as a constant and otherwise define said constant with
|
||||
* its default value. I did not wrote it that way because that would make it difficult for code
|
||||
* parsers to identify which constants are defined and where. So, here it is, that long list of
|
||||
* if (!defined) define(). Ho and by the way, such beautiful comment, much right aligned, wow !
|
||||
*/
|
||||
|
||||
// physical path of YOURLS root
|
||||
if (!defined( 'YOURLS_ABSPATH' ))
|
||||
define('YOURLS_ABSPATH', $this->root);
|
||||
|
||||
// physical path of includes directory
|
||||
if (!defined( 'YOURLS_INC' ))
|
||||
define('YOURLS_INC', YOURLS_ABSPATH.'/includes');
|
||||
|
||||
// physical path of user directory
|
||||
if (!defined( 'YOURLS_USERDIR' ))
|
||||
define( 'YOURLS_USERDIR', YOURLS_ABSPATH.'/user' );
|
||||
|
||||
// URL of user directory
|
||||
if (!defined( 'YOURLS_USERURL' ))
|
||||
define( 'YOURLS_USERURL', trim(YOURLS_SITE, '/').'/user' );
|
||||
|
||||
// physical path of asset directory
|
||||
if( !defined( 'YOURLS_ASSETDIR' ) )
|
||||
define( 'YOURLS_ASSETDIR', YOURLS_ABSPATH.'/assets' );
|
||||
|
||||
// URL of asset directory
|
||||
if( !defined( 'YOURLS_ASSETURL' ) )
|
||||
define( 'YOURLS_ASSETURL', trim(YOURLS_SITE, '/').'/assets' );
|
||||
|
||||
// physical path of translations directory
|
||||
if (!defined( 'YOURLS_LANG_DIR' ))
|
||||
define( 'YOURLS_LANG_DIR', YOURLS_USERDIR.'/languages' );
|
||||
|
||||
// physical path of plugins directory
|
||||
if (!defined( 'YOURLS_PLUGINDIR' ))
|
||||
define( 'YOURLS_PLUGINDIR', YOURLS_USERDIR.'/plugins' );
|
||||
|
||||
// URL of plugins directory
|
||||
if (!defined( 'YOURLS_PLUGINURL' ))
|
||||
define( 'YOURLS_PLUGINURL', YOURLS_USERURL.'/plugins' );
|
||||
|
||||
// physical path of themes directory
|
||||
if( !defined( 'YOURLS_THEMEDIR' ) )
|
||||
define( 'YOURLS_THEMEDIR', YOURLS_USERDIR.'/themes' );
|
||||
|
||||
// URL of themes directory
|
||||
if( !defined( 'YOURLS_THEMEURL' ) )
|
||||
define( 'YOURLS_THEMEURL', YOURLS_USERURL.'/themes' );
|
||||
|
||||
// physical path of pages directory
|
||||
if (!defined( 'YOURLS_PAGEDIR' ))
|
||||
define('YOURLS_PAGEDIR', YOURLS_USERDIR.'/pages' );
|
||||
|
||||
// table to store URLs
|
||||
if (!defined( 'YOURLS_DB_TABLE_URL' ))
|
||||
define( 'YOURLS_DB_TABLE_URL', YOURLS_DB_PREFIX.'url' );
|
||||
|
||||
// table to store options
|
||||
if (!defined( 'YOURLS_DB_TABLE_OPTIONS' ))
|
||||
define( 'YOURLS_DB_TABLE_OPTIONS', YOURLS_DB_PREFIX.'options' );
|
||||
|
||||
// table to store hits, for stats
|
||||
if (!defined( 'YOURLS_DB_TABLE_LOG' ))
|
||||
define( 'YOURLS_DB_TABLE_LOG', YOURLS_DB_PREFIX.'log' );
|
||||
|
||||
// minimum delay in sec before a same IP can add another URL. Note: logged in users are not throttled down.
|
||||
if (!defined( 'YOURLS_FLOOD_DELAY_SECONDS' ))
|
||||
define( 'YOURLS_FLOOD_DELAY_SECONDS', 15 );
|
||||
|
||||
// comma separated list of IPs that can bypass flood check.
|
||||
if (!defined( 'YOURLS_FLOOD_IP_WHITELIST' ))
|
||||
define( 'YOURLS_FLOOD_IP_WHITELIST', '' );
|
||||
|
||||
// life span of an auth cookie in seconds (60*60*24*7 = 7 days)
|
||||
if (!defined( 'YOURLS_COOKIE_LIFE' ))
|
||||
define( 'YOURLS_COOKIE_LIFE', 60*60*24*7 );
|
||||
|
||||
// life span of a nonce in seconds
|
||||
if (!defined( 'YOURLS_NONCE_LIFE' ))
|
||||
define( 'YOURLS_NONCE_LIFE', 43200 ); // 3600 * 12
|
||||
|
||||
// if set to true, disable stat logging (no use for it, too busy servers, ...)
|
||||
if (!defined( 'YOURLS_NOSTATS' ))
|
||||
define( 'YOURLS_NOSTATS', false );
|
||||
|
||||
// if set to true, force https:// in the admin area
|
||||
if (!defined( 'YOURLS_ADMIN_SSL' ))
|
||||
define( 'YOURLS_ADMIN_SSL', false );
|
||||
|
||||
// if set to true, verbose debug infos. Will break things. Don't enable.
|
||||
if (!defined( 'YOURLS_DEBUG' ))
|
||||
define( 'YOURLS_DEBUG', false );
|
||||
|
||||
// Error reporting
|
||||
if (defined( 'YOURLS_DEBUG' ) && YOURLS_DEBUG == true ) {
|
||||
error_reporting( -1 );
|
||||
} else {
|
||||
error_reporting( E_ERROR | E_PARSE );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* YOURLS actions upon instantiating
|
||||
*/
|
||||
|
||||
namespace YOURLS\Config;
|
||||
|
||||
class Init {
|
||||
|
||||
/**
|
||||
* @var InitDefaults
|
||||
*/
|
||||
protected $actions;
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
*
|
||||
* @param InitDefaults $actions
|
||||
*/
|
||||
public function __construct(InitDefaults $actions) {
|
||||
|
||||
$this->actions = $actions;
|
||||
|
||||
// Include core files
|
||||
if ($actions->include_core_funcs === true) {
|
||||
$this->include_core_functions();
|
||||
}
|
||||
|
||||
// Enforce UTC timezone. Date/time can be adjusted with a plugin.
|
||||
if ($actions->default_timezone === true) {
|
||||
date_default_timezone_set( 'UTC' );
|
||||
}
|
||||
|
||||
// Load locale
|
||||
if ($actions->load_default_textdomain === true) {
|
||||
yourls_load_default_textdomain();
|
||||
}
|
||||
|
||||
// Check if we are in maintenance mode - if yes, it will die here.
|
||||
if ($actions->check_maintenance_mode === true) {
|
||||
yourls_check_maintenance_mode();
|
||||
}
|
||||
|
||||
// Fix REQUEST_URI for IIS
|
||||
if ($actions->fix_request_uri === true) {
|
||||
yourls_fix_request_uri();
|
||||
}
|
||||
|
||||
// If request for an admin page is http:// and SSL is required, redirect
|
||||
if ($actions->redirect_ssl === true) {
|
||||
$this->redirect_ssl_if_needed();
|
||||
}
|
||||
|
||||
// Create the YOURLS object $ydb that will contain everything we globally need
|
||||
if ($actions->include_db === true) {
|
||||
$this->include_db_files();
|
||||
}
|
||||
|
||||
// Allow early inclusion of a cache layer
|
||||
if ($actions->include_cache === true) {
|
||||
$this->include_cache_files();
|
||||
}
|
||||
|
||||
// Abort initialization here if fast init wanted (for tests/debug/do not use)
|
||||
if ($actions->return_if_fast_init === true && defined('YOURLS_FAST_INIT') && YOURLS_FAST_INIT){
|
||||
return;
|
||||
}
|
||||
|
||||
// Read options right from start
|
||||
if ($actions->get_all_options === true) {
|
||||
yourls_get_all_options();
|
||||
}
|
||||
|
||||
// Register shutdown function
|
||||
if ($actions->register_shutdown === true) {
|
||||
register_shutdown_function( 'yourls_shutdown' );
|
||||
}
|
||||
|
||||
// Core now loaded
|
||||
if ($actions->core_loaded === true) {
|
||||
yourls_do_action( 'init' ); // plugins can't see this, not loaded yet
|
||||
}
|
||||
|
||||
// Check if need to redirect to install procedure
|
||||
if ($actions->redirect_to_install === true) {
|
||||
if (!yourls_is_installed() && !yourls_is_installing()) {
|
||||
yourls_no_cache_headers();
|
||||
yourls_redirect( yourls_admin_url('install.php'), 307 );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if upgrade is needed (bypassed if upgrading or installing)
|
||||
if ($actions->check_if_upgrade_needed === true) {
|
||||
if (!yourls_is_upgrading() && !yourls_is_installing() && yourls_upgrade_is_needed()) {
|
||||
yourls_no_cache_headers();
|
||||
yourls_redirect( yourls_admin_url('upgrade.php'), 307 );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Load all plugins
|
||||
if ($actions->load_plugins === true) {
|
||||
yourls_load_plugins();
|
||||
}
|
||||
|
||||
// Trigger plugin loaded action
|
||||
if ($actions->plugins_loaded_action === true) {
|
||||
yourls_do_action( 'plugins_loaded' );
|
||||
}
|
||||
|
||||
// Is there a new version of YOURLS ?
|
||||
if ($actions->check_new_version === true) {
|
||||
if (yourls_is_installed() && !yourls_is_upgrading()) {
|
||||
yourls_tell_if_new_version();
|
||||
}
|
||||
}
|
||||
|
||||
if ($actions->init_admin === true) {
|
||||
if (yourls_is_admin()) {
|
||||
yourls_do_action( 'admin_init' );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
*/
|
||||
public function redirect_ssl_if_needed() {
|
||||
if (yourls_is_admin() && yourls_needs_ssl() && !yourls_is_ssl()) {
|
||||
if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
|
||||
yourls_redirect( preg_replace( '|^http://|', 'https://', $_SERVER['REQUEST_URI'] ) );
|
||||
} else {
|
||||
yourls_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
|
||||
}
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
*/
|
||||
public function include_db_files() {
|
||||
// Allow drop-in replacement for the DB engine
|
||||
if (file_exists(YOURLS_USERDIR.'/db.php')) {
|
||||
require_once YOURLS_USERDIR.'/db.php';
|
||||
} else {
|
||||
require_once YOURLS_INC.'/class-mysql.php';
|
||||
yourls_db_connect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
*/
|
||||
public function include_cache_files() {
|
||||
if (file_exists(YOURLS_USERDIR.'/cache.php')) {
|
||||
require_once YOURLS_USERDIR.'/cache.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
*/
|
||||
public function include_core_functions() {
|
||||
require_once YOURLS_INC.'/version.php';
|
||||
require_once YOURLS_INC.'/functions.php';
|
||||
require_once YOURLS_INC.'/functions-geo.php';
|
||||
require_once YOURLS_INC.'/functions-shorturls.php';
|
||||
require_once YOURLS_INC.'/functions-debug.php';
|
||||
require_once YOURLS_INC.'/functions-options.php';
|
||||
require_once YOURLS_INC.'/functions-links.php';
|
||||
require_once YOURLS_INC.'/functions-plugins.php';
|
||||
require_once YOURLS_INC.'/functions-formatting.php';
|
||||
require_once YOURLS_INC.'/functions-api.php';
|
||||
require_once YOURLS_INC.'/functions-kses.php';
|
||||
require_once YOURLS_INC.'/functions-l10n.php';
|
||||
require_once YOURLS_INC.'/functions-compat.php';
|
||||
require_once YOURLS_INC.'/functions-html.php';
|
||||
require_once YOURLS_INC.'/functions-http.php';
|
||||
require_once YOURLS_INC.'/functions-infos.php';
|
||||
require_once YOURLS_INC.'/functions-deprecated.php';
|
||||
require_once YOURLS_INC.'/functions-auth.php';
|
||||
require_once YOURLS_INC.'/functions-upgrade.php';
|
||||
require_once YOURLS_INC.'/functions-install.php';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* YOURLS defaut actions upon instantiating
|
||||
*
|
||||
* This class defines all the default actions to be performed when instantiating YOURLS. The idea
|
||||
* is that this is easily tuneable depending on the scenario, namely when running YOURLS for
|
||||
* unit tests.
|
||||
*
|
||||
* @see \YOURLS\Config\Init
|
||||
*/
|
||||
|
||||
namespace YOURLS\Config;
|
||||
|
||||
class InitDefaults {
|
||||
|
||||
/**
|
||||
* Whether to include core function files
|
||||
* @var bool
|
||||
*/
|
||||
public $include_core_funcs = true;
|
||||
|
||||
/**
|
||||
* Whether to set default time zone
|
||||
* @var bool
|
||||
*/
|
||||
public $default_timezone = true;
|
||||
|
||||
/**
|
||||
* Whether to load default text domain
|
||||
* @var bool
|
||||
*/
|
||||
public $load_default_textdomain = true;
|
||||
|
||||
/**
|
||||
* Whether to check for maintenance mode and maybe die here
|
||||
* @var bool
|
||||
*/
|
||||
public $check_maintenance_mode = true;
|
||||
|
||||
/**
|
||||
* Whether to fix $_REQUEST for IIS
|
||||
* @var bool
|
||||
*/
|
||||
public $fix_request_uri = true;
|
||||
|
||||
/**
|
||||
* Whether to redirect to SSL if needed
|
||||
* @var bool
|
||||
*/
|
||||
public $redirect_ssl = true;
|
||||
|
||||
/**
|
||||
* Whether to include DB engine
|
||||
* @var bool
|
||||
*/
|
||||
public $include_db = true;
|
||||
|
||||
/**
|
||||
* Whether to include cache layer
|
||||
* @var bool
|
||||
*/
|
||||
public $include_cache = true;
|
||||
|
||||
/**
|
||||
* Whether to end instantiating early if YOURLS_FAST_INIT is defined and true
|
||||
* @var bool
|
||||
*/
|
||||
public $return_if_fast_init = true;
|
||||
|
||||
/**
|
||||
* Whether to read all options at once during starting
|
||||
* @var bool
|
||||
*/
|
||||
public $get_all_options = true;
|
||||
|
||||
/**
|
||||
* Whether to register shutdown action
|
||||
* @var bool
|
||||
*/
|
||||
public $register_shutdown = true;
|
||||
|
||||
/**
|
||||
* Whether to trigger action 'init' after core is loaded
|
||||
* @var bool
|
||||
*/
|
||||
public $core_loaded = true;
|
||||
|
||||
/**
|
||||
* Whether to redirect to install procedure if needed
|
||||
* @var bool
|
||||
*/
|
||||
public $redirect_to_install = true;
|
||||
|
||||
/**
|
||||
* Whether to redirect to upgrade procedure if needed
|
||||
* @var bool
|
||||
*/
|
||||
public $check_if_upgrade_needed = true;
|
||||
|
||||
/**
|
||||
* Whether to load all plugins
|
||||
* @var bool
|
||||
*/
|
||||
public $load_plugins = true;
|
||||
|
||||
/**
|
||||
* Whether to trigger the "plugins_loaded" action
|
||||
* @var bool
|
||||
*/
|
||||
public $plugins_loaded_action = true;
|
||||
|
||||
/**
|
||||
* Whether to check if a new version if available
|
||||
* @var bool
|
||||
*/
|
||||
public $check_new_version = true;
|
||||
|
||||
/**
|
||||
* Whether to trigger 'admin_init' if applicable
|
||||
* @var bool
|
||||
*/
|
||||
public $init_admin = true;
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Custom logger for YOURLS that logs debug messages and queries.
|
||||
*
|
||||
* Based on \Aura\Sql\Profiler\MemoryLogger
|
||||
*
|
||||
* @since 1.7.10
|
||||
*/
|
||||
|
||||
namespace YOURLS\Database;
|
||||
|
||||
use Psr\Log\AbstractLogger;
|
||||
|
||||
class Logger extends AbstractLogger {
|
||||
/**
|
||||
* Log messages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $messages = [];
|
||||
|
||||
/**
|
||||
* Logs a message.
|
||||
*
|
||||
* @param string $level The log level (ie type of message)
|
||||
* @param string $message The log message.
|
||||
* @param array $context Data to interpolate into the message.
|
||||
*
|
||||
* The logger receives the following:
|
||||
*
|
||||
* From yourls_debug("something went wrong") :
|
||||
* $level : string 'debug'
|
||||
* $message : string 'something went wrong'
|
||||
* $context : array()
|
||||
* See yourls_debug() in includes/functions-debug.php
|
||||
*
|
||||
* From a query that triggers the internal logging of Aura SQL :
|
||||
* $level : string 'query'
|
||||
* $message : string '{function} ({duration} seconds): {statement} {backtrace}'
|
||||
* (which is the default $logFormat from Aura\Sql\Profiler\Profiler), we're not using it)
|
||||
* $context : array(
|
||||
* 'function' => string 'perform'
|
||||
* 'duration' => float 0.0025360584259033
|
||||
* 'statement' => string 'SELECT `keyword`,`url` FROM `yourls_url` WHERE `url` LIKE (:url)'
|
||||
* 'values' => array('url' => '%rss%')
|
||||
* )
|
||||
* See finish() in Aura\Sql\Profiler\Profiler
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log($level, $message, array $context = []) {
|
||||
// if it's an internal SQL query, format the message, otherwise store a string
|
||||
if($level === 'query') {
|
||||
$this->messages[] = sprintf(
|
||||
'SQL %s: %s (%s s)',
|
||||
$context['function'],
|
||||
$this->pretty_format($context['statement'], $context['values']),
|
||||
number_format($context['duration'], 5)
|
||||
);
|
||||
} else {
|
||||
$this->messages[] = (string)$message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logged messages.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessages() {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format PDO statement with bind/values replacement
|
||||
*
|
||||
* This replaces PDO binds such as 'key_name = :name' with corresponding array values, eg array('name'=>'some value')
|
||||
* This is merely a cosmetic replacement to allow for readability: the result WILL NOT be valid SQL! (eg no proper quotes)
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @param string $statement SQL query with PDO style named placeholders
|
||||
* @param array $values Optional array of values corresponding to placeholders
|
||||
* @return string Readable SQL query with placeholders replaced
|
||||
*/
|
||||
public function pretty_format($statement, array $values = array() ) {
|
||||
if (!$values) {
|
||||
return $statement;
|
||||
}
|
||||
|
||||
return preg_replace_callback(
|
||||
'/:([^\s;)]*)/',
|
||||
|
||||
/**
|
||||
* @param string $matches
|
||||
*/
|
||||
function ($matches) use ($values) {
|
||||
$replacement = isset( $values[$matches[1]] ) ? $values[$matches[1]] : '';
|
||||
if(is_array($replacement)) {
|
||||
$replacement = implode(",", $replacement);
|
||||
}
|
||||
return "'$replacement'";
|
||||
},
|
||||
$statement
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* YOURLS Options
|
||||
*
|
||||
* Note to plugin authors: you most likely SHOULD NOT use directly methods and properties of this class. Use instead
|
||||
* function wrappers (eg don't use $ydb->option, or $ydb->get(), use yourls_*_options() functions instead).
|
||||
*
|
||||
* Note to devs: this class internally uses function wrappers eg yourls_*_options() instead of direct methods, to
|
||||
* comply to any filter set in the function wrappers (eg $this->update() uses yourls_get_option()).
|
||||
* Maybe in the future this will look as a dumb idea?
|
||||
* The alternative would be to move return filters from function wrappers to here, but I think this will make things
|
||||
* less readable for users.
|
||||
*
|
||||
* @since 1.7.3
|
||||
*/
|
||||
|
||||
namespace YOURLS\Database;
|
||||
|
||||
use YOURLS\Database\YDB;
|
||||
use PDOException;
|
||||
|
||||
class Options {
|
||||
|
||||
/**
|
||||
* Hold a copy of the all mighty $ydb global
|
||||
*
|
||||
* @var \YOURLS\Database\YDB
|
||||
*/
|
||||
protected $ydb;
|
||||
|
||||
public function __construct(YDB $ydb) {
|
||||
$this->ydb = $ydb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all options from DB at once, return bool
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @see yourls_get_all_options()
|
||||
* @return bool True on success, false on failure (eg table missing or empty)
|
||||
*/
|
||||
public function get_all_options() {
|
||||
// Get option values from DB
|
||||
$table = YOURLS_DB_TABLE_OPTIONS;
|
||||
$sql = "SELECT option_name, option_value FROM $table WHERE 1=1";
|
||||
|
||||
try {
|
||||
$options = (array) $this->ydb->fetchPairs($sql);
|
||||
|
||||
} catch ( PDOException $e ) {
|
||||
|
||||
// We could not fetch value from the table. Let's check if the option table exists
|
||||
try {
|
||||
$check = $this->ydb->fetchAffected(sprintf("SHOW TABLES LIKE '%s'", $table));
|
||||
// Table doesn't exist
|
||||
if ($check ==0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Error at this point means the database isn't readable
|
||||
} catch ( PDOException $e ) {
|
||||
$this->ydb->dead_or_error($e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Unlikely scenario, but who knows: table exists, but is empty
|
||||
if (empty($options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($options as $name => $value) {
|
||||
$this->ydb->set_option($name, yourls_maybe_unserialize($value));
|
||||
}
|
||||
|
||||
yourls_apply_filter('get_all_options', 'deprecated');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get option value from DB (or from cache if available). Return value or $default if not found
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @see yourls_get_option()
|
||||
* @param string $name Option name
|
||||
* @param string $default Value to return if option doesn't exist
|
||||
* @return mixed Value set for the option
|
||||
*/
|
||||
public function get($name, $default) {
|
||||
$name = trim((string)$name);
|
||||
if (empty($name)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
// Check if option value is cached already
|
||||
if($this->ydb->has_option($name)) {
|
||||
return $this->ydb->get_option($name);
|
||||
}
|
||||
|
||||
// Get option value from DB
|
||||
$table = YOURLS_DB_TABLE_OPTIONS;
|
||||
$sql = "SELECT option_value FROM $table WHERE option_name = :option_name LIMIT 1";
|
||||
$bind = array('option_name' => $name);
|
||||
|
||||
// Use fechOne() to get array('option_value'=>$value), or false if not found.
|
||||
// This way, we can effectively store false as an option value, and not confuse with false as the default return value
|
||||
$value = $this->ydb->fetchOne($sql, $bind);
|
||||
if($value !== false) {
|
||||
$value = yourls_maybe_unserialize( $value['option_value'] );
|
||||
// Cache option value to save a DB query if needed later
|
||||
$this->ydb->set_option($name, $value);
|
||||
} else {
|
||||
$value = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't cache value if option is not set, to make a difference between "not found: returning false"
|
||||
* and "found, and value is false".
|
||||
* This way, we can:
|
||||
* $check = yourls_get_option('doesnt_exist'); // false
|
||||
* yourls_add_option('doesnt_exist', 'value'); // will work, because check on has_option() will return false
|
||||
*/
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update (add if doesn't exist) an option to DB
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @see yourls_update_option()
|
||||
* @param string $name Option name. Expected to not be SQL-escaped.
|
||||
* @param mixed $newvalue Option value.
|
||||
* @return bool False if value was not updated, true otherwise.
|
||||
*/
|
||||
public function update($name, $newvalue) {
|
||||
$name = trim((string)$name);
|
||||
if (empty($name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use clone to break object refs -- see commit 09b989d375bac65e692277f61a84fede2fb04ae3
|
||||
if (is_object($newvalue)) {
|
||||
$newvalue = clone $newvalue;
|
||||
}
|
||||
|
||||
$oldvalue = yourls_get_option($name);
|
||||
|
||||
// If the new and old values are the same, no need to update.
|
||||
if ($newvalue === $oldvalue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a new option, just add it
|
||||
if (false === $oldvalue) {
|
||||
return $this->add($name, $newvalue);
|
||||
}
|
||||
|
||||
$_newvalue = yourls_maybe_serialize($newvalue);
|
||||
$table = YOURLS_DB_TABLE_OPTIONS;
|
||||
$sql = "UPDATE $table SET option_value = :value WHERE option_name = :name";
|
||||
$bind = array('name' => $name, 'value' => $_newvalue);
|
||||
$do = $this->ydb->fetchAffected($sql, $bind);
|
||||
|
||||
if($do !== 1) {
|
||||
// Something went wrong :(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache option value to save a DB query if needed later
|
||||
$this->ydb->set_option($name, $newvalue);
|
||||
yourls_do_action( 'update_option', $name, $oldvalue, $newvalue );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an option to the DB
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @see yourls_add_option()
|
||||
* @param string $name Name of option to add. Expected to not be SQL-escaped.
|
||||
* @param mixed $value Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
|
||||
* @return bool False if option was not added (eg already exists), true otherwise.
|
||||
*/
|
||||
public function add($name, $value) {
|
||||
$name = trim((string)$name);
|
||||
if (empty($name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use clone to break object refs -- see commit 09b989d375bac65e692277f61a84fede2fb04ae3
|
||||
if (is_object($value)) {
|
||||
$value = clone $value;
|
||||
}
|
||||
|
||||
// Make sure the option doesn't already exist
|
||||
if ($this->ydb->has_option($name)) {
|
||||
return false;
|
||||
}
|
||||
// if (false !== yourls_get_option($name)) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
$table = YOURLS_DB_TABLE_OPTIONS;
|
||||
$_value = yourls_maybe_serialize($value);
|
||||
$sql = "INSERT INTO $table (option_name, option_value) VALUES (:name, :value)";
|
||||
$bind = array('name' => $name, 'value' => $_value);
|
||||
$do = $this->ydb->fetchAffected($sql, $bind);
|
||||
|
||||
if($do !== 1) {
|
||||
// Something went wrong :(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache option value to save a DB query if needed later
|
||||
$this->ydb->set_option($name, $value);
|
||||
yourls_do_action('add_option', $name, $_value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete option from DB
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @see yourls_delete_option()
|
||||
* @param string $name Option name to delete. Expected to not be SQL-escaped.
|
||||
* @return bool False if option was not deleted (eg not found), true otherwise.
|
||||
*/
|
||||
public function delete($name) {
|
||||
$name = trim((string)$name);
|
||||
if (empty($name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = YOURLS_DB_TABLE_OPTIONS;
|
||||
$sql = "DELETE FROM $table WHERE option_name = :name";
|
||||
$bind = array('name' => $name);
|
||||
$do = $this->ydb->fetchAffected($sql, $bind);
|
||||
|
||||
if($do !== 1) {
|
||||
// Something went wrong :(
|
||||
return false;
|
||||
}
|
||||
|
||||
yourls_do_action('delete_option', $name);
|
||||
$this->ydb->delete_option($name);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Custom profiler for YOURLS
|
||||
*
|
||||
* Based on \Aura\Sql\Profiler\Profiler to tweak function finish()
|
||||
*
|
||||
* @since 1.7.10
|
||||
*/
|
||||
|
||||
namespace YOURLS\Database;
|
||||
|
||||
class Profiler extends \Aura\Sql\Profiler\Profiler {
|
||||
/**
|
||||
*
|
||||
* Finishes and logs a profile entry.
|
||||
*
|
||||
* We're just overriding the original class finish() to
|
||||
* - not throw an exception and collect a backtrace that will remain unused
|
||||
* - not flatten the array of 'values' into a string
|
||||
*
|
||||
* @param string $statement The statement being profiled, if any.
|
||||
* @param array $values The values bound to the statement, if any.
|
||||
* @return void
|
||||
*/
|
||||
public function finish($statement = null, array $values = [])
|
||||
{
|
||||
if (! $this->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->context['duration'] = microtime(true) - $this->context['start'];
|
||||
$this->context['statement'] = $statement;
|
||||
$this->context['values'] = (array)$values;
|
||||
|
||||
$this->logger->log($this->logLevel, $this->logFormat, $this->context);
|
||||
|
||||
$this->context = [];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,423 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Aura SQL wrapper for YOURLS that creates the allmighty YDB object.
|
||||
*
|
||||
* A fine example of a "class that knows too much" (see https://en.wikipedia.org/wiki/God_object)
|
||||
*
|
||||
* Note to plugin authors: you most likely SHOULD NOT use directly methods and properties of this class. Use instead
|
||||
* function wrappers (eg don't use $ydb->option, or $ydb->set_option(), use yourls_*_options() functions instead).
|
||||
*
|
||||
* @since 1.7.3
|
||||
*/
|
||||
|
||||
namespace YOURLS\Database;
|
||||
|
||||
use \Aura\Sql\ExtendedPdo;
|
||||
use \YOURLS\Database\Profiler;
|
||||
use \YOURLS\Database\Logger;
|
||||
use PDO;
|
||||
|
||||
class YDB extends ExtendedPdo {
|
||||
|
||||
/**
|
||||
* Debug mode, default false
|
||||
* @var bool
|
||||
*/
|
||||
protected $debug = false;
|
||||
|
||||
/**
|
||||
* Page context (ie "infos", "bookmark", "plugins"...)
|
||||
* @var string
|
||||
*/
|
||||
protected $context = '';
|
||||
|
||||
/**
|
||||
* Information related to a short URL keyword (eg timestamp, long URL, ...)
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
*/
|
||||
protected $infos = [];
|
||||
|
||||
/**
|
||||
* Is YOURLS installed and ready to run?
|
||||
* @var bool
|
||||
*/
|
||||
protected $installed = false;
|
||||
|
||||
/**
|
||||
* Options
|
||||
* @var array
|
||||
*/
|
||||
protected $option = [];
|
||||
|
||||
/**
|
||||
* Plugin admin pages informations
|
||||
* @var array
|
||||
*/
|
||||
protected $plugin_pages = [];
|
||||
|
||||
/**
|
||||
* Plugin informations
|
||||
* @var array
|
||||
*/
|
||||
protected $plugins = [];
|
||||
|
||||
/**
|
||||
* Are we emulating prepare statements ?
|
||||
* @var bool
|
||||
*/
|
||||
protected $is_emulate_prepare;
|
||||
|
||||
/**
|
||||
* @since 1.7.3
|
||||
* @param string $dsn The data source name
|
||||
* @param string $user The username
|
||||
* @param string $pass The password
|
||||
* @param array $options Driver-specific options
|
||||
* @param array $attributes Attributes to set after a connection
|
||||
*/
|
||||
public function __construct($dsn, $user, $pass, $options, $attributes) {
|
||||
parent::__construct($dsn, $user, $pass, $options, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init everything needed
|
||||
*
|
||||
* Everything we need to set up is done here in init(), not in the constructor, so even
|
||||
* when the connection fails (eg config error or DB dead), the constructor has worked
|
||||
* and we have a $ydb object properly instantiated (and for instance yourls_die() can
|
||||
* correctly die, even if using $ydb methods)
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
$this->connect_to_DB();
|
||||
|
||||
$this->set_emulate_state();
|
||||
|
||||
$this->start_profiler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we emulate prepare statements, and set bool flag accordingly
|
||||
*
|
||||
* Check if current driver can PDO::getAttribute(PDO::ATTR_EMULATE_PREPARES)
|
||||
* Some combinations of PHP/MySQL don't support this function. See
|
||||
* https://travis-ci.org/YOURLS/YOURLS/jobs/271423782#L481
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
*/
|
||||
public function set_emulate_state() {
|
||||
try {
|
||||
$this->is_emulate_prepare = $this->getAttribute(PDO::ATTR_EMULATE_PREPARES);
|
||||
} catch (\PDOException $e) {
|
||||
$this->is_emulate_prepare = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get emulate status
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return bool
|
||||
*/
|
||||
public function get_emulate_state() {
|
||||
return $this->is_emulate_prepare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate real connection to DB server
|
||||
*
|
||||
* This is to check that the server is running and/or the config is OK
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return void
|
||||
* @throws \PDOException
|
||||
*/
|
||||
public function connect_to_DB() {
|
||||
try {
|
||||
$this->connect();
|
||||
} catch ( \Exception $e ) {
|
||||
$this->dead_or_error($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die with an error message
|
||||
*
|
||||
* @since 1.7.3
|
||||
*
|
||||
* @param \Exception $exception
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dead_or_error(\Exception $exception) {
|
||||
// Use any /user/db_error.php file
|
||||
if( file_exists( YOURLS_USERDIR . '/db_error.php' ) ) {
|
||||
include_once( YOURLS_USERDIR . '/db_error.php' );
|
||||
die();
|
||||
}
|
||||
|
||||
$message = yourls__( 'Incorrect DB config, or could not connect to DB' );
|
||||
$message .= '<br/>' . get_class($exception) .': ' . $exception->getMessage();
|
||||
|
||||
yourls_die( yourls__( $message ), yourls__( 'Fatal error' ), 503 );
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a Message Logger
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @see \Aura\Sql\Profiler\Profiler
|
||||
* @see \Aura\Sql\Profiler\MemoryLogger
|
||||
* @return void
|
||||
*/
|
||||
public function start_profiler() {
|
||||
// Instantiate a custom logger and make it the profiler
|
||||
$yourls_logger = new Logger();
|
||||
$profiler = new Profiler($yourls_logger);
|
||||
$this->setProfiler($profiler);
|
||||
|
||||
/* By default, make "query" the log level. This way, each internal logging triggered
|
||||
* by Aura SQL will be a "query", and logging triggered by yourls_debug() will be
|
||||
* a "message". See includes/functions-debug.php:yourls_debug()
|
||||
*/
|
||||
$profiler->setLoglevel('query');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @return void
|
||||
*/
|
||||
public function set_html_context($context) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_html_context() {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
// Options low level functions, see \YOURLS\Database\Options
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function set_option($name, $value) {
|
||||
$this->option[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function has_option($name) {
|
||||
return array_key_exists($name, $this->option);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function get_option($name) {
|
||||
return $this->option[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function delete_option($name) {
|
||||
unset($this->option[$name]);
|
||||
}
|
||||
|
||||
|
||||
// Infos (related to keyword) low level functions
|
||||
|
||||
/**
|
||||
* @param string $keyword
|
||||
* @param mixed $infos
|
||||
* @return void
|
||||
*/
|
||||
public function set_infos($keyword, $infos) {
|
||||
$this->infos[$keyword] = $infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keyword
|
||||
* @return bool
|
||||
*/
|
||||
public function has_infos($keyword) {
|
||||
return array_key_exists($keyword, $this->infos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keyword
|
||||
* @return array
|
||||
*/
|
||||
public function get_infos($keyword) {
|
||||
return $this->infos[$keyword];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keyword
|
||||
* @return void
|
||||
*/
|
||||
public function delete_infos($keyword) {
|
||||
unset($this->infos[$keyword]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo: infos & options are working the same way here. Abstract this.
|
||||
*/
|
||||
|
||||
|
||||
// Plugin low level functions, see functions-plugins.php
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_plugins() {
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $plugins
|
||||
* @return void
|
||||
*/
|
||||
public function set_plugins(array $plugins) {
|
||||
$this->plugins = $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin plugin filename
|
||||
* @return void
|
||||
*/
|
||||
public function add_plugin($plugin) {
|
||||
$this->plugins[] = $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin plugin filename
|
||||
* @return void
|
||||
*/
|
||||
public function remove_plugin($plugin) {
|
||||
unset($this->plugins[$plugin]);
|
||||
}
|
||||
|
||||
|
||||
// Plugin Pages low level functions, see functions-plugins.php
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_plugin_pages() {
|
||||
return is_array( $this->plugin_pages ) ? $this->plugin_pages : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $pages
|
||||
* @return void
|
||||
*/
|
||||
public function set_plugin_pages(array $pages) {
|
||||
$this->plugin_pages = $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $slug
|
||||
* @param string $title
|
||||
* @param callable $function
|
||||
* @return void
|
||||
*/
|
||||
public function add_plugin_page( $slug, $title, $function ) {
|
||||
$this->plugin_pages[ $slug ] = [
|
||||
'slug' => $slug,
|
||||
'title' => $title,
|
||||
'function' => $function,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $slug
|
||||
* @return void
|
||||
*/
|
||||
public function remove_plugin_page( $slug ) {
|
||||
unset( $this->plugin_pages[ $slug ] );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return count of SQL queries performed
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return int
|
||||
*/
|
||||
public function get_num_queries() {
|
||||
return count( (array) $this->get_queries() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return SQL queries performed
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return array
|
||||
*/
|
||||
public function get_queries() {
|
||||
$queries = $this->getProfiler()->getLogger()->getMessages();
|
||||
|
||||
// Only keep messages that start with "SQL "
|
||||
$queries = array_filter($queries, function($query) {return substr( $query, 0, 4 ) === "SQL ";});
|
||||
|
||||
return $queries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set YOURLS installed state
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @param bool $bool
|
||||
* @return void
|
||||
*/
|
||||
public function set_installed($bool) {
|
||||
$this->installed = $bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get YOURLS installed state
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return bool
|
||||
*/
|
||||
public function is_installed() {
|
||||
return $this->installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return standardized DB version
|
||||
*
|
||||
* The regex removes everything that's not a number at the start of the string, or remove anything that's not a number and what
|
||||
* follows after that.
|
||||
* 'omgmysql-5.5-ubuntu-4.20' => '5.5'
|
||||
* 'mysql5.5-ubuntu-4.20' => '5.5'
|
||||
* '5.5-ubuntu-4.20' => '5.5'
|
||||
* '5.5-beta2' => '5.5'
|
||||
* '5.5' => '5.5'
|
||||
*
|
||||
* @since 1.7.3
|
||||
* @return string
|
||||
*/
|
||||
public function mysql_version() {
|
||||
$version = $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
return $version;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace YOURLS\Exceptions;
|
||||
|
||||
class ConfigException extends \Exception {}
|
|
@ -0,0 +1,280 @@
|
|||
<?php
|
||||
/**
|
||||
* Parameters used to display links the admin view (eg admin/index.php)
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
|
||||
namespace YOURLS\Views;
|
||||
|
||||
/**
|
||||
* Class AdminParams to get admin view parameters (number of links to display, search, ...)
|
||||
*
|
||||
* @since 1.8.2
|
||||
* @package YOURLS\Views
|
||||
*/
|
||||
class AdminParams
|
||||
{
|
||||
|
||||
/**
|
||||
* All possible search parameters. Populated in the constructor.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $possible_search_params;
|
||||
|
||||
/**
|
||||
* All possible sort parameters. Populated in the constructor.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $possible_sort_params;
|
||||
|
||||
/**
|
||||
* All possible date sorting parameters. Populated in the constructor.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $possible_date_sorting;
|
||||
|
||||
/**
|
||||
* Parameter translations. Populated in the constructor.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $params_translations;
|
||||
|
||||
|
||||
/**
|
||||
* Admin constructor : populate all default parameters
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Cast return values of yourls_apply_filter() to array in case a hook would incorrectly return something else
|
||||
$this->possible_search_params = (array)yourls_apply_filter('admin_params_possible_search',
|
||||
['all', 'keyword', 'url', 'title', 'ip']);
|
||||
$this->possible_sort_params = (array)yourls_apply_filter('admin_params_possible_sort',
|
||||
['keyword', 'url', 'title', 'ip', 'timestamp', 'clicks']);
|
||||
$this->params_translations = (array)yourls_apply_filter('admin_params_possible_translations',[
|
||||
'all' => yourls__('All fields'),
|
||||
'keyword' => yourls__('Short URL'),
|
||||
'url' => yourls__('URL'),
|
||||
'title' => yourls__('Title'),
|
||||
'ip' => yourls__('IP Address'),
|
||||
'timestamp' => yourls__('Date'),
|
||||
'clicks' => yourls__('Clicks'),
|
||||
]);
|
||||
$this->possible_date_sorting = (array)yourls_apply_filter('admin_params_possible_date_sort',
|
||||
['before', 'after', 'between']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of links to display per page
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param int $default default number of links to display
|
||||
* @return int
|
||||
*/
|
||||
public function get_per_page(int $default): int
|
||||
{
|
||||
// return if we have a value and it's not 0
|
||||
if (isset($_GET['perpage']) && intval($_GET['perpage'])) {
|
||||
$per_page = intval($_GET['perpage']);
|
||||
// otherwise return filtered default value
|
||||
} else {
|
||||
// @hook Default number of links to display (value provided by caller eg /admin/index.php)
|
||||
$per_page = yourls_apply_filter('admin_view_per_page', $default);
|
||||
}
|
||||
|
||||
return $per_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current page number to be displayed
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_page(): int
|
||||
{
|
||||
return isset($_GET['page']) ? intval($_GET['page']) : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get search text (the 'Search for') from query string variables search_protocol, search_slashes and search
|
||||
*
|
||||
* Some servers don't like query strings containing "(ht|f)tp(s)://". A javascript bit
|
||||
* explodes the search text into protocol, slashes and the rest (see JS function
|
||||
* split_search_text_before_search()) and this function glues pieces back together
|
||||
* See issue https://github.com/YOURLS/YOURLS/issues/1576
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_search(): string
|
||||
{
|
||||
$search = '';
|
||||
if (isset($_GET['search_protocol'])) {
|
||||
$search .= $_GET['search_protocol'];
|
||||
}
|
||||
if (isset($_GET['search_slashes'])) {
|
||||
$search .= $_GET['search_slashes'];
|
||||
}
|
||||
if (isset($_GET['search'])) {
|
||||
$search .= $_GET['search'];
|
||||
}
|
||||
|
||||
// @hook Default search text in links displayed
|
||||
return yourls_apply_filter('admin_view_get_search_text', htmlspecialchars(trim($search)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'Search In' parameter (one of 'all', 'keyword', 'url', 'title', 'ip')
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_search_in(): string
|
||||
{
|
||||
if (isset($_GET['search_in']) && in_array($_GET['search_in'], $this->possible_search_params)) {
|
||||
$search_in = $_GET['search_in'];
|
||||
} else {
|
||||
// @hook Default searching in the admin view (in all fields)
|
||||
$search_in = yourls_apply_filter('admin_view_search_in', 'all');
|
||||
}
|
||||
|
||||
return $search_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'Sort by' parameter
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_sort_by(): string
|
||||
{
|
||||
if (isset($_GET['sort_by']) && in_array($_GET['sort_by'], $this->possible_sort_params)) {
|
||||
$sort_by = $_GET['sort_by'];
|
||||
} else {
|
||||
// @hook Default sorting in the admin view (by Timestamp)
|
||||
$sort_by = yourls_apply_filter('admin_view_sort_by', 'timestamp');
|
||||
}
|
||||
|
||||
return $sort_by;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the correct phrasing associated to a search or sort parameter (ie 'all' -> 'All fields' for instance)
|
||||
*
|
||||
* No checks : you need to supply an existing parameter, see $params_translations
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param string $param
|
||||
* @return string
|
||||
*/
|
||||
public function get_param_long_name(string $param): string
|
||||
{
|
||||
return $this->params_translations[$param];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sort order (asc or desc)
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_sort_order()
|
||||
{
|
||||
// @hook Default sorting order in the admin view (descending)
|
||||
return isset($_GET['sort_order']) && $_GET['sort_order'] == 'asc' ? 'asc' : yourls_apply_filter('admin_view_sort_order', 'desc');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the click "more or less than"
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_click_filter()
|
||||
{
|
||||
// @hook Default 'Show links with more/less than' ('more')
|
||||
return isset($_GET['click_filter']) && $_GET['click_filter'] == 'less' ? 'less' : yourls_apply_filter('admin_view_click_filter', 'more');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the click threshold
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public function get_click_limit()
|
||||
{
|
||||
// @hook Default link click threshold (unset)
|
||||
return (isset($_GET['click_limit']) && intval($_GET['click_limit'])) ?
|
||||
intval($_GET['click_limit']) : yourls_apply_filter('admin_view_click_limit', '');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the date parameters : the date "filter" and the two dates
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_date_params(): array
|
||||
{
|
||||
if (isset($_GET['date_filter']) && in_array($_GET['date_filter'], $this->possible_date_sorting)) {
|
||||
$date_filter = $_GET['date_filter'];
|
||||
} else {
|
||||
// @hook Default date filtering (unset)
|
||||
$date_filter = yourls_apply_filter('admin_view_date_filter', '');
|
||||
}
|
||||
|
||||
switch ($date_filter) {
|
||||
case 'after':
|
||||
case 'before':
|
||||
if (isset($_GET['date_first']) && yourls_sanitize_date($_GET['date_first'])) {
|
||||
$date_first = yourls_sanitize_date($_GET['date_first']);
|
||||
} else {
|
||||
// @hook Default date when date filter is either 'after' or 'before' (unset)
|
||||
// In such case, the filter is either 'admin_view_date_first_after' or 'admin_view_date_first_before'
|
||||
$date_first = yourls_apply_filter('admin_view_date_first_' . $date_filter, '');
|
||||
}
|
||||
$date_second = '';
|
||||
break;
|
||||
|
||||
case 'between':
|
||||
if (isset($_GET['date_first']) && isset($_GET['date_second']) && yourls_sanitize_date($_GET['date_first']) && yourls_sanitize_date($_GET['date_second'])) {
|
||||
$date_first = yourls_sanitize_date($_GET['date_first']);
|
||||
$date_second = yourls_sanitize_date($_GET['date_second']);
|
||||
} else {
|
||||
// @hook Default dates when date filter is 'between' (unset)
|
||||
$date_first = yourls_apply_filter('admin_view_date_first_between', '');
|
||||
$date_second = yourls_apply_filter('admin_view_date_second_between', '');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// @hook Default date when date filter is unset (unset)
|
||||
$date_first = yourls_apply_filter('admin_view_date_first_unset', '');
|
||||
$date_second = yourls_apply_filter('admin_view_date_second_unset', '');
|
||||
|
||||
}
|
||||
|
||||
return ['date_filter' => $date_filter, 'date_first' => $date_first, 'date_second' => $date_second];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Database and Contents Copyright (c) 2022 MaxMind, Inc.
|
|
@ -0,0 +1,3 @@
|
|||
Use of this MaxMind product is governed by MaxMind's GeoLite2 End User License Agreement, which can be viewed at https://www.maxmind.com/en/geolite2/eula.
|
||||
|
||||
This database incorporates GeoNames [https://www.geonames.org] geographical data, which is made available under the Creative Commons Attribution 4.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by/4.0/.
|
|
@ -0,0 +1,23 @@
|
|||
GeoIP package for YOURLS
|
||||
========================
|
||||
|
||||
YOURLS includes GeoLite2 data created by MaxMind, available from [maxmind.com](https://www.maxmind.com)
|
||||
For more information on the the DB file (`GeoLite2-Country.mmdb`), see [Geolite2](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data?lang=en).
|
||||
|
||||
Flag files from this package come from various sources.
|
||||
|
||||
|
||||
IP to country Database
|
||||
----------------------
|
||||
|
||||
YOURLS people update the DB here from time to time. To manually update the DB, register an account on maxmind.com and replace `GeoLite2-Country.mmdb` here with a newer version.
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Database and Contents Copyright (c) 2021 MaxMind, Inc.
|
||||
|
||||
Use of this MaxMind product is governed by MaxMind's GeoLite2 End User License Agreement, which can be viewed at https://www.maxmind.com/en/geolite2/eula.
|
||||
|
||||
This database incorporates GeoNames [https://www.geonames.org] geographical data, which is made available under the Creative Commons Attribution 4.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by/4.0/.
|
After Width: | Height: | Size: 218 B |
After Width: | Height: | Size: 980 B |
After Width: | Height: | Size: 980 B |
After Width: | Height: | Size: 588 B |
After Width: | Height: | Size: 169 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 489 B |
After Width: | Height: | Size: 588 B |
After Width: | Height: | Size: 1005 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 901 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 588 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 229 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1005 B |
After Width: | Height: | Size: 1003 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 998 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1005 B |
After Width: | Height: | Size: 995 B |
After Width: | Height: | Size: 1000 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1004 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 175 B |
After Width: | Height: | Size: 999 B |
After Width: | Height: | Size: 995 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1005 B |
After Width: | Height: | Size: 326 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1001 B |
After Width: | Height: | Size: 1004 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 579 B |
After Width: | Height: | Size: 999 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 217 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 588 B |
After Width: | Height: | Size: 1005 B |