PluginProbe
SQLite Database Integration / 3.1.0
SQLite Database Integration v3.1.0
3.1.0 3.0.2 3.0.1 trunk 2.1.13 2.1.14 2.1.15 2.1.16 2.2.0 2.2.1 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.2.2 2.2.20 2.2.21 2.2.22 2.2.23 All 33 releases
← All changes | wp-includes/sqlite/class-wp-sqlite-db.php +62 -82 3.0.2 → 3.1.0 View file →
@@ -48,10 +48,12 @@
48 48 * which creates a circular dependency.
49 49 */
50 50 $GLOBALS['wpdb'] = $this;
51 51
52 + // The SQLite driver may use the charset and collation while connecting.
53 + $this->init_charset();
54 +
52 55 parent::__construct( '', '', $dbname, '' );
53 - $this->charset = 'utf8mb4';
54 56 }
55 57
56 58 /**
57 59 * Returns the active MySQL-on-SQLite driver.
@@ -232,8 +234,38 @@
232 234 return true;
233 235 }
234 236
235 237 /**
238 + * Sets $this->charset and $this->collate.
239 + *
240 + * This overrides wpdb::init_charset(). SQLite stores all text as UTF-8, and
241 + * the emulated MySQL connection always uses utf8mb4 (see set_charset()), so
242 + * the charset is always utf8mb4, and only a UTF-8 DB_COLLATE applies.
243 + *
244 + * Unlike in wpdb, the result doesn't depend on the database connection.
245 + * This is important, as the SQLite driver may use the charset and collation
246 + * while connecting (see the constructor).
247 + *
248 + * @see wpdb::init_charset()
249 + */
250 + public function init_charset() {
251 + $collate = defined( 'DB_COLLATE' ) ? strtolower( (string) DB_COLLATE ) : '';
252 +
253 + // MySQL 8.0.30 and newer name the utf8 collations "utf8mb3_*".
254 + $collate = preg_replace( '/^utf8mb3_/', 'utf8_', $collate );
255 +
256 + // Collations of other charsets don't apply to the utf8mb4 connection.
257 + if ( ! preg_match( '/^utf8(mb4)?_/', $collate ) ) {
258 + $collate = '';
259 + }
260 +
261 + $charset_collate = $this->resolve_charset( 'utf8mb4', $collate );
262 +
263 + $this->charset = $charset_collate['charset'];
264 + $this->collate = $charset_collate['collate'];
265 + }
266 +
267 + /**
236 268 * Determines the best charset and collation to use given a charset and collation.
237 269 *
238 270 * For example, when able, utf8mb4 should be used instead of utf8.
239 271 *
@@ -253,27 +285,9 @@
253 285 if ( ! $this->dbh ) {
254 286 return compact( 'charset', 'collate' );
255 287 }
256 288
257 - if ( 'utf8' === $charset ) {
258 - $charset = 'utf8mb4';
259 - }
260 -
261 - if ( 'utf8mb4' === $charset ) {
262 - // _general_ is outdated, so we can upgrade it to _unicode_, instead.
263 - if ( ! $collate || 'utf8_general_ci' === $collate ) {
264 - $collate = 'utf8mb4_unicode_ci';
265 - } else {
266 - $collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
267 - }
268 - }
269 -
270 - // _unicode_520_ is a better collation, we should use that when it's available.
271 - if ( $this->has_cap( 'utf8mb4_520' ) && 'utf8mb4_unicode_ci' === $collate ) {
272 - $collate = 'utf8mb4_unicode_520_ci';
273 - }
274 -
275 - return compact( 'charset', 'collate' );
289 + return $this->resolve_charset( $charset, $collate );
276 290 }
277 291
278 292 /**
279 293 * Method to select the database connection.
@@ -427,31 +441,8 @@
427 441 E_USER_WARNING
428 442 );
429 443 }
430 444
431 - if ( ! isset( $this->charset ) ) {
432 - $this->init_charset();
433 - }
434 -
435 - // Migrate the database file from a legacy path, if it exists.
436 - if ( ! defined( 'DB_FILE' ) && ! file_exists( FQDB ) ) {
437 - $old_db_path = FQDBDIR . '.ht.sqlite.php';
438 -
439 - if ( file_exists( $old_db_path ) ) {
440 - if ( ! rename( $old_db_path, FQDB ) ) {
441 - wp_die( 'Failed to rename database file.', 'Error!' );
442 - }
443 -
444 - foreach ( array( '-wal', '-shm', '-journal' ) as $suffix ) {
445 - if ( file_exists( $old_db_path . $suffix ) ) {
446 - if ( ! rename( $old_db_path . $suffix, FQDB . $suffix ) ) {
447 - wp_die( 'Failed to rename database file.', 'Error!' );
448 - }
449 - }
450 - }
451 - }
452 - }
453 -
454 445 if ( null === $this->dbname || '' === $this->dbname ) {
455 446 $this->bail(
456 447 'The database name was not set. The SQLite driver requires a database name to be set to emulate MySQL information schema tables.',
457 448 'db_connect_fail'
@@ -458,10 +449,8 @@
458 449 );
459 450 return false;
460 451 }
461 452
462 - $this->ensure_database_directory( FQDB );
463 -
464 453 try {
465 454 $options = array(
466 455 'sqlite_journal_mode' => defined( 'SQLITE_JOURNAL_MODE' ) ? SQLITE_JOURNAL_MODE : null,
467 456 );
@@ -467,9 +456,9 @@
467 456 );
468 457 $dbh = new WP_MySQL_On_SQLite(
469 458 sprintf(
470 459 'mysql-on-sqlite:path=%s;dbname=%s',
471 - str_replace( ';', ';;', FQDB ),
460 + str_replace( ';', ';;', DB_PATH ),
472 461 str_replace( ';', ';;', $this->dbname )
473 462 ),
474 463 null,
475 464 null,
@@ -785,54 +774,45 @@
785 774 return $this->dbh->getAttribute( PDO::ATTR_SERVER_VERSION ); // phpcs:ignore WordPress.DB.RestrictedClasses.mysql__PDO
786 775 }
787 776
788 777 /**
789 - * Make sure the SQLite database directory exists and is writable.
790 - * Create .htaccess and index.php files to prevent direct access.
778 + * Resolves the charset and collation as wpdb::determine_charset() does.
791 779 *
792 - * @param string $database_path The path to the SQLite database file.
780 + * Unlike in wpdb, this doesn't need a database connection. The emulated
781 + * MySQL server (5.7 or newer) always supports utf8mb4_unicode_520_ci.
782 + *
783 + * @see wpdb::determine_charset()
784 + *
785 + * @param string $charset The character set to check.
786 + * @param string $collate The collation to check.
787 + * @return array {
788 + * The most appropriate character set and collation to use.
789 + *
790 + * @type string $charset Character set.
791 + * @type string $collate Collation.
792 + * }
793 793 */
794 - private function ensure_database_directory( string $database_path ) {
795 - $dir = dirname( $database_path );
796 -
797 - // Set the umask to 0000 to apply permissions exactly as specified.
798 - // A non-zero umask affects new file and directory permissions.
799 - $umask = umask( 0 );
800 -
801 - // Ensure database directory.
802 - if ( ! is_dir( $dir ) ) {
803 - if ( ! @mkdir( $dir, 0700, true ) ) {
804 - wp_die( sprintf( 'Failed to create database directory: %s', $dir ), 'Error!' );
805 - }
794 + private function resolve_charset( $charset, $collate ) {
795 + if ( 'utf8' === $charset ) {
796 + $charset = 'utf8mb4';
806 797 }
807 - if ( ! is_writable( $dir ) ) {
808 - wp_die( sprintf( 'Database directory is not writable: %s', $dir ), 'Error!' );
809 - }
810 798
811 - // Ensure .htaccess file to prevent direct access.
812 - $path = $dir . DIRECTORY_SEPARATOR . '.htaccess';
813 - if ( ! is_file( $path ) ) {
814 - $result = file_put_contents( $path, 'DENY FROM ALL', LOCK_EX );
815 - if ( false === $result ) {
816 - wp_die( sprintf( 'Failed to create file: %s', $path ), 'Error!' );
799 + if ( 'utf8mb4' === $charset ) {
800 + // _general_ is outdated, so we can upgrade it to _unicode_, instead.
801 + if ( ! $collate || 'utf8_general_ci' === $collate ) {
802 + $collate = 'utf8mb4_unicode_ci';
803 + } else {
804 + $collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
817 805 }
818 - chmod( $path, 0600 );
819 806 }
820 807
821 - // Ensure index.php file to prevent direct access.
822 - $path = $dir . DIRECTORY_SEPARATOR . 'index.php';
823 - if ( ! is_file( $path ) ) {
824 - $result = file_put_contents( $path, '<?php // Silence is gold. ?>', LOCK_EX );
825 - if ( false === $result ) {
826 - wp_die( sprintf( 'Failed to create file: %s', $path ), 'Error!' );
827 - }
828 - chmod( $path, 0600 );
808 + // _unicode_520_ is a better collation, we should use that when it's available.
809 + if ( 'utf8mb4_unicode_ci' === $collate ) {
810 + $collate = 'utf8mb4_unicode_520_ci';
829 811 }
830 812
831 - // Restore the original umask value.
832 - umask( $umask );
813 + return compact( 'charset', 'collate' );
833 814 }
834 -
835 815
836 816 /**
837 817 * Format MySQL-on-SQLite driver error message.
838 818 *