init
This commit is contained in:
+363
@@ -0,0 +1,363 @@
|
||||
<?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_Translator
|
||||
*/
|
||||
protected $dbh;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Unlike wpdb, no credentials are needed.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct( '', '', '', '' );
|
||||
$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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to dummy out wpdb::set_sql_mode()
|
||||
*
|
||||
* @see wpdb::set_sql_mode()
|
||||
*
|
||||
* @param array $modes Optional. A list of SQL modes to set.
|
||||
*/
|
||||
public function set_sql_mode( $modes = array() ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $str The string to escape.
|
||||
*
|
||||
* @return string escaped
|
||||
*/
|
||||
public function _real_escape( $str ) {
|
||||
return addslashes( $str );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to dummy out wpdb::esc_like() function.
|
||||
*
|
||||
* WordPress 4.0.0 introduced esc_like() function that adds backslashes to %,
|
||||
* underscore and backslash, which is not interpreted as escape character
|
||||
* by SQLite. So we override it and dummy out this function.
|
||||
*
|
||||
* @param string $text The raw text to be escaped. The input typed by the user should have no
|
||||
* extra or deleted slashes.
|
||||
*
|
||||
* @return string Text in the form of a LIKE phrase. The output is not SQL safe. Call $wpdb::prepare()
|
||||
* or real_escape next.
|
||||
*/
|
||||
public function esc_like( $text ) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to put out the error message.
|
||||
*
|
||||
* This overrides wpdb::print_error(), for we can't use the parent class method.
|
||||
*
|
||||
* @see wpdb::print_error()
|
||||
*
|
||||
* @global array $EZSQL_ERROR Stores error information of query and error string.
|
||||
*
|
||||
* @param string $str The error to display.
|
||||
*
|
||||
* @return bool|void False if the showing of errors is disabled.
|
||||
*/
|
||||
public function print_error( $str = '' ) {
|
||||
global $EZSQL_ERROR;
|
||||
|
||||
if ( ! $str ) {
|
||||
$err = $this->dbh->get_error_message() ? $this->dbh->get_error_message() : '';
|
||||
$str = empty( $err ) ? '' : $err[2];
|
||||
}
|
||||
$EZSQL_ERROR[] = array(
|
||||
'query' => $this->last_query,
|
||||
'error_str' => $str,
|
||||
);
|
||||
|
||||
if ( $this->suppress_errors ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wp_load_translations_early();
|
||||
|
||||
$caller = $this->get_caller();
|
||||
$caller = $caller ? $caller : '(unknown)';
|
||||
|
||||
$error_str = sprintf(
|
||||
'WordPress database error %1$s for query %2$s made by %3$s',
|
||||
$str,
|
||||
$this->last_query,
|
||||
$caller
|
||||
);
|
||||
|
||||
error_log( $error_str );
|
||||
|
||||
if ( ! $this->show_errors ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$msg = "WordPress database error: [$str]\n{$this->last_query}\n";
|
||||
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">WordPress database error: [%1$s] %2$s</p></div>',
|
||||
$str,
|
||||
'<code>' . $query . '</code>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'];
|
||||
}
|
||||
$this->dbh = new WP_SQLite_Translator( $pdo );
|
||||
$this->last_error = $this->dbh->get_error_message();
|
||||
if ( $this->last_error ) {
|
||||
return false;
|
||||
}
|
||||
$GLOBALS['@pdo'] = $this->dbh->get_pdo();
|
||||
$this->ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to dummy out wpdb::check_connection()
|
||||
*
|
||||
* @param bool $allow_bail Not used.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check_connection( $allow_bail = true ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute the query.
|
||||
*
|
||||
* This overrides wpdb::query(). In fact, this method does all the database
|
||||
* access jobs.
|
||||
*
|
||||
* @see wpdb::query()
|
||||
*
|
||||
* @param string $query Database query.
|
||||
*
|
||||
* @return int|false Number of rows affected/selected or false on error
|
||||
*/
|
||||
public function query( $query ) {
|
||||
if ( ! $this->ready ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = apply_filters( 'query', $query );
|
||||
|
||||
$this->flush();
|
||||
|
||||
$this->func_call = "\$db->query(\"$query\")";
|
||||
$this->last_query = $query;
|
||||
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
||||
$this->timer_start();
|
||||
}
|
||||
|
||||
$this->result = $this->dbh->query( $query );
|
||||
++$this->num_queries;
|
||||
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
||||
$this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
|
||||
}
|
||||
|
||||
$this->last_error = $this->dbh->get_error_message();
|
||||
if ( $this->last_error ) {
|
||||
$this->print_error( $this->last_error );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\\s*(set|create|alter|truncate|drop|optimize)\\s*/i', $query ) ) {
|
||||
return $this->dbh->get_return_value();
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\\s*(insert|delete|update|replace)\s/i', $query ) ) {
|
||||
$this->rows_affected = $this->dbh->get_affected_rows();
|
||||
if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
|
||||
$this->insert_id = $this->dbh->get_insert_id();
|
||||
}
|
||||
return $this->rows_affected;
|
||||
}
|
||||
|
||||
$this->last_result = $this->dbh->get_query_results();
|
||||
$this->num_rows = $this->dbh->get_num_rows();
|
||||
return $this->num_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = $this->dbh->get_columns();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves full database server information.
|
||||
*
|
||||
* @return string|false Server info on success, false on failure.
|
||||
*/
|
||||
public function db_server_info() {
|
||||
return SQLite3::version()['versionString'];
|
||||
}
|
||||
}
|
||||
+2575
File diff suppressed because it is too large
Load Diff
+762
@@ -0,0 +1,762 @@
|
||||
<?php
|
||||
/**
|
||||
* Custom functions for the SQLite implementation.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines user defined functions(UDFs) for PDO library.
|
||||
*
|
||||
* These functions replace those used in the SQL statement with the PHP functions.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <code>
|
||||
* new WP_SQLite_PDO_User_Defined_Functions(ref_to_pdo_obj);
|
||||
* </code>
|
||||
*
|
||||
* This automatically enables ref_to_pdo_obj to replace the function in the SQL statement
|
||||
* to the ones defined here.
|
||||
*/
|
||||
class WP_SQLite_PDO_User_Defined_Functions {
|
||||
|
||||
/**
|
||||
* The class constructor
|
||||
*
|
||||
* Initializes the use defined functions to PDO object with PDO::sqliteCreateFunction().
|
||||
*
|
||||
* @param PDO $pdo The PDO object.
|
||||
*/
|
||||
public function __construct( $pdo ) {
|
||||
if ( ! $pdo ) {
|
||||
wp_die( 'Database is not initialized.', 'Database Error' );
|
||||
}
|
||||
foreach ( $this->functions as $f => $t ) {
|
||||
$pdo->sqliteCreateFunction( $f, array( $this, $t ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Array to define MySQL function => function defined with PHP.
|
||||
*
|
||||
* Replaced functions must be public.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $functions = array(
|
||||
'month' => 'month',
|
||||
'monthnum' => 'month',
|
||||
'year' => 'year',
|
||||
'day' => 'day',
|
||||
'hour' => 'hour',
|
||||
'minute' => 'minute',
|
||||
'second' => 'second',
|
||||
'week' => 'week',
|
||||
'weekday' => 'weekday',
|
||||
'dayofweek' => 'dayofweek',
|
||||
'dayofmonth' => 'dayofmonth',
|
||||
'unix_timestamp' => 'unix_timestamp',
|
||||
'now' => 'now',
|
||||
'md5' => 'md5',
|
||||
'curdate' => 'curdate',
|
||||
'rand' => 'rand',
|
||||
'from_unixtime' => 'from_unixtime',
|
||||
'localtime' => 'now',
|
||||
'localtimestamp' => 'now',
|
||||
'isnull' => 'isnull',
|
||||
'if' => '_if',
|
||||
'regexp' => 'regexp',
|
||||
'field' => 'field',
|
||||
'log' => 'log',
|
||||
'least' => 'least',
|
||||
'greatest' => 'greatest',
|
||||
'get_lock' => 'get_lock',
|
||||
'release_lock' => 'release_lock',
|
||||
'ucase' => 'ucase',
|
||||
'lcase' => 'lcase',
|
||||
'unhex' => 'unhex',
|
||||
'inet_ntoa' => 'inet_ntoa',
|
||||
'inet_aton' => 'inet_aton',
|
||||
'datediff' => 'datediff',
|
||||
'locate' => 'locate',
|
||||
'utc_date' => 'utc_date',
|
||||
'utc_time' => 'utc_time',
|
||||
'utc_timestamp' => 'utc_timestamp',
|
||||
'version' => 'version',
|
||||
);
|
||||
|
||||
/**
|
||||
* Method to return the unix timestamp.
|
||||
*
|
||||
* Used without an argument, it returns PHP time() function (total seconds passed
|
||||
* from '1970-01-01 00:00:00' GMT). Used with the argument, it changes the value
|
||||
* to the timestamp.
|
||||
*
|
||||
* @param string $field Representing the date formatted as '0000-00-00 00:00:00'.
|
||||
*
|
||||
* @return number of unsigned integer
|
||||
*/
|
||||
public function unix_timestamp( $field = null ) {
|
||||
return is_null( $field ) ? time() : strtotime( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL FROM_UNIXTIME() function.
|
||||
*
|
||||
* @param int $field The unix timestamp.
|
||||
* @param string $format Indicate the way of formatting(optional).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function from_unixtime( $field, $format = null ) {
|
||||
// Convert to ISO time.
|
||||
$date = gmdate( 'Y-m-d H:i:s', $field );
|
||||
|
||||
return is_null( $format ) ? $date : $this->dateformat( $date, $format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL NOW() function.
|
||||
*
|
||||
* @return string representing current time formatted as '0000-00-00 00:00:00'.
|
||||
*/
|
||||
public function now() {
|
||||
return gmdate( 'Y-m-d H:i:s' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL CURDATE() function.
|
||||
*
|
||||
* @return string representing current time formatted as '0000-00-00'.
|
||||
*/
|
||||
public function curdate() {
|
||||
return gmdate( 'Y-m-d' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL MD5() function.
|
||||
*
|
||||
* @param string $field The string to be hashed.
|
||||
*
|
||||
* @return string of the md5 hash value of the argument.
|
||||
*/
|
||||
public function md5( $field ) {
|
||||
return md5( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL RAND() function.
|
||||
*
|
||||
* SQLite does have a random generator, but it is called RANDOM() and returns random
|
||||
* number between -9223372036854775808 and +9223372036854775807. So we substitute it
|
||||
* with PHP random generator.
|
||||
*
|
||||
* This function uses mt_rand() which is four times faster than rand() and returns
|
||||
* the random number between 0 and 1.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function rand() {
|
||||
return mt_rand( 0, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL DATEFORMAT() function.
|
||||
*
|
||||
* @param string $date Formatted as '0000-00-00' or datetime as '0000-00-00 00:00:00'.
|
||||
* @param string $format The string format.
|
||||
*
|
||||
* @return string formatted according to $format
|
||||
*/
|
||||
public function dateformat( $date, $format ) {
|
||||
$mysql_php_date_formats = array(
|
||||
'%a' => 'D',
|
||||
'%b' => 'M',
|
||||
'%c' => 'n',
|
||||
'%D' => 'jS',
|
||||
'%d' => 'd',
|
||||
'%e' => 'j',
|
||||
'%H' => 'H',
|
||||
'%h' => 'h',
|
||||
'%I' => 'h',
|
||||
'%i' => 'i',
|
||||
'%j' => 'z',
|
||||
'%k' => 'G',
|
||||
'%l' => 'g',
|
||||
'%M' => 'F',
|
||||
'%m' => 'm',
|
||||
'%p' => 'A',
|
||||
'%r' => 'h:i:s A',
|
||||
'%S' => 's',
|
||||
'%s' => 's',
|
||||
'%T' => 'H:i:s',
|
||||
'%U' => 'W',
|
||||
'%u' => 'W',
|
||||
'%V' => 'W',
|
||||
'%v' => 'W',
|
||||
'%W' => 'l',
|
||||
'%w' => 'w',
|
||||
'%X' => 'Y',
|
||||
'%x' => 'o',
|
||||
'%Y' => 'Y',
|
||||
'%y' => 'y',
|
||||
);
|
||||
|
||||
$time = strtotime( $date );
|
||||
$format = strtr( $format, $mysql_php_date_formats );
|
||||
|
||||
return gmdate( $format, $time );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to extract the month value from the date.
|
||||
*
|
||||
* @param string $field Representing the date formatted as 0000-00-00.
|
||||
*
|
||||
* @return string Representing the number of the month between 1 and 12.
|
||||
*/
|
||||
public function month( $field ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* n - Numeric representation of a month, without leading zeros.
|
||||
* 1 through 12
|
||||
*/
|
||||
return intval( gmdate( 'n', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to extract the year value from the date.
|
||||
*
|
||||
* @param string $field Representing the date formatted as 0000-00-00.
|
||||
*
|
||||
* @return string Representing the number of the year.
|
||||
*/
|
||||
public function year( $field ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* Y - A full numeric representation of a year, 4 digits.
|
||||
*/
|
||||
return intval( gmdate( 'Y', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to extract the day value from the date.
|
||||
*
|
||||
* @param string $field Representing the date formatted as 0000-00-00.
|
||||
*
|
||||
* @return string Representing the number of the day of the month from 1 and 31.
|
||||
*/
|
||||
public function day( $field ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* j - Day of the month without leading zeros.
|
||||
* 1 to 31.
|
||||
*/
|
||||
return intval( gmdate( 'j', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL SECOND() function.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/datetime.format.php
|
||||
*
|
||||
* @param string $field Representing the time formatted as '00:00:00'.
|
||||
*
|
||||
* @return number Unsigned integer
|
||||
*/
|
||||
public function second( $field ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* s - Seconds, with leading zeros (00 to 59)
|
||||
*/
|
||||
return intval( gmdate( 's', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL MINUTE() function.
|
||||
*
|
||||
* @param string $field Representing the time formatted as '00:00:00'.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function minute( $field ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* i - Minutes with leading zeros.
|
||||
* 00 to 59.
|
||||
*/
|
||||
return intval( gmdate( 'i', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL HOUR() function.
|
||||
*
|
||||
* Returns the hour for time, in 24-hour format, from 0 to 23.
|
||||
* Importantly, midnight is 0, not 24.
|
||||
*
|
||||
* @param string $time Representing the time formatted, like '14:08:12'.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function hour( $time ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* H 24-hour format of an hour with leading zeros.
|
||||
* 00 through 23.
|
||||
*/
|
||||
return intval( gmdate( 'H', strtotime( $time ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Covers MySQL WEEK() function.
|
||||
*
|
||||
* Always assumes $mode = 1.
|
||||
*
|
||||
* @TODO: Support other modes.
|
||||
*
|
||||
* From https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_week:
|
||||
*
|
||||
* > Returns the week number for date. The two-argument form of WEEK()
|
||||
* > enables you to specify whether the week starts on Sunday or Monday
|
||||
* > and whether the return value should be in the range from 0 to 53
|
||||
* > or from 1 to 53. If the mode argument is omitted, the value of the
|
||||
* > default_week_format system variable is used.
|
||||
* >
|
||||
* > The following table describes how the mode argument works:
|
||||
* >
|
||||
* > Mode First day of week Range Week 1 is the first week …
|
||||
* > 0 Sunday 0-53 with a Sunday in this year
|
||||
* > 1 Monday 0-53 with 4 or more days this year
|
||||
* > 2 Sunday 1-53 with a Sunday in this year
|
||||
* > 3 Monday 1-53 with 4 or more days this year
|
||||
* > 4 Sunday 0-53 with 4 or more days this year
|
||||
* > 5 Monday 0-53 with a Monday in this year
|
||||
* > 6 Sunday 1-53 with 4 or more days this year
|
||||
* > 7 Monday 1-53 with a Monday in this year
|
||||
*
|
||||
* @param string $field Representing the date.
|
||||
* @param int $mode The mode argument.
|
||||
*/
|
||||
public function week( $field, $mode ) {
|
||||
/*
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* W - ISO-8601 week number of year, weeks starting on Monday.
|
||||
* Example: 42 (the 42nd week in the year)
|
||||
*
|
||||
* Week 1 is the first week with a Thursday in it.
|
||||
*/
|
||||
return intval( gmdate( 'W', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates WEEKDAY() function in MySQL.
|
||||
*
|
||||
* Returns the day of the week as an integer.
|
||||
* The days of the week are numbered 0 to 6:
|
||||
* * 0 for Monday
|
||||
* * 1 for Tuesday
|
||||
* * 2 for Wednesday
|
||||
* * 3 for Thursday
|
||||
* * 4 for Friday
|
||||
* * 5 for Saturday
|
||||
* * 6 for Sunday
|
||||
*
|
||||
* @param string $field Representing the date.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function weekday( $field ) {
|
||||
/*
|
||||
* date('N') returns 1 (for Monday) through 7 (for Sunday)
|
||||
* That's one more than MySQL.
|
||||
* Let's subtract one to make it compatible.
|
||||
*/
|
||||
return intval( gmdate( 'N', strtotime( $field ) ) ) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL DAYOFMONTH() function.
|
||||
*
|
||||
* @see https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_dayofmonth
|
||||
*
|
||||
* @param string $field Representing the date.
|
||||
*
|
||||
* @return int Returns the day of the month for date as a number in the range 1 to 31.
|
||||
*/
|
||||
public function dayofmonth( $field ) {
|
||||
return intval( gmdate( 'j', strtotime( $field ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL DAYOFWEEK() function.
|
||||
*
|
||||
* > Returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday).
|
||||
* > These index values correspond to the ODBC standard. Returns NULL if date is NULL.
|
||||
*
|
||||
* @param string $field Representing the date.
|
||||
*
|
||||
* @return int Returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday).
|
||||
*/
|
||||
public function dayofweek( $field ) {
|
||||
/**
|
||||
* From https://www.php.net/manual/en/datetime.format.php:
|
||||
*
|
||||
* `w` – Numeric representation of the day of the week
|
||||
* 0 (for Sunday) through 6 (for Saturday)
|
||||
*/
|
||||
return intval( gmdate( 'w', strtotime( $field ) ) ) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL DATE() function.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/datetime.format.php
|
||||
*
|
||||
* @param string $date formatted as unix time.
|
||||
*
|
||||
* @return string formatted as '0000-00-00'.
|
||||
*/
|
||||
public function date( $date ) {
|
||||
return gmdate( 'Y-m-d', strtotime( $date ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL ISNULL() function.
|
||||
*
|
||||
* This function returns true if the argument is null, and true if not.
|
||||
*
|
||||
* @param mixed $field The field to be tested.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isnull( $field ) {
|
||||
return is_null( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL IF() function.
|
||||
*
|
||||
* As 'IF' is a reserved word for PHP, function name must be changed.
|
||||
*
|
||||
* @param mixed $expression The statement to be evaluated as true or false.
|
||||
* @param mixed $truthy Statement or value returned if $expression is true.
|
||||
* @param mixed $falsy Statement or value returned if $expression is false.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function _if( $expression, $truthy, $falsy ) {
|
||||
return ( true === $expression ) ? $truthy : $falsy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL REGEXP() function.
|
||||
*
|
||||
* @param string $pattern Regular expression to match.
|
||||
* @param string $field Haystack.
|
||||
*
|
||||
* @return integer 1 if matched, 0 if not matched.
|
||||
*/
|
||||
public function regexp( $pattern, $field ) {
|
||||
/*
|
||||
* If the original query says REGEXP BINARY
|
||||
* the comparison is byte-by-byte and letter casing now
|
||||
* matters since lower- and upper-case letters have different
|
||||
* byte codes.
|
||||
*
|
||||
* The REGEXP function can't be easily made to accept two
|
||||
* parameters, so we'll have to use a hack to get around this.
|
||||
*
|
||||
* If the first character of the pattern is a null byte, we'll
|
||||
* remove it and make the comparison case-sensitive. This should
|
||||
* be reasonably safe since PHP does not allow null bytes in
|
||||
* regular expressions anyway.
|
||||
*/
|
||||
if ( "\x00" === $pattern[0] ) {
|
||||
$pattern = substr( $pattern, 1 );
|
||||
$flags = '';
|
||||
} else {
|
||||
// Otherwise, the search is case-insensitive.
|
||||
$flags = 'i';
|
||||
}
|
||||
$pattern = str_replace( '/', '\/', $pattern );
|
||||
$pattern = '/' . $pattern . '/' . $flags;
|
||||
|
||||
return preg_match( $pattern, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL FIELD() function.
|
||||
*
|
||||
* This function gets the list argument and compares the first item to all the others.
|
||||
* If the same value is found, it returns the position of that value. If not, it
|
||||
* returns 0.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function field() {
|
||||
$num_args = func_num_args();
|
||||
if ( $num_args < 2 || is_null( func_get_arg( 0 ) ) ) {
|
||||
return 0;
|
||||
}
|
||||
$arg_list = func_get_args();
|
||||
$search_string = strtolower( array_shift( $arg_list ) );
|
||||
|
||||
for ( $i = 0; $i < $num_args - 1; $i++ ) {
|
||||
if ( strtolower( $arg_list[ $i ] ) === $search_string ) {
|
||||
return $i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL LOG() function.
|
||||
*
|
||||
* Used with one argument, it returns the natural logarithm of X.
|
||||
* <code>
|
||||
* LOG(X)
|
||||
* </code>
|
||||
* Used with two arguments, it returns the natural logarithm of X base B.
|
||||
* <code>
|
||||
* LOG(B, X)
|
||||
* </code>
|
||||
* In this case, it returns the value of log(X) / log(B).
|
||||
*
|
||||
* Used without an argument, it returns false. This returned value will be
|
||||
* rewritten to 0, because SQLite doesn't understand true/false value.
|
||||
*
|
||||
* @return double|null
|
||||
*/
|
||||
public function log() {
|
||||
$num_args = func_num_args();
|
||||
if ( 1 === $num_args ) {
|
||||
$arg1 = func_get_arg( 0 );
|
||||
|
||||
return log( $arg1 );
|
||||
}
|
||||
if ( 2 === $num_args ) {
|
||||
$arg1 = func_get_arg( 0 );
|
||||
$arg2 = func_get_arg( 1 );
|
||||
|
||||
return log( $arg1 ) / log( $arg2 );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL LEAST() function.
|
||||
*
|
||||
* This function rewrites the function name to SQLite compatible function name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function least() {
|
||||
$arg_list = func_get_args();
|
||||
|
||||
return min( $arg_list );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL GREATEST() function.
|
||||
*
|
||||
* This function rewrites the function name to SQLite compatible function name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function greatest() {
|
||||
$arg_list = func_get_args();
|
||||
|
||||
return max( $arg_list );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to dummy out MySQL GET_LOCK() function.
|
||||
*
|
||||
* This function is meaningless in SQLite, so we do nothing.
|
||||
*
|
||||
* @param string $name Not used.
|
||||
* @param integer $timeout Not used.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_lock( $name, $timeout ) {
|
||||
return '1=1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to dummy out MySQL RELEASE_LOCK() function.
|
||||
*
|
||||
* This function is meaningless in SQLite, so we do nothing.
|
||||
*
|
||||
* @param string $name Not used.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function release_lock( $name ) {
|
||||
return '1=1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL UCASE() function.
|
||||
*
|
||||
* This is MySQL alias for upper() function. This function rewrites it
|
||||
* to SQLite compatible name upper().
|
||||
*
|
||||
* @param string $content String to be converted to uppercase.
|
||||
*
|
||||
* @return string SQLite compatible function name.
|
||||
*/
|
||||
public function ucase( $content ) {
|
||||
return "upper($content)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL LCASE() function.
|
||||
*
|
||||
* This is MySQL alias for lower() function. This function rewrites it
|
||||
* to SQLite compatible name lower().
|
||||
*
|
||||
* @param string $content String to be converted to lowercase.
|
||||
*
|
||||
* @return string SQLite compatible function name.
|
||||
*/
|
||||
public function lcase( $content ) {
|
||||
return "lower($content)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL UNHEX() function.
|
||||
*
|
||||
* For a string argument str, UNHEX(str) interprets each pair of characters
|
||||
* in the argument as a hexadecimal number and converts it to the byte represented
|
||||
* by the number. The return value is a binary string.
|
||||
*
|
||||
* @param string $number Number to be unhexed.
|
||||
*
|
||||
* @return string Binary string
|
||||
*/
|
||||
public function unhex( $number ) {
|
||||
return pack( 'H*', $number );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL INET_NTOA() function.
|
||||
*
|
||||
* This function gets 4 or 8 bytes integer and turn it into the network address.
|
||||
*
|
||||
* @param integer $num Long integer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function inet_ntoa( $num ) {
|
||||
return long2ip( $num );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL INET_ATON() function.
|
||||
*
|
||||
* This function gets the network address and turns it into integer.
|
||||
*
|
||||
* @param string $addr Network address.
|
||||
*
|
||||
* @return int long integer
|
||||
*/
|
||||
public function inet_aton( $addr ) {
|
||||
return absint( ip2long( $addr ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL DATEDIFF() function.
|
||||
*
|
||||
* This function compares two dates value and returns the difference.
|
||||
*
|
||||
* @param string $start Start date.
|
||||
* @param string $end End date.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function datediff( $start, $end ) {
|
||||
$start_date = new DateTime( $start );
|
||||
$end_date = new DateTime( $end );
|
||||
$interval = $end_date->diff( $start_date, false );
|
||||
|
||||
return $interval->format( '%r%a' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to emulate MySQL LOCATE() function.
|
||||
*
|
||||
* This function returns the position if $substr is found in $str. If not,
|
||||
* it returns 0. If mbstring extension is loaded, mb_strpos() function is
|
||||
* used.
|
||||
*
|
||||
* @param string $substr Needle.
|
||||
* @param string $str Haystack.
|
||||
* @param integer $pos Position.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function locate( $substr, $str, $pos = 0 ) {
|
||||
if ( ! extension_loaded( 'mbstring' ) ) {
|
||||
$val = strpos( $str, $substr, $pos );
|
||||
if ( false !== $val ) {
|
||||
return $val + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
$val = mb_strpos( $str, $substr, $pos );
|
||||
if ( false !== $val ) {
|
||||
return $val + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return GMT date in the string format.
|
||||
*
|
||||
* @return string formatted GMT date 'dddd-mm-dd'
|
||||
*/
|
||||
public function utc_date() {
|
||||
return gmdate( 'Y-m-d', time() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return GMT time in the string format.
|
||||
*
|
||||
* @return string formatted GMT time '00:00:00'
|
||||
*/
|
||||
public function utc_time() {
|
||||
return gmdate( 'H:i:s', time() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return GMT time stamp in the string format.
|
||||
*
|
||||
* @return string formatted GMT timestamp 'yyyy-mm-dd 00:00:00'
|
||||
*/
|
||||
public function utc_timestamp() {
|
||||
return gmdate( 'Y-m-d H:i:s', time() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return MySQL version.
|
||||
*
|
||||
* This function only returns the current newest version number of MySQL,
|
||||
* because it is meaningless for SQLite database.
|
||||
*
|
||||
* @return string representing the version number: major_version.minor_version
|
||||
*/
|
||||
public function version() {
|
||||
return '5.5';
|
||||
}
|
||||
}
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WP_SQLite_Query_Rewriter
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
/**
|
||||
* The query rewriter class.
|
||||
*/
|
||||
class WP_SQLite_Query_Rewriter {
|
||||
|
||||
/**
|
||||
* An array of input token objects.
|
||||
*
|
||||
* @var WP_SQLite_Token[]
|
||||
*/
|
||||
public $input_tokens = array();
|
||||
|
||||
/**
|
||||
* An array of output token objects.
|
||||
*
|
||||
* @var WP_SQLite_Token[]
|
||||
*/
|
||||
public $output_tokens = array();
|
||||
|
||||
/**
|
||||
* The current index.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $index = -1;
|
||||
|
||||
/**
|
||||
* The maximum index.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $max = -1;
|
||||
|
||||
/**
|
||||
* The call stack.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $call_stack = array();
|
||||
|
||||
/**
|
||||
* The current depth.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $depth = 0;
|
||||
|
||||
/**
|
||||
* The current token.
|
||||
*
|
||||
* @var WP_SQLite_Token
|
||||
*/
|
||||
private $token;
|
||||
|
||||
/**
|
||||
* The last function call.
|
||||
*
|
||||
* @var WP_SQLite_Token
|
||||
*/
|
||||
private $last_function_call;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WP_SQLite_Token[] $input_tokens Array of token objects.
|
||||
*/
|
||||
public function __construct( $input_tokens ) {
|
||||
$this->input_tokens = $input_tokens;
|
||||
$this->max = count( $input_tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the updated query.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_updated_query() {
|
||||
$query = '';
|
||||
foreach ( $this->output_tokens as $token ) {
|
||||
$query .= $token->token;
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a token to the output.
|
||||
*
|
||||
* @param WP_SQLite_Token $token Token object.
|
||||
*/
|
||||
public function add( $token ) {
|
||||
if ( $token ) {
|
||||
$this->output_tokens[] = $token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple tokens to the output.
|
||||
*
|
||||
* @param WP_SQLite_Token[] $tokens Array of token objects.
|
||||
*/
|
||||
public function add_many( $tokens ) {
|
||||
$this->output_tokens = array_merge( $this->output_tokens, $tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all tokens.
|
||||
*
|
||||
* @param WP_SQLite_Token[] $tokens Array of token objects.
|
||||
*/
|
||||
public function replace_all( $tokens ) {
|
||||
$this->output_tokens = $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek at the next tokens and return one that matches the given criteria.
|
||||
*
|
||||
* @param array $query Optional. Search query.
|
||||
* [
|
||||
* 'type' => string|null, // Token type.
|
||||
* 'flags' => int|null, // Token flags.
|
||||
* 'values' => string|null, // Token values.
|
||||
* ].
|
||||
*
|
||||
* @return WP_SQLite_Token
|
||||
*/
|
||||
public function peek( $query = array() ) {
|
||||
$type = isset( $query['type'] ) ? $query['type'] : null;
|
||||
$flags = isset( $query['flags'] ) ? $query['flags'] : null;
|
||||
$values = isset( $query['value'] )
|
||||
? ( is_array( $query['value'] ) ? $query['value'] : array( $query['value'] ) )
|
||||
: null;
|
||||
|
||||
$i = $this->index;
|
||||
while ( ++$i < $this->max ) {
|
||||
if ( $this->input_tokens[ $i ]->matches( $type, $flags, $values ) ) {
|
||||
return $this->input_tokens[ $i ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move forward and return the next tokens that match the given criteria.
|
||||
*
|
||||
* @param int $nth The nth token to return.
|
||||
*
|
||||
* @return WP_SQLite_Token
|
||||
*/
|
||||
public function peek_nth( $nth ) {
|
||||
$found = 0;
|
||||
for ( $i = $this->index + 1;$i < $this->max;$i++ ) {
|
||||
$token = $this->input_tokens[ $i ];
|
||||
if ( ! $token->is_semantically_void() ) {
|
||||
++$found;
|
||||
}
|
||||
if ( $found === $nth ) {
|
||||
return $this->input_tokens[ $i ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume all the tokens.
|
||||
*
|
||||
* @param array $query Search query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function consume_all( $query = array() ) {
|
||||
while ( $this->consume( $query ) ) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume the next tokens and return one that matches the given criteria.
|
||||
*
|
||||
* @param array $query Search query.
|
||||
* [
|
||||
* 'type' => null, // Optional. Token type.
|
||||
* 'flags' => null, // Optional. Token flags.
|
||||
* 'values' => null, // Optional. Token values.
|
||||
* ].
|
||||
*
|
||||
* @return WP_SQLite_Token|null
|
||||
*/
|
||||
public function consume( $query = array() ) {
|
||||
$tokens = $this->move_forward( $query );
|
||||
$this->output_tokens = array_merge( $this->output_tokens, $tokens );
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the last consumed token and return it.
|
||||
*
|
||||
* @return WP_SQLite_Token|null
|
||||
*/
|
||||
public function drop_last() {
|
||||
return array_pop( $this->output_tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip over the next tokens and return one that matches the given criteria.
|
||||
*
|
||||
* @param array $query Search query.
|
||||
* [
|
||||
* 'type' => null, // Optional. Token type.
|
||||
* 'flags' => null, // Optional. Token flags.
|
||||
* 'values' => null, // Optional. Token values.
|
||||
* ].
|
||||
*
|
||||
* @return WP_SQLite_Token|null
|
||||
*/
|
||||
public function skip( $query = array() ) {
|
||||
$this->skip_and_return_all( $query );
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip over the next tokens until one matches the given criteria,
|
||||
* and return all the skipped tokens.
|
||||
*
|
||||
* @param array $query Search query.
|
||||
* [
|
||||
* 'type' => null, // Optional. Token type.
|
||||
* 'flags' => null, // Optional. Token flags.
|
||||
* 'values' => null, // Optional. Token values.
|
||||
* ].
|
||||
*
|
||||
* @return WP_SQLite_Token[]
|
||||
*/
|
||||
public function skip_and_return_all( $query = array() ) {
|
||||
$tokens = $this->move_forward( $query );
|
||||
|
||||
/*
|
||||
* When skipping over whitespaces, make sure to consume
|
||||
* at least one to avoid SQL syntax errors.
|
||||
*/
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->matches( WP_SQLite_Token::TYPE_WHITESPACE ) ) {
|
||||
$this->add( $token );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next tokens that match the given criteria.
|
||||
*
|
||||
* @param array $query Search query.
|
||||
* [
|
||||
* 'type' => string|null, // Optional. Token type.
|
||||
* 'flags' => int|null, // Optional. Token flags.
|
||||
* 'values' => string|null, // Optional. Token values.
|
||||
* ].
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function move_forward( $query = array() ) {
|
||||
$type = isset( $query['type'] ) ? $query['type'] : null;
|
||||
$flags = isset( $query['flags'] ) ? $query['flags'] : null;
|
||||
$values = isset( $query['value'] )
|
||||
? ( is_array( $query['value'] ) ? $query['value'] : array( $query['value'] ) )
|
||||
: null;
|
||||
$depth = isset( $query['depth'] ) ? $query['depth'] : null;
|
||||
|
||||
$buffered = array();
|
||||
while ( true ) {
|
||||
if ( ++$this->index >= $this->max ) {
|
||||
$this->token = null;
|
||||
$this->call_stack = array();
|
||||
break;
|
||||
}
|
||||
$this->token = $this->input_tokens[ $this->index ];
|
||||
$this->update_call_stack();
|
||||
$buffered[] = $this->token;
|
||||
if (
|
||||
( null === $depth || $this->depth === $depth )
|
||||
&& $this->token->matches( $type, $flags, $values )
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $buffered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last call stack element.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function last_call_stack_element() {
|
||||
return count( $this->call_stack ) ? $this->call_stack[ count( $this->call_stack ) - 1 ] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the call stack.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function update_call_stack() {
|
||||
if ( $this->token->flags & WP_SQLite_Token::FLAG_KEYWORD_FUNCTION ) {
|
||||
$this->last_function_call = $this->token->value;
|
||||
}
|
||||
if ( WP_SQLite_Token::TYPE_OPERATOR === $this->token->type ) {
|
||||
switch ( $this->token->value ) {
|
||||
case '(':
|
||||
if ( $this->last_function_call ) {
|
||||
array_push(
|
||||
$this->call_stack,
|
||||
array(
|
||||
'function' => $this->last_function_call,
|
||||
'depth' => $this->depth,
|
||||
)
|
||||
);
|
||||
$this->last_function_call = null;
|
||||
}
|
||||
++$this->depth;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
--$this->depth;
|
||||
$call_parent = $this->last_call_stack_element();
|
||||
if (
|
||||
$call_parent &&
|
||||
$call_parent['depth'] === $this->depth
|
||||
) {
|
||||
array_pop( $this->call_stack );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is a port of the Token class from the PHPMyAdmin/sql-parser library.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
* @see https://github.com/phpmyadmin/sql-parser
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines a token along with a set of types and flags and utility functions.
|
||||
*
|
||||
* An array of tokens will result after parsing the query.
|
||||
*
|
||||
* A structure representing a lexeme that explicitly indicates its categorization for the purpose of parsing.
|
||||
*/
|
||||
class WP_SQLite_Token {
|
||||
|
||||
/**
|
||||
* This type is used when the token is invalid or its type cannot be
|
||||
* determined because of the ambiguous context. Further analysis might be
|
||||
* required to detect its type.
|
||||
*/
|
||||
const TYPE_NONE = 0;
|
||||
|
||||
/**
|
||||
* SQL specific keywords: SELECT, UPDATE, INSERT, etc.
|
||||
*/
|
||||
const TYPE_KEYWORD = 1;
|
||||
|
||||
/**
|
||||
* Any type of legal operator.
|
||||
*
|
||||
* Arithmetic operators: +, -, *, /, etc.
|
||||
* Logical operators: ===, <>, !==, etc.
|
||||
* Bitwise operators: &, |, ^, etc.
|
||||
* Assignment operators: =, +=, -=, etc.
|
||||
* SQL specific operators: . (e.g. .. WHERE database.table ..),
|
||||
* * (e.g. SELECT * FROM ..)
|
||||
*/
|
||||
const TYPE_OPERATOR = 2;
|
||||
|
||||
/**
|
||||
* Spaces, tabs, new lines, etc.
|
||||
*/
|
||||
const TYPE_WHITESPACE = 3;
|
||||
|
||||
/**
|
||||
* Any type of legal comment.
|
||||
*
|
||||
* Bash (#), C (/* *\/) or SQL (--) comments:
|
||||
*
|
||||
* -- SQL-comment
|
||||
*
|
||||
* #Bash-like comment
|
||||
*
|
||||
* /*C-like comment*\/
|
||||
*
|
||||
* or:
|
||||
*
|
||||
* /*C-like
|
||||
* comment*\/
|
||||
*
|
||||
* Backslashes were added to respect PHP's comments syntax.
|
||||
*/
|
||||
const TYPE_COMMENT = 4;
|
||||
|
||||
/**
|
||||
* Boolean values: true or false.
|
||||
*/
|
||||
const TYPE_BOOL = 5;
|
||||
|
||||
/**
|
||||
* Numbers: 4, 0x8, 15.16, 23e42, etc.
|
||||
*/
|
||||
const TYPE_NUMBER = 6;
|
||||
|
||||
/**
|
||||
* Literal strings: 'string', "test".
|
||||
* Some of these strings are actually symbols.
|
||||
*/
|
||||
const TYPE_STRING = 7;
|
||||
|
||||
/**
|
||||
* Database, table names, variables, etc.
|
||||
* For example: ```SELECT `foo`, `bar` FROM `database`.`table`;```.
|
||||
*/
|
||||
const TYPE_SYMBOL = 8;
|
||||
|
||||
/**
|
||||
* Delimits an unknown string.
|
||||
* For example: ```SELECT * FROM test;```, `test` is a delimiter.
|
||||
*/
|
||||
const TYPE_DELIMITER = 9;
|
||||
|
||||
/**
|
||||
* Labels in LOOP statement, ITERATE statement etc.
|
||||
* For example (only for begin label):
|
||||
* begin_label: BEGIN [statement_list] END [end_label]
|
||||
* begin_label: LOOP [statement_list] END LOOP [end_label]
|
||||
* begin_label: REPEAT [statement_list] ... END REPEAT [end_label]
|
||||
* begin_label: WHILE ... DO [statement_list] END WHILE [end_label].
|
||||
*/
|
||||
const TYPE_LABEL = 10;
|
||||
|
||||
// Flags that describe the tokens in more detail.
|
||||
// All keywords must have flag 1 so `Context::isKeyword` method doesn't
|
||||
// require strict comparison.
|
||||
const FLAG_KEYWORD_RESERVED = 2;
|
||||
const FLAG_KEYWORD_COMPOSED = 4;
|
||||
const FLAG_KEYWORD_DATA_TYPE = 8;
|
||||
const FLAG_KEYWORD_KEY = 16;
|
||||
const FLAG_KEYWORD_FUNCTION = 32;
|
||||
|
||||
// Numbers related flags.
|
||||
const FLAG_NUMBER_HEX = 1;
|
||||
const FLAG_NUMBER_FLOAT = 2;
|
||||
const FLAG_NUMBER_APPROXIMATE = 4;
|
||||
const FLAG_NUMBER_NEGATIVE = 8;
|
||||
const FLAG_NUMBER_BINARY = 16;
|
||||
|
||||
// Strings related flags.
|
||||
const FLAG_STRING_SINGLE_QUOTES = 1;
|
||||
const FLAG_STRING_DOUBLE_QUOTES = 2;
|
||||
|
||||
// Comments related flags.
|
||||
const FLAG_COMMENT_BASH = 1;
|
||||
const FLAG_COMMENT_C = 2;
|
||||
const FLAG_COMMENT_SQL = 4;
|
||||
const FLAG_COMMENT_MYSQL_CMD = 8;
|
||||
|
||||
// Operators related flags.
|
||||
const FLAG_OPERATOR_ARITHMETIC = 1;
|
||||
const FLAG_OPERATOR_LOGICAL = 2;
|
||||
const FLAG_OPERATOR_BITWISE = 4;
|
||||
const FLAG_OPERATOR_ASSIGNMENT = 8;
|
||||
const FLAG_OPERATOR_SQL = 16;
|
||||
|
||||
// Symbols related flags.
|
||||
const FLAG_SYMBOL_VARIABLE = 1;
|
||||
const FLAG_SYMBOL_BACKTICK = 2;
|
||||
const FLAG_SYMBOL_USER = 4;
|
||||
const FLAG_SYMBOL_SYSTEM = 8;
|
||||
const FLAG_SYMBOL_PARAMETER = 16;
|
||||
|
||||
/**
|
||||
* The token it its raw string representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* The value this token contains (i.e. token after some evaluation).
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* The keyword value this token contains, always uppercase.
|
||||
*
|
||||
* @var mixed|string|null
|
||||
*/
|
||||
public $keyword = null;
|
||||
|
||||
/**
|
||||
* The type of this token.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* The flags of this token.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $flags;
|
||||
|
||||
/**
|
||||
* The position in the initial string where this token started.
|
||||
*
|
||||
* The position is counted in chars, not bytes, so you should
|
||||
* use mb_* functions to properly handle utf-8 multibyte chars.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
public $position;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $token The value of the token.
|
||||
* @param int $type The type of the token.
|
||||
* @param int $flags The flags of the token.
|
||||
*/
|
||||
public function __construct( $token, $type = 0, $flags = 0 ) {
|
||||
$this->token = $token;
|
||||
$this->type = $type;
|
||||
$this->flags = $flags;
|
||||
$this->value = $this->extract();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the token matches the given parameters.
|
||||
*
|
||||
* @param int|null $type The type of the token.
|
||||
* @param int|null $flags The flags of the token.
|
||||
* @param array|null $values The values of the token.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matches( $type = null, $flags = null, $values = null ) {
|
||||
if ( null === $type && null === $flags && ( null === $values || array() === $values ) ) {
|
||||
return ! $this->is_semantically_void();
|
||||
}
|
||||
|
||||
return (
|
||||
( null === $type || $this->type === $type )
|
||||
&& ( null === $flags || ( $this->flags & $flags ) )
|
||||
&& ( null === $values || in_array( strtoupper( $this->value ?? '' ), $values, true ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the token is semantically void (i.e. whitespace or comment).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_semantically_void() {
|
||||
return $this->matches( self::TYPE_WHITESPACE ) || $this->matches( self::TYPE_COMMENT );
|
||||
}
|
||||
|
||||
/**
|
||||
* Does little processing to the token to extract a value.
|
||||
*
|
||||
* If no processing can be done it will return the initial string.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function extract() {
|
||||
switch ( $this->type ) {
|
||||
case self::TYPE_KEYWORD:
|
||||
$this->keyword = strtoupper( $this->token ?? '' );
|
||||
if ( ! ( $this->flags & self::FLAG_KEYWORD_RESERVED ) ) {
|
||||
/*
|
||||
* Unreserved keywords should stay the way they are
|
||||
* because they might represent field names.
|
||||
*/
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
return $this->keyword;
|
||||
|
||||
case self::TYPE_WHITESPACE:
|
||||
return ' ';
|
||||
|
||||
case self::TYPE_BOOL:
|
||||
return strtoupper( $this->token ?? '' ) === 'TRUE';
|
||||
|
||||
case self::TYPE_NUMBER:
|
||||
$ret = str_replace( '--', '', $this->token ); // e.g. ---42 === -42.
|
||||
if ( $this->flags & self::FLAG_NUMBER_HEX ) {
|
||||
$ret = str_replace( array( '-', '+' ), '', $this->token );
|
||||
if ( $this->flags & self::FLAG_NUMBER_NEGATIVE ) {
|
||||
$ret = -hexdec( $ret );
|
||||
} else {
|
||||
$ret = hexdec( $ret );
|
||||
}
|
||||
} elseif ( ( $this->flags & self::FLAG_NUMBER_APPROXIMATE ) || ( $this->flags & self::FLAG_NUMBER_FLOAT ) ) {
|
||||
$ret = (float) $ret;
|
||||
} elseif ( ! ( $this->flags & self::FLAG_NUMBER_BINARY ) ) {
|
||||
$ret = (int) $ret;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
case self::TYPE_STRING:
|
||||
// Trims quotes.
|
||||
$str = $this->token;
|
||||
$str = mb_substr( $str, 1, -1, 'UTF-8' );
|
||||
|
||||
// Removes surrounding quotes.
|
||||
$quote = $this->token[0];
|
||||
$str = str_replace( $quote . $quote, $quote, $str );
|
||||
|
||||
/*
|
||||
* Finally unescapes the string.
|
||||
*
|
||||
* `stripcslashes` replaces escape sequences with their
|
||||
* representation.
|
||||
*/
|
||||
$str = stripcslashes( $str );
|
||||
|
||||
return $str;
|
||||
|
||||
case self::TYPE_SYMBOL:
|
||||
$str = $this->token;
|
||||
if ( isset( $str[0] ) && ( '@' === $str[0] ) ) {
|
||||
/*
|
||||
* `mb_strlen($str)` must be used instead of `null` because
|
||||
* in PHP 5.3- the `null` parameter isn't handled correctly.
|
||||
*/
|
||||
$str = mb_substr(
|
||||
$str,
|
||||
! empty( $str[1] ) && ( '@' === $str[1] ) ? 2 : 1,
|
||||
mb_strlen( $str ),
|
||||
'UTF-8'
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $str[0] ) && ( ':' === $str[0] ) ) {
|
||||
$str = mb_substr( $str, 1, mb_strlen( $str ), 'UTF-8' );
|
||||
}
|
||||
|
||||
if ( isset( $str[0] ) && ( ( '`' === $str[0] ) || ( '"' === $str[0] ) || ( '\'' === $str[0] ) ) ) {
|
||||
$quote = $str[0];
|
||||
$str = str_replace( $quote . $quote, $quote, $str );
|
||||
$str = mb_substr( $str, 1, -1, 'UTF-8' );
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
return $this->token;
|
||||
}
|
||||
}
|
||||
+4475
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Main integration file.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
// Require the constants file.
|
||||
require_once dirname( __DIR__, 2 ) . '/constants.php';
|
||||
|
||||
// Bail early if DB_ENGINE is not defined as sqlite.
|
||||
if ( ! defined( 'DB_ENGINE' ) || 'sqlite' !== DB_ENGINE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! extension_loaded( 'pdo' ) ) {
|
||||
wp_die(
|
||||
new WP_Error(
|
||||
'pdo_not_loaded',
|
||||
sprintf(
|
||||
'<h1>%1$s</h1><p>%2$s</p>',
|
||||
'PHP PDO Extension is not loaded',
|
||||
'Your PHP installation appears to be missing the PDO extension which is required for this version of WordPress and the type of database you have specified.'
|
||||
)
|
||||
),
|
||||
'PHP PDO Extension is not loaded.'
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! extension_loaded( 'pdo_sqlite' ) ) {
|
||||
wp_die(
|
||||
new WP_Error(
|
||||
'pdo_driver_not_loaded',
|
||||
sprintf(
|
||||
'<h1>%1$s</h1><p>%2$s</p>',
|
||||
'PDO Driver for SQLite is missing',
|
||||
'Your PHP installation appears not to have the right PDO drivers loaded. These are required for this version of WordPress and the type of database you have specified.'
|
||||
)
|
||||
),
|
||||
'PDO Driver for SQLite is missing.'
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/class-wp-sqlite-lexer.php';
|
||||
require_once __DIR__ . '/class-wp-sqlite-query-rewriter.php';
|
||||
require_once __DIR__ . '/class-wp-sqlite-translator.php';
|
||||
require_once __DIR__ . '/class-wp-sqlite-token.php';
|
||||
require_once __DIR__ . '/class-wp-sqlite-pdo-user-defined-functions.php';
|
||||
require_once __DIR__ . '/class-wp-sqlite-db.php';
|
||||
require_once __DIR__ . '/install-functions.php';
|
||||
|
||||
/*
|
||||
* Debug: Cross-check with MySQL.
|
||||
* This is for debugging purpose only and requires files
|
||||
* that are present in the GitHub repository
|
||||
* but not the plugin published on WordPress.org.
|
||||
*/
|
||||
$crosscheck_tests_file_path = dirname( __DIR__, 2 ) . '/tests/class-wp-sqlite-crosscheck-db.php';
|
||||
if ( defined( 'SQLITE_DEBUG_CROSSCHECK' ) && SQLITE_DEBUG_CROSSCHECK && file_exists( $crosscheck_tests_file_path ) ) {
|
||||
require_once $crosscheck_tests_file_path;
|
||||
$GLOBALS['wpdb'] = new WP_SQLite_Crosscheck_DB();
|
||||
} else {
|
||||
$GLOBALS['wpdb'] = new WP_SQLite_DB();
|
||||
}
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
/**
|
||||
* Main integration file.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to create tables according to the schemas of WordPress.
|
||||
*
|
||||
* This is executed only once while installation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @throws PDOException If the database connection fails.
|
||||
*/
|
||||
function sqlite_make_db_sqlite() {
|
||||
include_once ABSPATH . 'wp-admin/includes/schema.php';
|
||||
|
||||
$table_schemas = wp_get_db_schema();
|
||||
$queries = explode( ';', $table_schemas );
|
||||
try {
|
||||
$pdo = new PDO( 'sqlite:' . FQDB, null, null, array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ) ); // phpcs:ignore WordPress.DB.RestrictedClasses
|
||||
} catch ( PDOException $err ) {
|
||||
$err_data = $err->errorInfo; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$message = 'Database connection error!<br />';
|
||||
$message .= sprintf( 'Error message is: %s', $err_data[2] );
|
||||
wp_die( $message, 'Database Error!' );
|
||||
}
|
||||
|
||||
$translator = new WP_SQLite_Translator( $pdo );
|
||||
$query = null;
|
||||
|
||||
try {
|
||||
$translator->begin_transaction();
|
||||
foreach ( $queries as $query ) {
|
||||
$query = trim( $query );
|
||||
if ( empty( $query ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $translator->query( $query );
|
||||
if ( false === $result ) {
|
||||
throw new PDOException( $translator->get_error_message() );
|
||||
}
|
||||
}
|
||||
$translator->commit();
|
||||
} catch ( PDOException $err ) {
|
||||
$err_data = $err->errorInfo; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$err_code = $err_data[1];
|
||||
$translator->rollback();
|
||||
$message = sprintf(
|
||||
'Error occurred while creating tables or indexes...<br />Query was: %s<br />',
|
||||
var_export( $query, true )
|
||||
);
|
||||
$message .= sprintf( 'Error message is: %s', $err_data[2] );
|
||||
wp_die( $message, 'Database Error!' );
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug: Cross-check with MySQL.
|
||||
* This is for debugging purpose only and requires files
|
||||
* that are present in the GitHub repository
|
||||
* but not the plugin published on WordPress.org.
|
||||
*/
|
||||
if ( defined( 'SQLITE_DEBUG_CROSSCHECK' ) && SQLITE_DEBUG_CROSSCHECK ) {
|
||||
$host = DB_HOST;
|
||||
$port = 3306;
|
||||
if ( str_contains( $host, ':' ) ) {
|
||||
$host_parts = explode( ':', $host );
|
||||
$host = $host_parts[0];
|
||||
$port = $host_parts[1];
|
||||
}
|
||||
$dsn = 'mysql:host=' . $host . '; port=' . $port . '; dbname=' . DB_NAME;
|
||||
$pdo_mysql = new PDO( $dsn, DB_USER, DB_PASSWORD, array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ) ); // phpcs:ignore WordPress.DB.RestrictedClasses.mysql__PDO
|
||||
$pdo_mysql->query( 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' );
|
||||
$pdo_mysql->query( 'SET time_zone = "+00:00";' );
|
||||
foreach ( $queries as $query ) {
|
||||
$query = trim( $query );
|
||||
if ( empty( $query ) ) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$pdo_mysql->beginTransaction();
|
||||
$pdo_mysql->query( $query );
|
||||
} catch ( PDOException $err ) {
|
||||
$err_data = $err->errorInfo; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$err_code = $err_data[1];
|
||||
// phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
|
||||
if ( 5 == $err_code || 6 == $err_code ) {
|
||||
// If the database is locked, commit again.
|
||||
$pdo_mysql->commit();
|
||||
} else {
|
||||
$pdo_mysql->rollBack();
|
||||
$message = sprintf(
|
||||
'Error occurred while creating tables or indexes...<br />Query was: %s<br />',
|
||||
var_export( $query, true )
|
||||
);
|
||||
$message .= sprintf( 'Error message is: %s', $err_data[2] );
|
||||
wp_die( $message, 'Database Error!' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pdo = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'wp_install' ) ) {
|
||||
/**
|
||||
* Installs the site.
|
||||
*
|
||||
* Runs the required functions to set up and populate the database,
|
||||
* including primary admin user and initial options.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $blog_title Site title.
|
||||
* @param string $user_name User's username.
|
||||
* @param string $user_email User's email.
|
||||
* @param bool $is_public Whether the site is public.
|
||||
* @param string $deprecated Optional. Not used.
|
||||
* @param string $user_password Optional. User's chosen password. Default empty (random password).
|
||||
* @param string $language Optional. Language chosen. Default empty.
|
||||
* @return array {
|
||||
* Data for the newly installed site.
|
||||
*
|
||||
* @type string $url The URL of the site.
|
||||
* @type int $user_id The ID of the site owner.
|
||||
* @type string $password The password of the site owner, if their user account didn't already exist.
|
||||
* @type string $password_message The explanatory message regarding the password.
|
||||
* }
|
||||
*/
|
||||
function wp_install( $blog_title, $user_name, $user_email, $is_public, $deprecated = '', $user_password = '', $language = '' ) {
|
||||
if ( ! empty( $deprecated ) ) {
|
||||
_deprecated_argument( __FUNCTION__, '2.6.0' );
|
||||
}
|
||||
|
||||
wp_check_mysql_version();
|
||||
wp_cache_flush();
|
||||
/* SQLite changes: Replace the call to make_db_current_silent() with sqlite_make_db_sqlite(). */
|
||||
sqlite_make_db_sqlite(); // phpcs:ignore PHPCompatibility.Extensions.RemovedExtensions.sqliteRemoved
|
||||
populate_options();
|
||||
populate_roles();
|
||||
|
||||
update_option( 'blogname', $blog_title );
|
||||
update_option( 'admin_email', $user_email );
|
||||
update_option( 'blog_public', $is_public );
|
||||
|
||||
// Freshness of site - in the future, this could get more specific about actions taken, perhaps.
|
||||
update_option( 'fresh_site', 1 );
|
||||
|
||||
if ( $language ) {
|
||||
update_option( 'WPLANG', $language );
|
||||
}
|
||||
|
||||
$guessurl = wp_guess_url();
|
||||
|
||||
update_option( 'siteurl', $guessurl );
|
||||
|
||||
// If not a public site, don't ping.
|
||||
if ( ! $is_public ) {
|
||||
update_option( 'default_pingback_flag', 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Create default user. If the user already exists, the user tables are
|
||||
* being shared among sites. Just set the role in that case.
|
||||
*/
|
||||
$user_id = username_exists( $user_name );
|
||||
$user_password = trim( $user_password );
|
||||
$email_password = false;
|
||||
$user_created = false;
|
||||
|
||||
if ( ! $user_id && empty( $user_password ) ) {
|
||||
$user_password = wp_generate_password( 12, false );
|
||||
$message = __( '<strong><em>Note that password</em></strong> carefully! It is a <em>random</em> password that was generated just for you.', 'sqlite-database-integration' );
|
||||
$user_id = wp_create_user( $user_name, $user_password, $user_email );
|
||||
update_user_meta( $user_id, 'default_password_nag', true );
|
||||
$email_password = true;
|
||||
$user_created = true;
|
||||
} elseif ( ! $user_id ) {
|
||||
// Password has been provided.
|
||||
$message = '<em>' . __( 'Your chosen password.', 'sqlite-database-integration' ) . '</em>';
|
||||
$user_id = wp_create_user( $user_name, $user_password, $user_email );
|
||||
$user_created = true;
|
||||
} else {
|
||||
$message = __( 'User already exists. Password inherited.', 'sqlite-database-integration' );
|
||||
}
|
||||
|
||||
$user = new WP_User( $user_id );
|
||||
$user->set_role( 'administrator' );
|
||||
|
||||
if ( $user_created ) {
|
||||
$user->user_url = $guessurl;
|
||||
wp_update_user( $user );
|
||||
}
|
||||
|
||||
wp_install_defaults( $user_id );
|
||||
|
||||
wp_install_maybe_enable_pretty_permalinks();
|
||||
|
||||
flush_rewrite_rules();
|
||||
|
||||
wp_new_blog_notification( $blog_title, $guessurl, $user_id, ( $email_password ? $user_password : __( 'The password you chose during installation.', 'sqlite-database-integration' ) ) );
|
||||
|
||||
wp_cache_flush();
|
||||
|
||||
/**
|
||||
* Fires after a site is fully installed.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @param WP_User $user The site owner.
|
||||
*/
|
||||
do_action( 'wp_install', $user );
|
||||
|
||||
return array(
|
||||
'url' => $guessurl,
|
||||
'user_id' => $user_id,
|
||||
'password' => $user_password,
|
||||
'password_message' => $message,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user