[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/includes/Database/ -> YDB.php (source)

   1  <?php
   2  
   3  /**
   4   * Aura SQL wrapper for YOURLS that creates the allmighty YDB object.
   5   *
   6   * A fine example of a "class that knows too much" (see https://en.wikipedia.org/wiki/God_object)
   7   *
   8   * Note to plugin authors: you most likely SHOULD NOT use directly methods and properties of this class. Use instead
   9   * function wrappers (eg don't use $ydb->option, or $ydb->set_option(), use yourls_*_options() functions instead).
  10   *
  11   * @since 1.7.3
  12   */
  13  
  14  namespace YOURLS\Database;
  15  
  16  use \Aura\Sql\ExtendedPdo;
  17  use \YOURLS\Database\Profiler;
  18  use \YOURLS\Database\Logger;
  19  use PDO;
  20  
  21  class YDB extends ExtendedPdo {
  22  
  23      /**
  24       * Debug mode, default false
  25       * @var bool
  26       */
  27      protected $debug = false;
  28  
  29      /**
  30       * Page context (ie "infos", "bookmark", "plugins"...)
  31       * @var string
  32       */
  33      protected $context = '';
  34  
  35      /**
  36       * Information related to a short URL keyword (eg timestamp, long URL, ...)
  37       *
  38       * @var array
  39       *
  40       */
  41      protected $infos = [];
  42  
  43      /**
  44       * Is YOURLS installed and ready to run?
  45       * @var bool
  46       */
  47      protected $installed = false;
  48  
  49      /**
  50       * Options
  51       * @var array
  52       */
  53      protected $option = [];
  54  
  55      /**
  56       * Plugin admin pages informations
  57       * @var array
  58       */
  59      protected $plugin_pages = [];
  60  
  61      /**
  62       * Plugin informations
  63       * @var array
  64       */
  65      protected $plugins = [];
  66  
  67      /**
  68       * Are we emulating prepare statements ?
  69       * @var bool
  70       */
  71      protected $is_emulate_prepare;
  72  
  73      /**
  74       * @since 1.7.3
  75       * @param string $dsn         The data source name
  76       * @param string $user        The username
  77       * @param string $pass        The password
  78       * @param array  $options     Driver-specific options
  79       * @param array  $attributes  Attributes to set after a connection
  80       */
  81      public function __construct($dsn, $user, $pass, $options) {
  82          parent::__construct($dsn, $user, $pass, $options);
  83      }
  84  
  85      /**
  86       * Init everything needed
  87       *
  88       * Everything we need to set up is done here in init(), not in the constructor, so even
  89       * when the connection fails (eg config error or DB dead), the constructor has worked
  90       * and we have a $ydb object properly instantiated (and for instance yourls_die() can
  91       * correctly die, even if using $ydb methods)
  92       *
  93       * @since  1.7.3
  94       * @return void
  95       */
  96      public function init() {
  97          $this->connect_to_DB();
  98  
  99          $this->set_emulate_state();
 100  
 101          $this->start_profiler();
 102      }
 103  
 104      /**
 105       * Check if we emulate prepare statements, and set bool flag accordingly
 106       *
 107       * Check if current driver can PDO::getAttribute(PDO::ATTR_EMULATE_PREPARES)
 108       * Some combinations of PHP/MySQL don't support this function. See
 109       * https://travis-ci.org/YOURLS/YOURLS/jobs/271423782#L481
 110       *
 111       * @since  1.7.3
 112       * @return void
 113       */
 114      public function set_emulate_state() {
 115          try {
 116              $this->is_emulate_prepare = $this->getAttribute(PDO::ATTR_EMULATE_PREPARES);
 117          } catch (\PDOException $e) {
 118              $this->is_emulate_prepare = false;
 119          }
 120      }
 121  
 122      /**
 123       * Get emulate status
 124       *
 125       * @since  1.7.3
 126       * @return bool
 127       */
 128      public function get_emulate_state() {
 129          return $this->is_emulate_prepare;
 130      }
 131  
 132      /**
 133       * Initiate real connection to DB server
 134       *
 135       * This is to check that the server is running and/or the config is OK
 136       *
 137       * @since  1.7.3
 138       * @return void
 139       * @throws \PDOException
 140       */
 141      public function connect_to_DB() {
 142          try {
 143              list($dsn, $_user, $_pwd, $_opt, $_queries) = $this->args;
 144              $this->connect($dsn);
 145          } catch ( \Exception $e ) {
 146              $this->dead_or_error($e);
 147          }
 148      }
 149  
 150      /**
 151       * Die with an error message
 152       *
 153       * @since  1.7.3
 154       *
 155       * @param \Exception $exception
 156       *
 157       * @return void
 158       */
 159      public function dead_or_error(\Exception $exception) {
 160          // Use any /user/db_error.php file
 161          $file = YOURLS_USERDIR . '/db_error.php';
 162          if(file_exists($file)) {
 163              if(yourls_include_file_sandbox( $file ) === true) {
 164                  die();
 165              }
 166          }
 167  
 168          $message  = yourls__( 'Incorrect DB config, or could not connect to DB' );
 169          $message .= '<br/>' . get_class($exception) .': ' . $exception->getMessage();
 170          yourls_die( yourls__( $message ), yourls__( 'Fatal error' ), 503 );
 171          die();
 172  
 173      }
 174  
 175      /**
 176       * Start a Message Logger
 177       *
 178       * @since  1.7.3
 179       * @see    \Aura\Sql\Profiler\Profiler
 180       * @see    \Aura\Sql\Profiler\MemoryLogger
 181       * @return void
 182       */
 183      public function start_profiler() {
 184          // Instantiate a custom logger and make it the profiler
 185          $yourls_logger = new Logger();
 186          $profiler = new Profiler($yourls_logger);
 187          $this->setProfiler($profiler);
 188  
 189          /* By default, make "query" the log level. This way, each internal logging triggered
 190           * by Aura SQL will be a "query", and logging triggered by yourls_debug() will be
 191           * a "message". See includes/functions-debug.php:yourls_debug()
 192           */
 193          $profiler->setLoglevel('query');
 194      }
 195  
 196      /**
 197       * @param string $context
 198       * @return void
 199       */
 200      public function set_html_context($context) {
 201          $this->context = $context;
 202      }
 203  
 204      /**
 205       * @return string
 206       */
 207      public function get_html_context() {
 208          return $this->context;
 209      }
 210  
 211      // Options low level functions, see \YOURLS\Database\Options
 212  
 213      /**
 214       * @param string $name
 215       * @param mixed  $value
 216       * @return void
 217       */
 218      public function set_option($name, $value) {
 219          $this->option[$name] = $value;
 220      }
 221  
 222      /**
 223       * @param  string $name
 224       * @return bool
 225       */
 226      public function has_option($name) {
 227          return array_key_exists($name, $this->option);
 228      }
 229  
 230      /**
 231       * @param  string $name
 232       * @return string
 233       */
 234      public function get_option($name) {
 235          return $this->option[$name];
 236      }
 237  
 238      /**
 239       * @param string $name
 240       * @return void
 241       */
 242      public function delete_option($name) {
 243          unset($this->option[$name]);
 244      }
 245  
 246  
 247      // Infos (related to keyword) low level functions
 248  
 249      /**
 250       * @param string $keyword
 251       * @param mixed  $infos
 252       * @return void
 253       */
 254      public function set_infos($keyword, $infos) {
 255          $this->infos[$keyword] = $infos;
 256      }
 257  
 258      /**
 259       * @param  string $keyword
 260       * @return bool
 261       */
 262      public function has_infos($keyword) {
 263          return array_key_exists($keyword, $this->infos);
 264      }
 265  
 266      /**
 267       * @param  string $keyword
 268       * @return array
 269       */
 270      public function get_infos($keyword) {
 271          return $this->infos[$keyword];
 272      }
 273  
 274      /**
 275       * @param string $keyword
 276       * @return void
 277       */
 278      public function delete_infos($keyword) {
 279          unset($this->infos[$keyword]);
 280      }
 281  
 282      /**
 283       * @todo: infos & options are working the same way here. Abstract this.
 284       */
 285  
 286  
 287      // Plugin low level functions, see functions-plugins.php
 288  
 289      /**
 290       * @return array
 291       */
 292      public function get_plugins() {
 293          return $this->plugins;
 294      }
 295  
 296      /**
 297       * @param array $plugins
 298       * @return void
 299       */
 300      public function set_plugins(array $plugins) {
 301          $this->plugins = $plugins;
 302      }
 303  
 304      /**
 305       * @param string $plugin  plugin filename
 306       * @return void
 307       */
 308      public function add_plugin($plugin) {
 309          $this->plugins[] = $plugin;
 310      }
 311  
 312      /**
 313       * @param string $plugin  plugin filename
 314       * @return void
 315       */
 316      public function remove_plugin($plugin) {
 317          unset($this->plugins[$plugin]);
 318      }
 319  
 320  
 321      // Plugin Pages low level functions, see functions-plugins.php
 322  
 323      /**
 324       * @return array
 325       */
 326      public function get_plugin_pages() {
 327          return is_array( $this->plugin_pages ) ? $this->plugin_pages : [];
 328      }
 329  
 330      /**
 331       * @param array $pages
 332       * @return void
 333       */
 334      public function set_plugin_pages(array $pages) {
 335          $this->plugin_pages = $pages;
 336      }
 337  
 338      /**
 339       * @param string   $slug
 340       * @param string   $title
 341       * @param callable $function
 342       * @return void
 343       */
 344      public function add_plugin_page( $slug, $title, $function ) {
 345          $this->plugin_pages[ $slug ] = [
 346              'slug'     => $slug,
 347              'title'    => $title,
 348              'function' => $function,
 349          ];
 350      }
 351  
 352      /**
 353       * @param string $slug
 354       * @return void
 355       */
 356      public function remove_plugin_page( $slug ) {
 357          unset( $this->plugin_pages[ $slug ] );
 358      }
 359  
 360  
 361      /**
 362       * Return count of SQL queries performed
 363       *
 364       * @since  1.7.3
 365       * @return int
 366       */
 367      public function get_num_queries() {
 368          return count( (array) $this->get_queries() );
 369      }
 370  
 371      /**
 372       * Return SQL queries performed
 373       *
 374       * @since  1.7.3
 375       * @return array
 376       */
 377      public function get_queries() {
 378          $queries = $this->getProfiler()->getLogger()->getMessages();
 379  
 380          // Only keep messages that start with "SQL "
 381          $queries = array_filter($queries, function($query) {return substr( $query, 0, 4 ) === "SQL ";});
 382  
 383          return $queries;
 384      }
 385  
 386      /**
 387       * Set YOURLS installed state
 388       *
 389       * @since  1.7.3
 390       * @param  bool $bool
 391       * @return void
 392       */
 393      public function set_installed($bool) {
 394          $this->installed = $bool;
 395      }
 396  
 397      /**
 398       * Get YOURLS installed state
 399       *
 400       * @since  1.7.3
 401       * @return bool
 402       */
 403      public function is_installed() {
 404          return $this->installed;
 405      }
 406  
 407      /**
 408       * Return standardized DB version
 409       *
 410       * 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
 411       * follows after that.
 412       *   'omgmysql-5.5-ubuntu-4.20' => '5.5'
 413       *   'mysql5.5-ubuntu-4.20'     => '5.5'
 414       *   '5.5-ubuntu-4.20'          => '5.5'
 415       *   '5.5-beta2'                => '5.5'
 416       *   '5.5'                      => '5.5'
 417       *
 418       * @since  1.7.3
 419       * @return string
 420       */
 421      public function mysql_version() {
 422          $version = $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
 423          return $version;
 424      }
 425  
 426  }


Generated: Mon Mar 31 05:10:02 2025 Cross-referenced by PHPXref 0.7.1