[ 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 almighty 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 (e.g. 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 (e.g. 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 information
  57       * @var array
  58       */
  59      protected $plugin_pages = [];
  60  
  61      /**
  62       * Plugin information
  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 (e.g. 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          if (isset($this->infos[$keyword])) {
 280              unset($this->infos[$keyword]);
 281          }
 282      }
 283  
 284      /**
 285       * @param string $keyword
 286       * @param mixed  $infos
 287       * @return void
 288       */
 289      public function update_infos_if_exists($keyword, $infos) {
 290          if ($this->has_infos($keyword) && $this->infos[$keyword]) {
 291              $this->infos[$keyword] = array_merge($this->infos[$keyword], $infos);
 292          }
 293      }
 294  
 295      /**
 296       * @todo: infos & options are working the same way here. Abstract this.
 297       */
 298  
 299  
 300      // Plugin low level functions, see functions-plugins.php
 301  
 302      /**
 303       * @return array
 304       */
 305      public function get_plugins() {
 306          return $this->plugins;
 307      }
 308  
 309      /**
 310       * @param array $plugins
 311       * @return void
 312       */
 313      public function set_plugins(array $plugins) {
 314          $this->plugins = $plugins;
 315      }
 316  
 317      /**
 318       * @param string $plugin  plugin filename
 319       * @return void
 320       */
 321      public function add_plugin($plugin) {
 322          $this->plugins[] = $plugin;
 323      }
 324  
 325      /**
 326       * @param string $plugin  plugin filename
 327       * @return void
 328       */
 329      public function remove_plugin($plugin) {
 330          unset($this->plugins[$plugin]);
 331      }
 332  
 333  
 334      // Plugin Pages low level functions, see functions-plugins.php
 335  
 336      /**
 337       * @return array
 338       */
 339      public function get_plugin_pages() {
 340          return is_array( $this->plugin_pages ) ? $this->plugin_pages : [];
 341      }
 342  
 343      /**
 344       * @param array $pages
 345       * @return void
 346       */
 347      public function set_plugin_pages(array $pages) {
 348          $this->plugin_pages = $pages;
 349      }
 350  
 351      /**
 352       * @param string   $slug
 353       * @param string   $title
 354       * @param callable $function
 355       * @return void
 356       */
 357      public function add_plugin_page( $slug, $title, $function ) {
 358          $this->plugin_pages[ $slug ] = [
 359              'slug'     => $slug,
 360              'title'    => $title,
 361              'function' => $function,
 362          ];
 363      }
 364  
 365      /**
 366       * @param string $slug
 367       * @return void
 368       */
 369      public function remove_plugin_page( $slug ) {
 370          unset( $this->plugin_pages[ $slug ] );
 371      }
 372  
 373  
 374      /**
 375       * Return count of SQL queries performed
 376       *
 377       * @since  1.7.3
 378       * @return int
 379       */
 380      public function get_num_queries() {
 381          return count( (array) $this->get_queries() );
 382      }
 383  
 384      /**
 385       * Return SQL queries performed
 386       *
 387       * @since  1.7.3
 388       * @return array
 389       */
 390      public function get_queries() {
 391          $queries = $this->getProfiler()->getLogger()->getMessages();
 392  
 393          // Only keep messages that start with "SQL "
 394          $queries = array_filter($queries, function($query) {return substr( $query, 0, 4 ) === "SQL ";});
 395  
 396          return $queries;
 397      }
 398  
 399      /**
 400       * Set YOURLS installed state
 401       *
 402       * @since  1.7.3
 403       * @param  bool $bool
 404       * @return void
 405       */
 406      public function set_installed($bool) {
 407          $this->installed = $bool;
 408      }
 409  
 410      /**
 411       * Get YOURLS installed state
 412       *
 413       * @since  1.7.3
 414       * @return bool
 415       */
 416      public function is_installed() {
 417          return $this->installed;
 418      }
 419  
 420      /**
 421       * Return MySQL version
 422       *
 423       * @since  1.7.3
 424       * @return string
 425       */
 426      public function mysql_version() {
 427          return $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
 428      }
 429  
 430  }


Generated: Wed Nov 5 05:10:36 2025 Cross-referenced by PHPXref 0.7.1