initial
This commit is contained in:
+675
@@ -0,0 +1,675 @@
|
||||
<?php
|
||||
/**
|
||||
* Extend and replace the wpdb class.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class extends wpdb and replaces it.
|
||||
*
|
||||
* It also rewrites some methods that use mysql specific functions.
|
||||
*/
|
||||
class WP_SQLite_DB extends wpdb {
|
||||
|
||||
/**
|
||||
* Database Handle
|
||||
*
|
||||
* @var WP_SQLite_Driver
|
||||
*/
|
||||
protected $dbh;
|
||||
|
||||
/**
|
||||
* Backward compatibility, see wpdb::$allow_unsafe_unquoted_parameters.
|
||||
*
|
||||
* This property is mirroring "wpdb::$allow_unsafe_unquoted_parameters",
|
||||
* because some tests are accessing it externally using PHP reflection.
|
||||
*
|
||||
* @var
|
||||
*/
|
||||
private $allow_unsafe_unquoted_parameters = true;
|
||||
|
||||
/**
|
||||
* Connects to the SQLite database.
|
||||
*
|
||||
* Unlike for MySQL, no credentials and host are needed.
|
||||
*
|
||||
* @param string $dbname Database name.
|
||||
*/
|
||||
public function __construct( $dbname ) {
|
||||
/**
|
||||
* We need to initialize the "$wpdb" global early, so that the SQLite
|
||||
* driver can configure the database. The call stack goes like this:
|
||||
*
|
||||
* 1. The "parent::__construct()" call executes "$this->db_connect()".
|
||||
* 2. The database connection call initializes the SQLite driver.
|
||||
* 3. The SQLite driver initializes and runs "WP_SQLite_Configurator".
|
||||
* 4. The configurator uses "WP_SQLite_Information_Schema_Reconstructor",
|
||||
* which requires "wp-admin/includes/schema.php" when in WordPress.
|
||||
* 5. The "wp-admin/includes/schema.php" requires the "$wpdb" global,
|
||||
* which creates a circular dependency.
|
||||
*/
|
||||
$GLOBALS['wpdb'] = $this;
|
||||
|
||||
parent::__construct( '', '', $dbname, '' );
|
||||
$this->charset = 'utf8mb4';
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set character set for the database.
|
||||
*
|
||||
* This overrides wpdb::set_charset(), only to dummy out the MySQL function.
|
||||
*
|
||||
* @see wpdb::set_charset()
|
||||
*
|
||||
* @param resource $dbh The resource given by mysql_connect.
|
||||
* @param string $charset Optional. The character set. Default null.
|
||||
* @param string $collate Optional. The collation. Default null.
|
||||
*/
|
||||
public function set_charset( $dbh, $charset = null, $collate = null ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the character set for the database.
|
||||
* Hardcoded to utf8mb4 for now.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param string $column The column name.
|
||||
*
|
||||
* @return string The character set.
|
||||
*/
|
||||
public function get_col_charset( $table, $column ) {
|
||||
// Hardcoded for now.
|
||||
return 'utf8mb4';
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the current SQL mode, and ensures its WordPress compatibility.
|
||||
*
|
||||
* If no modes are passed, it will ensure the current MySQL server modes are compatible.
|
||||
*
|
||||
* This overrides wpdb::set_sql_mode() while closely mirroring its implementation.
|
||||
*
|
||||
* @param array $modes Optional. A list of SQL modes to set. Default empty array.
|
||||
*/
|
||||
public function set_sql_mode( $modes = array() ) {
|
||||
if ( empty( $modes ) ) {
|
||||
$result = $this->dbh->query( 'SELECT @@SESSION.sql_mode' );
|
||||
if ( ! isset( $result[0] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$modes_str = $result[0]->{'@@SESSION.sql_mode'};
|
||||
if ( empty( $modes_str ) ) {
|
||||
return;
|
||||
}
|
||||
$modes = explode( ',', $modes_str );
|
||||
}
|
||||
|
||||
$modes = array_change_key_case( $modes, CASE_UPPER );
|
||||
|
||||
/**
|
||||
* Filters the list of incompatible SQL modes to exclude.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @param array $incompatible_modes An array of incompatible modes.
|
||||
*/
|
||||
$incompatible_modes = (array) apply_filters( 'incompatible_sql_modes', $this->incompatible_modes );
|
||||
|
||||
foreach ( $modes as $i => $mode ) {
|
||||
if ( in_array( $mode, $incompatible_modes, true ) ) {
|
||||
unset( $modes[ $i ] );
|
||||
}
|
||||
}
|
||||
$modes_str = implode( ',', $modes );
|
||||
|
||||
$this->dbh->query( "SET SESSION sql_mode='$modes_str'" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current database connection.
|
||||
* Noop in SQLite.
|
||||
*
|
||||
* @return bool True to indicate the connection was successfully closed.
|
||||
*/
|
||||
public function close() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to select the database connection.
|
||||
*
|
||||
* This overrides wpdb::select(), only to dummy out the MySQL function.
|
||||
*
|
||||
* @see wpdb::select()
|
||||
*
|
||||
* @param string $db MySQL database name. Not used.
|
||||
* @param resource|null $dbh Optional link identifier.
|
||||
*/
|
||||
public function select( $db, $dbh = null ) {
|
||||
$this->ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to escape characters.
|
||||
*
|
||||
* This overrides wpdb::_real_escape() to avoid using mysql_real_escape_string().
|
||||
*
|
||||
* @see wpdb::_real_escape()
|
||||
*
|
||||
* @param string $data The string to escape.
|
||||
*
|
||||
* @return string escaped
|
||||
*/
|
||||
public function _real_escape( $data ) {
|
||||
if ( ! is_scalar( $data ) ) {
|
||||
return '';
|
||||
}
|
||||
$escaped = addslashes( $data );
|
||||
return $this->add_placeholder_escape( $escaped );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints SQL/DB error.
|
||||
*
|
||||
* This overrides wpdb::print_error() while closely mirroring its implementation.
|
||||
*
|
||||
* @global array $EZSQL_ERROR Stores error information of query and error string.
|
||||
*
|
||||
* @param string $str The error to display.
|
||||
* @return void|false Void if the showing of errors is enabled, false if disabled.
|
||||
*/
|
||||
public function print_error( $str = '' ) {
|
||||
global $EZSQL_ERROR;
|
||||
|
||||
if ( ! $str ) {
|
||||
$str = $this->last_error;
|
||||
}
|
||||
|
||||
$EZSQL_ERROR[] = array(
|
||||
'query' => $this->last_query,
|
||||
'error_str' => $str,
|
||||
);
|
||||
|
||||
if ( $this->suppress_errors ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$caller = $this->get_caller();
|
||||
if ( $caller ) {
|
||||
// Not translated, as this will only appear in the error log.
|
||||
$error_str = sprintf( 'WordPress database error %1$s for query %2$s made by %3$s', $str, $this->last_query, $caller );
|
||||
} else {
|
||||
$error_str = sprintf( 'WordPress database error %1$s for query %2$s', $str, $this->last_query );
|
||||
}
|
||||
|
||||
error_log( $error_str );
|
||||
|
||||
// Are we showing errors?
|
||||
if ( ! $this->show_errors ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wp_load_translations_early();
|
||||
|
||||
// If there is an error then take note of it.
|
||||
if ( is_multisite() ) {
|
||||
$msg = sprintf(
|
||||
"%s [%s]\n%s\n",
|
||||
__( 'WordPress database error:' ),
|
||||
$str,
|
||||
$this->last_query
|
||||
);
|
||||
|
||||
if ( defined( 'ERRORLOGFILE' ) ) {
|
||||
error_log( $msg, 3, ERRORLOGFILE );
|
||||
}
|
||||
if ( defined( 'DIEONDBERROR' ) ) {
|
||||
wp_die( $msg );
|
||||
}
|
||||
} else {
|
||||
$str = htmlspecialchars( $str, ENT_QUOTES );
|
||||
$query = htmlspecialchars( $this->last_query, ENT_QUOTES );
|
||||
|
||||
printf(
|
||||
'<div id="error"><p class="wpdberror"><strong>%s</strong> [%s]<br /><code>%s</code></p></div>',
|
||||
__( 'WordPress database error:' ),
|
||||
$str,
|
||||
$query
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to flush cached data.
|
||||
*
|
||||
* This overrides wpdb::flush(). This is not necessarily overridden, because
|
||||
* $result will never be resource.
|
||||
*
|
||||
* @see wpdb::flush
|
||||
*/
|
||||
public function flush() {
|
||||
$this->last_result = array();
|
||||
$this->col_info = null;
|
||||
$this->last_query = null;
|
||||
$this->rows_affected = 0;
|
||||
$this->num_rows = 0;
|
||||
$this->last_error = '';
|
||||
$this->result = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to do the database connection.
|
||||
*
|
||||
* This overrides wpdb::db_connect() to avoid using MySQL function.
|
||||
*
|
||||
* @see wpdb::db_connect()
|
||||
*
|
||||
* @param bool $allow_bail Not used.
|
||||
* @return void
|
||||
*/
|
||||
public function db_connect( $allow_bail = true ) {
|
||||
if ( $this->dbh ) {
|
||||
return;
|
||||
}
|
||||
$this->init_charset();
|
||||
|
||||
$pdo = null;
|
||||
if ( isset( $GLOBALS['@pdo'] ) ) {
|
||||
$pdo = $GLOBALS['@pdo'];
|
||||
}
|
||||
|
||||
// Migrate the database file from a legacy path, if it exists.
|
||||
if ( ! defined( 'DB_FILE' ) && ! file_exists( FQDB ) ) {
|
||||
$old_db_path = FQDBDIR . '.ht.sqlite.php';
|
||||
|
||||
if ( file_exists( $old_db_path ) ) {
|
||||
if ( ! rename( $old_db_path, FQDB ) ) {
|
||||
wp_die( 'Failed to rename database file.', 'Error!' );
|
||||
}
|
||||
|
||||
foreach ( array( '-wal', '-shm', '-journal' ) as $suffix ) {
|
||||
if ( file_exists( $old_db_path . $suffix ) ) {
|
||||
if ( ! rename( $old_db_path . $suffix, FQDB . $suffix ) ) {
|
||||
wp_die( 'Failed to rename database file.', 'Error!' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( null === $this->dbname || '' === $this->dbname ) {
|
||||
$this->bail(
|
||||
'The database name was not set. The SQLite driver requires a database name to be set to emulate MySQL information schema tables.',
|
||||
'db_connect_fail'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->ensure_database_directory( FQDB );
|
||||
|
||||
try {
|
||||
$connection = new WP_SQLite_Connection(
|
||||
array(
|
||||
'pdo' => $pdo,
|
||||
'path' => FQDB,
|
||||
'journal_mode' => defined( 'SQLITE_JOURNAL_MODE' ) ? SQLITE_JOURNAL_MODE : null,
|
||||
)
|
||||
);
|
||||
$this->dbh = new WP_SQLite_Driver( $connection, $this->dbname );
|
||||
$GLOBALS['@pdo'] = $this->dbh->get_connection()->get_pdo();
|
||||
} catch ( Throwable $e ) {
|
||||
$this->last_error = $this->format_error_message( $e );
|
||||
}
|
||||
if ( $this->last_error ) {
|
||||
return false;
|
||||
}
|
||||
$this->ready = true;
|
||||
$this->set_sql_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to dummy out wpdb::check_connection()
|
||||
*
|
||||
* @param bool $allow_bail Not used.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check_connection( $allow_bail = true ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a SQL query for safe execution.
|
||||
*
|
||||
* See "wpdb::prepare()". This override only fixes a WPDB test issue.
|
||||
*
|
||||
* @param string $query Query statement with `sprintf()`-like placeholders.
|
||||
* @param array|mixed $args The array of variables or the first variable to substitute.
|
||||
* @param mixed ...$args Further variables to substitute when using individual arguments.
|
||||
* @return string|void Sanitized query string, if there is a query to prepare.
|
||||
*/
|
||||
public function prepare( $query, ...$args ) {
|
||||
/*
|
||||
* Sync "$allow_unsafe_unquoted_parameters" with the WPDB parent property.
|
||||
* This is only needed because some WPDB tests are accessing the private
|
||||
* property externally via PHP reflection. This should be fixed WP tests.
|
||||
*/
|
||||
$wpdb_allow_unsafe_unquoted_parameters = $this->__get( 'allow_unsafe_unquoted_parameters' );
|
||||
if ( $wpdb_allow_unsafe_unquoted_parameters !== $this->allow_unsafe_unquoted_parameters ) {
|
||||
$property = new ReflectionProperty( 'wpdb', 'allow_unsafe_unquoted_parameters' );
|
||||
$property->setAccessible( true );
|
||||
$property->setValue( $this, $this->allow_unsafe_unquoted_parameters );
|
||||
$property->setAccessible( false );
|
||||
}
|
||||
|
||||
return parent::prepare( $query, ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a database query.
|
||||
*
|
||||
* This overrides wpdb::query() while closely mirroring its implementation.
|
||||
*
|
||||
* @see wpdb::query()
|
||||
*
|
||||
* @param string $query Database query.
|
||||
*
|
||||
* @param string $query Database query.
|
||||
* @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
|
||||
* affected/selected for all other queries. Boolean false on error.
|
||||
*/
|
||||
public function query( $query ) {
|
||||
// Query Monitor integration:
|
||||
$query_monitor_active = defined( 'SQLITE_QUERY_MONITOR_LOADED' ) && SQLITE_QUERY_MONITOR_LOADED;
|
||||
if ( $query_monitor_active && $this->show_errors ) {
|
||||
$this->hide_errors();
|
||||
}
|
||||
|
||||
if ( ! $this->ready ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = apply_filters( 'query', $query );
|
||||
|
||||
if ( ! $query ) {
|
||||
$this->insert_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->flush();
|
||||
|
||||
// Log how the function was called.
|
||||
$this->func_call = "\$db->query(\"$query\")";
|
||||
|
||||
// Keep track of the last query for debug.
|
||||
$this->last_query = $query;
|
||||
|
||||
// Save the query count before running another query.
|
||||
$last_query_count = count( $this->queries ?? array() );
|
||||
|
||||
/*
|
||||
* @TODO: WPDB uses "$this->check_current_query" to check table/column
|
||||
* charset and strip all invalid characters from the query.
|
||||
* This is an involved process that we can bypass for SQLite,
|
||||
* if we simply strip all invalid UTF-8 characters from the query.
|
||||
*
|
||||
* To do so, mb_convert_encoding can be used with an optional
|
||||
* fallback to a htmlspecialchars method. E.g.:
|
||||
* https://github.com/nette/utils/blob/be534713c227aeef57ce1883fc17bc9f9e29eca2/src/Utils/Strings.php#L42
|
||||
*/
|
||||
$this->_do_query( $query );
|
||||
|
||||
if ( $this->last_error ) {
|
||||
// Clear insert_id on a subsequent failed insert.
|
||||
if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
|
||||
$this->insert_id = 0;
|
||||
}
|
||||
|
||||
$this->print_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) {
|
||||
$return_val = true;
|
||||
} elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) {
|
||||
$this->rows_affected = $this->dbh->get_last_return_value();
|
||||
|
||||
// Take note of the insert_id.
|
||||
if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
|
||||
$this->insert_id = $this->dbh->get_insert_id();
|
||||
}
|
||||
|
||||
// Return number of rows affected.
|
||||
$return_val = $this->rows_affected;
|
||||
} else {
|
||||
$num_rows = 0;
|
||||
|
||||
if ( is_array( $this->result ) ) {
|
||||
$this->last_result = $this->result;
|
||||
$num_rows = count( $this->result );
|
||||
}
|
||||
|
||||
// Log and return the number of rows selected.
|
||||
$this->num_rows = $num_rows;
|
||||
$return_val = $num_rows;
|
||||
}
|
||||
|
||||
// Query monitor integration:
|
||||
if ( $query_monitor_active && class_exists( 'QM_Backtrace' ) ) {
|
||||
if ( did_action( 'qm/cease' ) ) {
|
||||
$this->queries = array();
|
||||
}
|
||||
|
||||
$i = $last_query_count;
|
||||
if ( ! isset( $this->queries[ $i ] ) ) {
|
||||
return $return_val;
|
||||
}
|
||||
|
||||
$this->queries[ $i ]['trace'] = new QM_Backtrace();
|
||||
if ( ! isset( $this->queries[ $i ][3] ) ) {
|
||||
$this->queries[ $i ][3] = $this->time_start;
|
||||
}
|
||||
|
||||
if ( $this->last_error && ! $this->suppress_errors ) {
|
||||
$this->queries[ $i ]['result'] = new WP_Error( 'qmdb', $this->last_error );
|
||||
} else {
|
||||
$this->queries[ $i ]['result'] = (int) $return_val;
|
||||
}
|
||||
|
||||
// Add SQLite query data.
|
||||
$this->queries[ $i ]['sqlite_queries'] = $this->dbh->get_last_sqlite_queries();
|
||||
}
|
||||
return $return_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to perform the SQLite query call.
|
||||
*
|
||||
* This closely mirrors wpdb::_do_query().
|
||||
*
|
||||
* @see wpdb::_do_query()
|
||||
*
|
||||
* @param string $query The query to run.
|
||||
*/
|
||||
private function _do_query( $query ) {
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
||||
$this->timer_start();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->result = $this->dbh->query( $query );
|
||||
} catch ( Throwable $e ) {
|
||||
$this->last_error = $this->format_error_message( $e );
|
||||
}
|
||||
|
||||
++$this->num_queries;
|
||||
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
||||
$this->log_query(
|
||||
$query,
|
||||
$this->timer_stop(),
|
||||
$this->get_caller(),
|
||||
$this->time_start,
|
||||
array()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the class variable $col_info.
|
||||
*
|
||||
* This overrides wpdb::load_col_info(), which uses a mysql function.
|
||||
*
|
||||
* @see wpdb::load_col_info()
|
||||
*/
|
||||
protected function load_col_info() {
|
||||
if ( $this->col_info ) {
|
||||
return;
|
||||
}
|
||||
$this->col_info = array();
|
||||
foreach ( $this->dbh->get_last_column_meta() as $column ) {
|
||||
$this->col_info[] = (object) array(
|
||||
'name' => $column['name'],
|
||||
'orgname' => $column['mysqli:orgname'],
|
||||
'table' => $column['table'],
|
||||
'orgtable' => $column['mysqli:orgtable'],
|
||||
'def' => '', // Unused, always ''.
|
||||
'db' => $column['mysqli:db'],
|
||||
'catalog' => 'def', // Unused, always 'def'.
|
||||
'max_length' => 0, // As of PHP 8.1, this is always 0.
|
||||
'length' => $column['len'],
|
||||
'charsetnr' => $column['mysqli:charsetnr'],
|
||||
'flags' => $column['mysqli:flags'],
|
||||
'type' => $column['mysqli:type'],
|
||||
'decimals' => $column['precision'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return what the database can do.
|
||||
*
|
||||
* This overrides wpdb::has_cap() to avoid using MySQL functions.
|
||||
* SQLite supports subqueries, but not support collation, group_concat and set_charset.
|
||||
*
|
||||
* @see wpdb::has_cap()
|
||||
*
|
||||
* @param string $db_cap The feature to check for. Accepts 'collation',
|
||||
* 'group_concat', 'subqueries', 'set_charset',
|
||||
* 'utf8mb4', or 'utf8mb4_520'.
|
||||
*
|
||||
* @return bool Whether the database feature is supported, false otherwise.
|
||||
*/
|
||||
public function has_cap( $db_cap ) {
|
||||
return 'subqueries' === strtolower( $db_cap );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return database version number.
|
||||
*
|
||||
* This overrides wpdb::db_version() to avoid using MySQL function.
|
||||
* It returns mysql version number, but it means nothing for SQLite.
|
||||
* So it return the newest mysql version.
|
||||
*
|
||||
* @see wpdb::db_version()
|
||||
*/
|
||||
public function db_version() {
|
||||
return '8.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the SQLite engine.
|
||||
*
|
||||
* @return string SQLite engine version as a string.
|
||||
*/
|
||||
public function db_server_info() {
|
||||
return $this->dbh->get_sqlite_version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the SQLite database directory exists and is writable.
|
||||
* Create .htaccess and index.php files to prevent direct access.
|
||||
*
|
||||
* @param string $database_path The path to the SQLite database file.
|
||||
*/
|
||||
private function ensure_database_directory( string $database_path ) {
|
||||
$dir = dirname( $database_path );
|
||||
|
||||
// Set the umask to 0000 to apply permissions exactly as specified.
|
||||
// A non-zero umask affects new file and directory permissions.
|
||||
$umask = umask( 0 );
|
||||
|
||||
// Ensure database directory.
|
||||
if ( ! is_dir( $dir ) ) {
|
||||
if ( ! @mkdir( $dir, 0700, true ) ) {
|
||||
wp_die( sprintf( 'Failed to create database directory: %s', $dir ), 'Error!' );
|
||||
}
|
||||
}
|
||||
if ( ! is_writable( $dir ) ) {
|
||||
wp_die( sprintf( 'Database directory is not writable: %s', $dir ), 'Error!' );
|
||||
}
|
||||
|
||||
// Ensure .htaccess file to prevent direct access.
|
||||
$path = $dir . DIRECTORY_SEPARATOR . '.htaccess';
|
||||
if ( ! is_file( $path ) ) {
|
||||
$result = file_put_contents( $path, 'DENY FROM ALL', LOCK_EX );
|
||||
if ( false === $result ) {
|
||||
wp_die( sprintf( 'Failed to create file: %s', $path ), 'Error!' );
|
||||
}
|
||||
chmod( $path, 0600 );
|
||||
}
|
||||
|
||||
// Ensure index.php file to prevent direct access.
|
||||
$path = $dir . DIRECTORY_SEPARATOR . 'index.php';
|
||||
if ( ! is_file( $path ) ) {
|
||||
$result = file_put_contents( $path, '<?php // Silence is gold. ?>', LOCK_EX );
|
||||
if ( false === $result ) {
|
||||
wp_die( sprintf( 'Failed to create file: %s', $path ), 'Error!' );
|
||||
}
|
||||
chmod( $path, 0600 );
|
||||
}
|
||||
|
||||
// Restore the original umask value.
|
||||
umask( $umask );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format SQLite driver error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function format_error_message( Throwable $e ) {
|
||||
$output = '<div style="clear:both"> </div>' . PHP_EOL;
|
||||
|
||||
// Queries.
|
||||
if ( $e instanceof WP_SQLite_Driver_Exception ) {
|
||||
$driver = $e->getDriver();
|
||||
|
||||
$output .= '<div class="queries" style="clear:both;margin-bottom:2px;border:red dotted thin;">' . PHP_EOL;
|
||||
$output .= '<p>MySQL query:</p>' . PHP_EOL;
|
||||
$output .= '<p>' . $driver->get_last_mysql_query() . '</p>' . PHP_EOL;
|
||||
$output .= '<p>Queries made or created this session were:</p>' . PHP_EOL;
|
||||
$output .= '<ol>' . PHP_EOL;
|
||||
foreach ( $driver->get_last_sqlite_queries() as $q ) {
|
||||
$message = "Executing: {$q['sql']} | " . ( $q['params'] ? 'parameters: ' . implode( ', ', $q['params'] ) : '(no parameters)' );
|
||||
$output .= '<li>' . htmlspecialchars( $message ) . '</li>' . PHP_EOL;
|
||||
}
|
||||
$output .= '</ol>' . PHP_EOL;
|
||||
$output .= '</div>' . PHP_EOL;
|
||||
}
|
||||
|
||||
// Message.
|
||||
$output .= '<div style="clear:both;margin-bottom:2px;border:red dotted thin;" class="error_message" style="border-bottom:dotted blue thin;">' . PHP_EOL;
|
||||
$output .= $e->getMessage() . PHP_EOL;
|
||||
$output .= '</div>' . PHP_EOL;
|
||||
|
||||
// Backtrace.
|
||||
$output .= '<p>Backtrace:</p>' . PHP_EOL;
|
||||
$output .= '<pre>' . $e->getTraceAsString() . '</pre>' . PHP_EOL;
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user