[ 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, $attributes) { 82 parent::__construct($dsn, $user, $pass, $options, $attributes); 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 $this->connect(); 144 } catch ( \Exception $e ) { 145 $this->dead_or_error($e); 146 } 147 } 148 149 /** 150 * Die with an error message 151 * 152 * @since 1.7.3 153 * 154 * @param \Exception $exception 155 * 156 * @return void 157 */ 158 public function dead_or_error(\Exception $exception) { 159 // Use any /user/db_error.php file 160 $file = YOURLS_USERDIR . '/db_error.php'; 161 if(file_exists($file)) { 162 if(yourls_include_file_sandbox( $file ) === true) { 163 die(); 164 } 165 } 166 167 $message = yourls__( 'Incorrect DB config, or could not connect to DB' ); 168 $message .= '<br/>' . get_class($exception) .': ' . $exception->getMessage(); 169 yourls_die( yourls__( $message ), yourls__( 'Fatal error' ), 503 ); 170 die(); 171 172 } 173 174 /** 175 * Start a Message Logger 176 * 177 * @since 1.7.3 178 * @see \Aura\Sql\Profiler\Profiler 179 * @see \Aura\Sql\Profiler\MemoryLogger 180 * @return void 181 */ 182 public function start_profiler() { 183 // Instantiate a custom logger and make it the profiler 184 $yourls_logger = new Logger(); 185 $profiler = new Profiler($yourls_logger); 186 $this->setProfiler($profiler); 187 188 /* By default, make "query" the log level. This way, each internal logging triggered 189 * by Aura SQL will be a "query", and logging triggered by yourls_debug() will be 190 * a "message". See includes/functions-debug.php:yourls_debug() 191 */ 192 $profiler->setLoglevel('query'); 193 } 194 195 /** 196 * @param string $context 197 * @return void 198 */ 199 public function set_html_context($context) { 200 $this->context = $context; 201 } 202 203 /** 204 * @return string 205 */ 206 public function get_html_context() { 207 return $this->context; 208 } 209 210 // Options low level functions, see \YOURLS\Database\Options 211 212 /** 213 * @param string $name 214 * @param mixed $value 215 * @return void 216 */ 217 public function set_option($name, $value) { 218 $this->option[$name] = $value; 219 } 220 221 /** 222 * @param string $name 223 * @return bool 224 */ 225 public function has_option($name) { 226 return array_key_exists($name, $this->option); 227 } 228 229 /** 230 * @param string $name 231 * @return string 232 */ 233 public function get_option($name) { 234 return $this->option[$name]; 235 } 236 237 /** 238 * @param string $name 239 * @return void 240 */ 241 public function delete_option($name) { 242 unset($this->option[$name]); 243 } 244 245 246 // Infos (related to keyword) low level functions 247 248 /** 249 * @param string $keyword 250 * @param mixed $infos 251 * @return void 252 */ 253 public function set_infos($keyword, $infos) { 254 $this->infos[$keyword] = $infos; 255 } 256 257 /** 258 * @param string $keyword 259 * @return bool 260 */ 261 public function has_infos($keyword) { 262 return array_key_exists($keyword, $this->infos); 263 } 264 265 /** 266 * @param string $keyword 267 * @return array 268 */ 269 public function get_infos($keyword) { 270 return $this->infos[$keyword]; 271 } 272 273 /** 274 * @param string $keyword 275 * @return void 276 */ 277 public function delete_infos($keyword) { 278 unset($this->infos[$keyword]); 279 } 280 281 /** 282 * @todo: infos & options are working the same way here. Abstract this. 283 */ 284 285 286 // Plugin low level functions, see functions-plugins.php 287 288 /** 289 * @return array 290 */ 291 public function get_plugins() { 292 return $this->plugins; 293 } 294 295 /** 296 * @param array $plugins 297 * @return void 298 */ 299 public function set_plugins(array $plugins) { 300 $this->plugins = $plugins; 301 } 302 303 /** 304 * @param string $plugin plugin filename 305 * @return void 306 */ 307 public function add_plugin($plugin) { 308 $this->plugins[] = $plugin; 309 } 310 311 /** 312 * @param string $plugin plugin filename 313 * @return void 314 */ 315 public function remove_plugin($plugin) { 316 unset($this->plugins[$plugin]); 317 } 318 319 320 // Plugin Pages low level functions, see functions-plugins.php 321 322 /** 323 * @return array 324 */ 325 public function get_plugin_pages() { 326 return is_array( $this->plugin_pages ) ? $this->plugin_pages : []; 327 } 328 329 /** 330 * @param array $pages 331 * @return void 332 */ 333 public function set_plugin_pages(array $pages) { 334 $this->plugin_pages = $pages; 335 } 336 337 /** 338 * @param string $slug 339 * @param string $title 340 * @param callable $function 341 * @return void 342 */ 343 public function add_plugin_page( $slug, $title, $function ) { 344 $this->plugin_pages[ $slug ] = [ 345 'slug' => $slug, 346 'title' => $title, 347 'function' => $function, 348 ]; 349 } 350 351 /** 352 * @param string $slug 353 * @return void 354 */ 355 public function remove_plugin_page( $slug ) { 356 unset( $this->plugin_pages[ $slug ] ); 357 } 358 359 360 /** 361 * Return count of SQL queries performed 362 * 363 * @since 1.7.3 364 * @return int 365 */ 366 public function get_num_queries() { 367 return count( (array) $this->get_queries() ); 368 } 369 370 /** 371 * Return SQL queries performed 372 * 373 * @since 1.7.3 374 * @return array 375 */ 376 public function get_queries() { 377 $queries = $this->getProfiler()->getLogger()->getMessages(); 378 379 // Only keep messages that start with "SQL " 380 $queries = array_filter($queries, function($query) {return substr( $query, 0, 4 ) === "SQL ";}); 381 382 return $queries; 383 } 384 385 /** 386 * Set YOURLS installed state 387 * 388 * @since 1.7.3 389 * @param bool $bool 390 * @return void 391 */ 392 public function set_installed($bool) { 393 $this->installed = $bool; 394 } 395 396 /** 397 * Get YOURLS installed state 398 * 399 * @since 1.7.3 400 * @return bool 401 */ 402 public function is_installed() { 403 return $this->installed; 404 } 405 406 /** 407 * Return standardized DB version 408 * 409 * 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 410 * follows after that. 411 * 'omgmysql-5.5-ubuntu-4.20' => '5.5' 412 * 'mysql5.5-ubuntu-4.20' => '5.5' 413 * '5.5-ubuntu-4.20' => '5.5' 414 * '5.5-beta2' => '5.5' 415 * '5.5' => '5.5' 416 * 417 * @since 1.7.3 418 * @return string 419 */ 420 public function mysql_version() { 421 $version = $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); 422 return $version; 423 } 424 425 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Jan 21 05:10:11 2025 | Cross-referenced by PHPXref 0.7.1 |