[ Index ] |
PHP Cross Reference of YOURLS |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Mar 31 05:10:02 2025 | Cross-referenced by PHPXref 0.7.1 |