init
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/**
|
||||
* Handle the SQLite activation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
/**
|
||||
* Redirect to the plugin's admin screen on activation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $plugin The plugin basename.
|
||||
*/
|
||||
function sqlite_plugin_activation_redirect( $plugin ) {
|
||||
if ( plugin_basename( SQLITE_MAIN_FILE ) === $plugin ) {
|
||||
if ( wp_safe_redirect( admin_url( 'options-general.php?page=sqlite-integration' ) ) ) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action( 'activated_plugin', 'sqlite_plugin_activation_redirect' );
|
||||
|
||||
/**
|
||||
* Check the URL to ensure we're on the plugin page,
|
||||
* the user has clicked the button to install SQLite,
|
||||
* and the nonce is valid.
|
||||
* If the above conditions are met, run the sqlite_plugin_copy_db_file() function,
|
||||
* and redirect to the install screen.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
function sqlite_activation() {
|
||||
global $current_screen;
|
||||
if ( isset( $current_screen->base ) && 'settings_page_sqlite-integration' === $current_screen->base ) {
|
||||
return;
|
||||
}
|
||||
if ( isset( $_GET['confirm-install'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'sqlite-install' ) ) {
|
||||
|
||||
// Handle upgrading from the performance-lab plugin.
|
||||
if ( isset( $_GET['upgrade-from-pl'] ) ) {
|
||||
global $wp_filesystem;
|
||||
require_once ABSPATH . '/wp-admin/includes/file.php';
|
||||
// Delete the previous db.php file.
|
||||
$wp_filesystem->delete( WP_CONTENT_DIR . '/db.php' );
|
||||
// Deactivate the performance-lab SQLite module.
|
||||
$pl_option_name = defined( 'PERFLAB_MODULES_SETTING' ) ? PERFLAB_MODULES_SETTING : 'perflab_modules_settings';
|
||||
$pl_option = get_option( $pl_option_name, array() );
|
||||
unset( $pl_option['database/sqlite'] );
|
||||
update_option( $pl_option_name, $pl_option );
|
||||
}
|
||||
sqlite_plugin_copy_db_file();
|
||||
// WordPress will automatically redirect to the install screen here.
|
||||
wp_redirect( admin_url() );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
add_action( 'admin_init', 'sqlite_activation' );
|
||||
|
||||
// Flush the cache at the last moment before the redirect.
|
||||
add_filter(
|
||||
'x_redirect_by',
|
||||
function ( $result ) {
|
||||
wp_cache_flush();
|
||||
return $result;
|
||||
},
|
||||
PHP_INT_MAX,
|
||||
1
|
||||
);
|
||||
|
||||
/**
|
||||
* Add the db.php file in wp-content.
|
||||
*
|
||||
* When the plugin gets merged in wp-core, this is not to be ported.
|
||||
*/
|
||||
function sqlite_plugin_copy_db_file() {
|
||||
// Bail early if the SQLite3 class does not exist.
|
||||
if ( ! class_exists( 'SQLite3' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$destination = WP_CONTENT_DIR . '/db.php';
|
||||
|
||||
// Place database drop-in if not present yet, except in case there is
|
||||
// another database drop-in present already.
|
||||
if ( ! defined( 'SQLITE_DB_DROPIN_VERSION' ) && ! file_exists( $destination ) ) {
|
||||
// Init the filesystem to allow copying the file.
|
||||
global $wp_filesystem;
|
||||
|
||||
require_once ABSPATH . '/wp-admin/includes/file.php';
|
||||
|
||||
// Init the filesystem if needed, then copy the file, replacing contents as needed.
|
||||
if ( ( $wp_filesystem || WP_Filesystem() ) && $wp_filesystem->touch( $destination ) ) {
|
||||
|
||||
// Get the db.copy.php file contents, replace placeholders and write it to the destination.
|
||||
$file_contents = str_replace(
|
||||
array(
|
||||
'{SQLITE_IMPLEMENTATION_FOLDER_PATH}',
|
||||
'{SQLITE_PLUGIN}',
|
||||
),
|
||||
array(
|
||||
__DIR__,
|
||||
str_replace( WP_PLUGIN_DIR . '/', '', SQLITE_MAIN_FILE ),
|
||||
),
|
||||
file_get_contents( __DIR__ . '/db.copy' )
|
||||
);
|
||||
|
||||
$wp_filesystem->put_contents( $destination, $file_contents );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Functions to add admin notices if necessary.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add admin notices.
|
||||
*
|
||||
* When the plugin gets merged in wp-core, this is not to be ported.
|
||||
*/
|
||||
function sqlite_plugin_admin_notice() {
|
||||
|
||||
// Don't print notices in the plugin's admin screen.
|
||||
global $current_screen;
|
||||
if ( isset( $current_screen->base ) && 'settings_page_sqlite-integration' === $current_screen->base ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If SQLite is not detected, bail early.
|
||||
if ( ! class_exists( 'SQLite3' ) ) {
|
||||
printf(
|
||||
'<div class="notice notice-error"><p>%s</p></div>',
|
||||
esc_html__( 'The SQLite Integration plugin is active, but the SQLite3 class is missing from your server. Please make sure that SQLite is enabled in your PHP installation.', 'sqlite-database-integration' )
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the SQLITE_DB_DROPIN_VERSION constant is not defined
|
||||
* but there's a db.php file in the wp-content directory, then the module can't be activated.
|
||||
* The module should not have been activated in the first place
|
||||
* (there's a check in the can-load.php file), but this is a fallback check.
|
||||
*/
|
||||
if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'SQLITE_DB_DROPIN_VERSION' ) ) {
|
||||
printf(
|
||||
'<div class="notice notice-error"><p>%s</p></div>',
|
||||
sprintf(
|
||||
/* translators: 1: SQLITE_DB_DROPIN_VERSION constant, 2: db.php drop-in path */
|
||||
__( 'The SQLite Integration module is active, but the %1$s constant is missing. It appears you already have another %2$s file present on your site. ', 'sqlite-database-integration' ),
|
||||
'<code>SQLITE_DB_DROPIN_VERSION</code>',
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
|
||||
)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wp_is_writable( WP_CONTENT_DIR ) ) {
|
||||
printf(
|
||||
'<div class="notice notice-error"><p>%s</p></div>',
|
||||
esc_html__( 'The SQLite Integration plugin is active, but the wp-content/db.php file is missing and the wp-content directory is not writable. Please ensure the wp-content folder is writable, then deactivate the plugin and try again.', 'sqlite-database-integration' )
|
||||
);
|
||||
return;
|
||||
}
|
||||
// The dropin db.php is missing.
|
||||
printf(
|
||||
'<div class="notice notice-error"><p>%s</p></div>',
|
||||
sprintf(
|
||||
/* translators: 1: db.php drop-in path, 2: Admin URL to deactivate the module */
|
||||
__( 'The SQLite Integration plugin is active, but the %1$s file is missing. Please <a href="%2$s">deactivate the plugin</a> and re-activate it to try again.', 'sqlite-database-integration' ),
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>',
|
||||
esc_url( admin_url( 'plugins.php' ) )
|
||||
)
|
||||
);
|
||||
}
|
||||
add_action( 'admin_notices', 'sqlite_plugin_admin_notice' ); // Add the admin notices.
|
||||
|
||||
// Remove the PL-plugin admin notices for SQLite.
|
||||
remove_action( 'admin_notices', 'perflab_sqlite_plugin_admin_notice' );
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* Functions for the admin page of the plugin.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add an admin menu page.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
function sqlite_add_admin_menu() {
|
||||
add_options_page(
|
||||
__( 'SQLite integration', 'sqlite-database-integration' ),
|
||||
__( 'SQLite integration', 'sqlite-database-integration' ),
|
||||
'manage_options',
|
||||
'sqlite-integration',
|
||||
'sqlite_integration_admin_screen'
|
||||
);
|
||||
}
|
||||
add_action( 'admin_menu', 'sqlite_add_admin_menu' );
|
||||
|
||||
/**
|
||||
* The admin page contents.
|
||||
*/
|
||||
function sqlite_integration_admin_screen() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'SQLite integration.', 'sqlite-database-integration' ); ?></h1>
|
||||
</div>
|
||||
<!-- Set the wrapper width to 50em, to improve readability. -->
|
||||
<div style="max-width:50em;">
|
||||
<?php if ( defined( 'SQLITE_DB_DROPIN_VERSION' ) ) : ?>
|
||||
<div class="notice notice-success">
|
||||
<p><?php esc_html_e( 'SQLite is enabled.', 'sqlite-database-integration' ); ?></p>
|
||||
</div>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: 1: Admin URL to deactivate the module, 2: db.php drop-in path, */
|
||||
__( 'The SQLite drop-in is enabled. To disable it and get back to your previous, MySQL database, you can <a href="%1$s">deactivate the plugin</a>. Alternatively, you can manually delete the %2$s file from your server.', 'sqlite-database-integration' ),
|
||||
esc_url( admin_url( 'plugins.php' ) ),
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<?php if ( ! class_exists( 'SQLite3' ) ) : ?>
|
||||
<div class="notice notice-error">
|
||||
<p><?php esc_html_e( 'We detected that the SQLite3 class is missing from your server. Please make sure that SQLite is enabled in your PHP installation before proceeding.', 'sqlite-database-integration' ); ?></p>
|
||||
</div>
|
||||
<?php elseif ( ! extension_loaded( 'pdo_sqlite' ) ) : ?>
|
||||
<div class="notice notice-error">
|
||||
<p><?php esc_html_e( 'We detected that the PDO SQLite driver is missing from your server (the pdo_sqlite extension is not loaded). Please make sure that SQLite is enabled in your PHP installation before proceeding.', 'sqlite-database-integration' ); ?></p>
|
||||
</div>
|
||||
<?php elseif ( file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'SQLITE_DB_DROPIN_VERSION' ) ) : ?>
|
||||
<?php if ( defined( 'PERFLAB_SQLITE_DB_DROPIN_VERSION' ) ) : ?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: db.php drop-in path */
|
||||
esc_html__( 'An older %s file was detected. Please click the button below to update the file.', 'sqlite-database-integration' ),
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<a class="button button-primary" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sqlite-integration&confirm-install&upgrade-from-pl' ), 'sqlite-install' ) ); ?>">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: db.php drop-in path */
|
||||
esc_html__( 'Update %s file', 'sqlite-database-integration' ),
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
|
||||
);
|
||||
?>
|
||||
</a>
|
||||
<?php else : ?>
|
||||
<div class="notice notice-error">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: db.php drop-in path */
|
||||
esc_html__( 'The SQLite plugin cannot be activated because a different %s drop-in already exists.', 'sqlite-database-integration' ),
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php elseif ( ! is_writable( WP_CONTENT_DIR ) ) : ?>
|
||||
<div class="notice notice-error">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: db.php drop-in path */
|
||||
esc_html__( 'The SQLite plugin cannot be activated because the %s directory is not writable.', 'sqlite-database-integration' ),
|
||||
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="notice notice-success">
|
||||
<p><?php esc_html_e( 'All checks completed successfully, your site can use an SQLite database. You can proceed with the installation.', 'sqlite-database-integration' ); ?></p>
|
||||
</div>
|
||||
<h2><?php esc_html_e( 'Important note', 'sqlite-database-integration' ); ?></h2>
|
||||
<p><?php esc_html_e( 'This plugin will switch to a separate database and install WordPress in it. You will need to reconfigure your site, and start with a fresh site. Disabling the plugin you will get back to your previous MySQL database, with all your previous data intact.', 'sqlite-database-integration' ); ?></p>
|
||||
<p><?php esc_html_e( 'By clicking the button below, you will be redirected to the WordPress installation screen to setup your new database', 'sqlite-database-integration' ); ?></p>
|
||||
|
||||
<a class="button button-primary" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sqlite-integration&confirm-install' ), 'sqlite-install' ) ); ?>"><?php esc_html_e( 'Install SQLite database', 'sqlite-database-integration' ); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a link to the admin bar.
|
||||
*
|
||||
* @since n.e.x.t
|
||||
*
|
||||
* @global wpdb $wpdb WordPress database abstraction object.
|
||||
*
|
||||
* @param WP_Admin_Bar $admin_bar The admin bar object.
|
||||
*/
|
||||
function sqlite_plugin_adminbar_item( $admin_bar ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( defined( 'SQLITE_DB_DROPIN_VERSION' ) && defined( 'DB_ENGINE' ) && 'sqlite' === DB_ENGINE ) {
|
||||
$title = '<span style="color:#46B450;">' . __( 'Database: SQLite', 'sqlite-database-integration' ) . '</span>';
|
||||
} elseif ( stripos( $wpdb->db_server_info(), 'maria' ) !== false ) {
|
||||
$title = '<span style="color:#DC3232;">' . __( 'Database: MariaDB', 'sqlite-database-integration' ) . '</span>';
|
||||
} else {
|
||||
$title = '<span style="color:#DC3232;">' . __( 'Database: MySQL', 'sqlite-database-integration' ) . '</span>';
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'id' => 'sqlite-db-integration',
|
||||
'parent' => 'top-secondary',
|
||||
'title' => $title,
|
||||
'href' => esc_url( admin_url( 'options-general.php?page=sqlite-integration' ) ),
|
||||
'meta' => false,
|
||||
);
|
||||
$admin_bar->add_node( $args );
|
||||
}
|
||||
add_action( 'admin_bar_menu', 'sqlite_plugin_adminbar_item', 999 );
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Define constants for the SQLite implementation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
// Temporary - This will be in wp-config.php once SQLite is merged in Core.
|
||||
if ( ! defined( 'DB_ENGINE' ) ) {
|
||||
if ( defined( 'SQLITE_DB_DROPIN_VERSION' ) ) {
|
||||
define( 'DB_ENGINE', 'sqlite' );
|
||||
} elseif ( defined( 'DATABASE_ENGINE' ) ) {
|
||||
// backwards compatibility with previous versions of the plugin.
|
||||
define( 'DB_ENGINE', DATABASE_ENGINE );
|
||||
} else {
|
||||
define( 'DB_ENGINE', 'mysql' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice:
|
||||
* Your scripts have the permission to create directories or files on your server.
|
||||
* If you write in your wp-config.php like below, we take these definitions.
|
||||
* define('DB_DIR', '/full_path_to_the_database_directory/');
|
||||
* define('DB_FILE', 'database_file_name');
|
||||
*/
|
||||
|
||||
/**
|
||||
* FQDBDIR is a directory where the sqlite database file is placed.
|
||||
* If DB_DIR is defined, it is used as FQDBDIR.
|
||||
*/
|
||||
if ( ! defined( 'FQDBDIR' ) ) {
|
||||
if ( defined( 'DB_DIR' ) ) {
|
||||
define( 'FQDBDIR', trailingslashit( DB_DIR ) );
|
||||
} elseif ( defined( 'WP_CONTENT_DIR' ) ) {
|
||||
define( 'FQDBDIR', WP_CONTENT_DIR . '/database/' );
|
||||
} else {
|
||||
define( 'FQDBDIR', ABSPATH . 'wp-content/database/' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FQDB is a database file name. If DB_FILE is defined, it is used
|
||||
* as FQDB.
|
||||
*/
|
||||
if ( ! defined( 'FQDB' ) ) {
|
||||
if ( defined( 'DB_FILE' ) ) {
|
||||
define( 'FQDB', FQDBDIR . DB_FILE );
|
||||
} else {
|
||||
define( 'FQDB', FQDBDIR . '.ht.sqlite' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: SQLite integration (Drop-in)
|
||||
* Version: 1.0.0
|
||||
* Author: WordPress Performance Team
|
||||
* Author URI: https://make.wordpress.org/performance/
|
||||
*
|
||||
* This file is auto-generated and copied from the sqlite plugin.
|
||||
* Please don't edit this file directly.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
define( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );
|
||||
|
||||
// Tweak to allow copy-pasting the file without having to run string-replacements.
|
||||
$sqlite_plugin_implementation_folder_path = '{SQLITE_IMPLEMENTATION_FOLDER_PATH}';
|
||||
if ( ! file_exists( $sqlite_plugin_implementation_folder_path ) ) { // Check that the folder exists.
|
||||
$sqlite_plugin_implementation_folder_path = realpath( __DIR__ . '/plugins/sqlite-database-integration' );
|
||||
}
|
||||
|
||||
// Bail early if the SQLite implementation was not located in the plugin.
|
||||
if ( ! $sqlite_plugin_implementation_folder_path || ! file_exists( $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/db.php' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Constant for backward compatibility.
|
||||
if ( ! defined( 'DATABASE_TYPE' ) ) {
|
||||
define( 'DATABASE_TYPE', 'sqlite' );
|
||||
}
|
||||
// Define SQLite constant.
|
||||
if ( ! defined( 'DB_ENGINE' ) ) {
|
||||
define( 'DB_ENGINE', 'sqlite' );
|
||||
}
|
||||
|
||||
// Require the implementation from the plugin.
|
||||
require_once $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/db.php';
|
||||
|
||||
// Activate the performance-lab plugin if it is not already activated.
|
||||
add_action(
|
||||
'admin_footer',
|
||||
function() {
|
||||
if ( defined( 'SQLITE_MAIN_FILE' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( ! function_exists( 'activate_plugin' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
if ( is_plugin_inactive( '{SQLITE_PLUGIN}' ) ) {
|
||||
// If `activate_plugin()` returns a value other than null (like WP_Error),
|
||||
// the plugin could not be found. Try with a hardcoded string,
|
||||
// because that probably means the file was directly copy-pasted.
|
||||
if ( null !== activate_plugin( '{SQLITE_PLUGIN}', '', false, true ) ) {
|
||||
activate_plugin( 'sqlite-database-integration/load.php', '', false, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Handle the SQLite deactivation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
/**
|
||||
* Delete the db.php file in wp-content.
|
||||
*
|
||||
* When the plugin gets merged in wp-core, this is not to be ported.
|
||||
*/
|
||||
function sqlite_plugin_remove_db_file() {
|
||||
if ( ! defined( 'SQLITE_DB_DROPIN_VERSION' ) || ! file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wp_filesystem;
|
||||
|
||||
require_once ABSPATH . '/wp-admin/includes/file.php';
|
||||
|
||||
// Init the filesystem if needed, then delete custom drop-in.
|
||||
if ( $wp_filesystem || WP_Filesystem() ) {
|
||||
// Flush any persistent cache.
|
||||
wp_cache_flush();
|
||||
// Delete the drop-in.
|
||||
$wp_filesystem->delete( WP_CONTENT_DIR . '/db.php' );
|
||||
// Flush the cache again to mitigate a possible race condition.
|
||||
wp_cache_flush();
|
||||
}
|
||||
|
||||
// Run an action on `shutdown`, to deactivate the option in the MySQL database.
|
||||
add_action(
|
||||
'shutdown',
|
||||
function () {
|
||||
global $table_prefix;
|
||||
|
||||
// Get credentials for the MySQL database.
|
||||
$dbuser = defined( 'DB_USER' ) ? DB_USER : '';
|
||||
$dbpassword = defined( 'DB_PASSWORD' ) ? DB_PASSWORD : '';
|
||||
$dbname = defined( 'DB_NAME' ) ? DB_NAME : '';
|
||||
$dbhost = defined( 'DB_HOST' ) ? DB_HOST : '';
|
||||
|
||||
// Init a connection to the MySQL database.
|
||||
$wpdb_mysql = new wpdb( $dbuser, $dbpassword, $dbname, $dbhost );
|
||||
$wpdb_mysql->set_prefix( $table_prefix );
|
||||
|
||||
// Get the perflab options, remove the database/sqlite module and update the option.
|
||||
$row = $wpdb_mysql->get_row( $wpdb_mysql->prepare( "SELECT option_value FROM $wpdb_mysql->options WHERE option_name = %s LIMIT 1", 'active_plugins' ) );
|
||||
if ( is_object( $row ) ) {
|
||||
$value = maybe_unserialize( $row->option_value );
|
||||
if ( is_array( $value ) ) {
|
||||
$value_flipped = array_flip( $value );
|
||||
$items = array_reverse( explode( DIRECTORY_SEPARATOR, SQLITE_MAIN_FILE ) );
|
||||
$item = $items[1] . DIRECTORY_SEPARATOR . $items[0];
|
||||
unset( $value_flipped[ $item ] );
|
||||
$value = array_flip( $value_flipped );
|
||||
$wpdb_mysql->update( $wpdb_mysql->options, array( 'option_value' => maybe_serialize( $value ) ), array( 'option_name' => 'active_plugins' ) );
|
||||
}
|
||||
}
|
||||
},
|
||||
PHP_INT_MAX
|
||||
);
|
||||
// Flush any persistent cache.
|
||||
wp_cache_flush();
|
||||
}
|
||||
register_deactivation_hook( SQLITE_MAIN_FILE, 'sqlite_plugin_remove_db_file' ); // Remove db.php file on plugin deactivation.
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Tweaks for the health-check screens.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
/**
|
||||
* Filter debug data in site-health screen.
|
||||
*
|
||||
* When the plugin gets merged in wp-core, these should be merged in src/wp-admin/includes/class-wp-debug-data.php
|
||||
* See https://github.com/WordPress/wordpress-develop/pull/3220/files
|
||||
*
|
||||
* @param array $info The debug data.
|
||||
*/
|
||||
function sqlite_plugin_filter_debug_data( $info ) {
|
||||
$db_engine = defined( 'DB_ENGINE' ) && 'sqlite' === DB_ENGINE ? 'sqlite' : 'mysql';
|
||||
|
||||
$info['wp-constants']['fields']['DB_ENGINE'] = array(
|
||||
'label' => 'DB_ENGINE',
|
||||
'value' => ( defined( 'DB_ENGINE' ) ? DB_ENGINE : __( 'Undefined', 'sqlite-database-integration' ) ),
|
||||
'debug' => ( defined( 'DB_ENGINE' ) ? DB_ENGINE : 'undefined' ),
|
||||
);
|
||||
|
||||
$info['wp-database']['fields']['db_engine'] = array(
|
||||
'label' => __( 'Database type', 'sqlite-database-integration' ),
|
||||
'value' => 'sqlite' === $db_engine ? 'SQLite' : 'MySQL/MariaDB',
|
||||
);
|
||||
|
||||
if ( 'sqlite' === $db_engine ) {
|
||||
$info['wp-database']['fields']['database_version'] = array(
|
||||
'label' => __( 'SQLite version', 'sqlite-database-integration' ),
|
||||
'value' => class_exists( 'SQLite3' ) ? SQLite3::version()['versionString'] : null,
|
||||
);
|
||||
|
||||
$info['wp-database']['fields']['database_file'] = array(
|
||||
'label' => __( 'Database file', 'sqlite-database-integration' ),
|
||||
'value' => FQDB,
|
||||
'private' => true,
|
||||
);
|
||||
|
||||
$info['wp-database']['fields']['database_size'] = array(
|
||||
'label' => __( 'Database size', 'sqlite-database-integration' ),
|
||||
'value' => size_format( filesize( FQDB ) ),
|
||||
);
|
||||
|
||||
unset( $info['wp-database']['fields']['extension'] );
|
||||
unset( $info['wp-database']['fields']['server_version'] );
|
||||
unset( $info['wp-database']['fields']['client_version'] );
|
||||
unset( $info['wp-database']['fields']['database_host'] );
|
||||
unset( $info['wp-database']['fields']['database_user'] );
|
||||
unset( $info['wp-database']['fields']['database_name'] );
|
||||
unset( $info['wp-database']['fields']['database_charset'] );
|
||||
unset( $info['wp-database']['fields']['database_collate'] );
|
||||
unset( $info['wp-database']['fields']['max_allowed_packet'] );
|
||||
unset( $info['wp-database']['fields']['max_connections'] );
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
add_filter( 'debug_information', 'sqlite_plugin_filter_debug_data' ); // Filter debug data in site-health screen.
|
||||
|
||||
/**
|
||||
* Filter site_status tests in site-health screen.
|
||||
*
|
||||
* When the plugin gets merged in wp-core, these should be merged in src/wp-admin/includes/class-wp-site-health.php
|
||||
*
|
||||
* @param array $tests The tests.
|
||||
* @return array
|
||||
*/
|
||||
function sqlite_plugin_filter_site_status_tests( $tests ) {
|
||||
$db_engine = defined( 'DB_ENGINE' ) && 'sqlite' === DB_ENGINE ? 'sqlite' : 'mysql';
|
||||
|
||||
if ( 'sqlite' === $db_engine ) {
|
||||
unset( $tests['direct']['utf8mb4_support'] );
|
||||
unset( $tests['direct']['sql_server'] );
|
||||
unset( $tests['direct']['persistent_object_cache'] ); // Throws an error because DB_NAME is not defined.
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
add_filter( 'site_status_tests', 'sqlite_plugin_filter_site_status_tests' );
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: SQLite Database Integration
|
||||
* Description: SQLite database driver drop-in.
|
||||
* Author: The WordPress Team
|
||||
* Version: 2.1.16
|
||||
* Requires PHP: 7.0
|
||||
* Textdomain: sqlite-database-integration
|
||||
*
|
||||
* This feature plugin allows WordPress to use SQLite instead of MySQL as its database.
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
define( 'SQLITE_MAIN_FILE', __FILE__ );
|
||||
|
||||
require_once __DIR__ . '/php-polyfills.php';
|
||||
require_once __DIR__ . '/admin-page.php';
|
||||
require_once __DIR__ . '/activate.php';
|
||||
require_once __DIR__ . '/deactivate.php';
|
||||
require_once __DIR__ . '/admin-notices.php';
|
||||
require_once __DIR__ . '/health-check.php';
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* Polyfills for php 7 & 8 functions
|
||||
*
|
||||
* @package wp-sqlite-integration
|
||||
*/
|
||||
|
||||
if ( ! function_exists( 'str_starts_with' ) ) {
|
||||
/**
|
||||
* Check if a string starts with a specific substring.
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The string to search for.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-starts-with
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function str_starts_with( string $haystack, string $needle ) {
|
||||
return empty( $needle ) || 0 === strpos( $haystack, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_contains' ) ) {
|
||||
/**
|
||||
* Check if a string contains a specific substring.
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The string to search for.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-contains
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function str_contains( string $haystack, string $needle ) {
|
||||
return empty( $needle ) || false !== strpos( $haystack, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_ends_with' ) ) {
|
||||
/**
|
||||
* Check if a string ends with a specific substring.
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The string to search for.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-ends-with
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function str_ends_with( string $haystack, string $needle ) {
|
||||
return empty( $needle ) || substr( $haystack, -strlen( $needle ) === $needle );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
=== SQLite Database Integration ===
|
||||
|
||||
Contributors: wordpressdotorg, aristath, janjakes, zieladam, berislav.grgicak, bpayton, zaerl
|
||||
Requires at least: 6.4
|
||||
Tested up to: 6.6.1
|
||||
Requires PHP: 7.0
|
||||
Stable tag: 2.1.16
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
Tags: performance, database
|
||||
|
||||
SQLite integration plugin by the WordPress Team.
|
||||
|
||||
== Description ==
|
||||
|
||||
The SQLite plugin is a community, feature plugin. The intent is to allow testing an SQLite integration with WordPress and gather feedback, with the goal of eventually landing it in WordPress core.
|
||||
|
||||
This feature plugin includes code from the PHPMyAdmin project (specifically parts of the PHPMyAdmin/sql-parser library), licensed under the GPL v2 or later. More info on the PHPMyAdmin/sql-parser library can be found on [GitHub](https://github.com/phpmyadmin/sql-parser).
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= What is the purpose of this plugin? =
|
||||
|
||||
The primary purpose of the SQLite plugin is to allow testing the use of an SQLite database, with the goal to eventually land in WordPress core.
|
||||
|
||||
You can read the original proposal on the [Make blog](https://make.wordpress.org/core/2022/09/12/lets-make-wordpress-officially-support-sqlite/), as well as the [call for testing](https://make.wordpress.org/core/2022/12/20/help-us-test-the-sqlite-implementation/) for more context and useful information.
|
||||
|
||||
= Can I use this plugin on my production site? =
|
||||
|
||||
Per the primary purpose of the plugin (see above), it can mostly be considered a beta testing plugin. To a degree, it should be okay to use it in production. However, as with every plugin, you are doing so at your own risk.
|
||||
|
||||
= Where can I submit my plugin feedback? =
|
||||
|
||||
Feedback is encouraged and much appreciated, especially since this plugin is a future WordPress core feature. If you need help with troubleshooting or have a question, suggestions, or requests, you can [submit them as an issue in the SQLite GitHub repository](https://github.com/wordpress/sqlite-database-integration/issues/new).
|
||||
|
||||
= How can I contribute to the plugin? =
|
||||
|
||||
Contributions are always welcome! Learn more about how to get involved in the [Core Performance Team Handbook](https://make.wordpress.org/performance/handbook/get-involved/).
|
||||
+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