* The class to store and manage litespeed db data.
* @subpackage LiteSpeed/src
* @author LiteSpeed Technologies <info@litespeedtech.com>
defined('WPINC') || exit();
const LOG_TAG = '[Data]';
private $_db_updater = array(
'3.5.0.3' => array('litespeed_update_3_5'),
'4.0' => array('litespeed_update_4'),
'4.1' => array('litespeed_update_4_1'),
'4.3' => array('litespeed_update_4_3'),
'4.4.4-b1' => array('litespeed_update_4_4_4'),
'5.3-a5' => array('litespeed_update_5_3'),
private $_db_site_updater = array(
// 'litespeed_update_site_2_0',
private $_url_file_types = array(
const TB_IMG_OPTM = 'litespeed_img_optm';
const TB_IMG_OPTMING = 'litespeed_img_optming'; // working table
const TB_AVATAR = 'litespeed_avatar';
const TB_CRAWLER = 'litespeed_crawler';
const TB_CRAWLER_BLACKLIST = 'litespeed_crawler_blacklist';
const TB_URL = 'litespeed_url';
const TB_URL_FILE = 'litespeed_url_file';
public function __construct()
* Correct table existence
* Call when activate -> update_confs()
* Call when update_confs()
public function correct_tb_existence()
if ($this->conf(Base::O_DISCUSS_AVATAR_CACHE)) {
$this->tb_create('avatar');
if ($this->conf(Base::O_CRAWLER)) {
$this->tb_create('crawler');
$this->tb_create('crawler_blacklist');
$this->tb_create('url_file');
// Image optm is a bit different. Only trigger creation when sending requests. Drop when destroying.
* Upgrade conf to latest format version from previous versions
public function conf_upgrade($ver)
// Skip count check if `Use Primary Site Configurations` is on
// Deprecated since v3.0 as network primary site didn't override the subsites conf yet
// if ( ! is_main_site() && ! empty ( $this->_site_options[ self::NETWORK_O_USE_PRIMARY ] ) ) {
if ($this->_get_upgrade_lock()) {
$this->_set_upgrade_lock(true);
require_once LSCWP_DIR . 'src/data.upgrade.func.php';
if ($this->conf(Base::O_DEBUG)) {
$this->cls('Debug2')->init();
foreach ($this->_db_updater as $k => $v) {
if (version_compare($ver, $k, '<')) {
Debug2::debug("[Data] Updating [ori_v] $ver \t[to] $k \t[func] $v2");
$this->cls('Conf')->load_options();
$this->correct_tb_existence();
$this->cls('Activation')->update_files();
// Update version to latest
Conf::delete_option(Base::_VER);
Conf::add_option(Base::_VER, Core::VER);
Debug2::debug('[Data] Updated version to ' . Core::VER);
$this->_set_upgrade_lock(false);
!defined('LSWCP_EMPTYCACHE') && define('LSWCP_EMPTYCACHE', true); // clear all sites caches
Cloud::version_check('upgrade');
* Upgrade site conf to latest format version from previous versions
public function conf_site_upgrade($ver)
if ($this->_get_upgrade_lock()) {
$this->_set_upgrade_lock(true);
require_once LSCWP_DIR . 'src/data.upgrade.func.php';
foreach ($this->_db_site_updater as $k => $v) {
if (version_compare($ver, $k, '<')) {
Debug2::debug("[Data] Updating site [ori_v] $ver \t[to] $k \t[func] $v2");
$this->cls('Conf')->load_site_options();
Conf::delete_site_option(Base::_VER);
Conf::add_site_option(Base::_VER, Core::VER);
Debug2::debug('[Data] Updated site_version to ' . Core::VER);
$this->_set_upgrade_lock(false);
!defined('LSWCP_EMPTYCACHE') && define('LSWCP_EMPTYCACHE', true); // clear all sites caches
* Check if upgrade script is running or not
private function _get_upgrade_lock()
$is_upgrading = get_option('litespeed.data.upgrading');
$this->_set_upgrade_lock(false); // set option value to existed to avoid repeated db query next time
if ($is_upgrading && time() - $is_upgrading < 3600) {
* Show the upgrading banner if upgrade script is running
public function check_upgrading_msg()
$is_upgrading = $this->_get_upgrade_lock();
__('The database has been upgrading in the background since %s. This message will disappear once upgrade is complete.', 'litespeed-cache'),
'<code>' . Utility::readable_time($is_upgrading) . '</code>'
* Set lock for upgrade process
private function _set_upgrade_lock($lock)
update_option('litespeed.data.upgrading', -1);
update_option('litespeed.data.upgrading', time());
* Upgrade the conf to v3.0 from previous v3.0- data
public function try_upgrade_conf_3_0()
$previous_options = get_option('litespeed-cache-conf');
if (!$previous_options) {
Cloud::version_check('new');
$ver = $previous_options['version'];
!defined('LSCWP_CUR_V') && define('LSCWP_CUR_V', $ver);
if ($this->conf(Base::O_DEBUG)) {
$this->cls('Debug2')->init();
Debug2::debug('[Data] Upgrading previous settings [from] ' . $ver . ' [to] v3.0');
if ($this->_get_upgrade_lock()) {
$this->_set_upgrade_lock(true);
require_once LSCWP_DIR . 'src/data.upgrade.func.php';
// Here inside will update the version to v3.0
litespeed_update_3_0($ver);
$this->_set_upgrade_lock(false);
Debug2::debug('[Data] Upgraded to v3.0');
// Upgrade from 3.0 to latest version
$this->conf_upgrade($ver);
$this->cls('Conf')->load_options();
$this->correct_tb_existence();
!defined('LSWCP_EMPTYCACHE') && define('LSWCP_EMPTYCACHE', true); // clear all sites caches
Cloud::version_check('upgrade');
return $wpdb->prefix . self::TB_IMG_OPTM;
return $wpdb->prefix . self::TB_IMG_OPTMING;
return $wpdb->prefix . self::TB_AVATAR;
return $wpdb->prefix . self::TB_CRAWLER;
case 'crawler_blacklist':
return $wpdb->prefix . self::TB_CRAWLER_BLACKLIST;
return $wpdb->prefix . self::TB_URL;
return $wpdb->prefix . self::TB_URL_FILE;
* Check if one table exists or not
public function tb_exist($tb)
return $wpdb->get_var("SHOW TABLES LIKE '" . $this->tb($tb) . "'");
* Get data structure of one table
private function _tb_structure($tb)
return File::read(LSCWP_DIR . 'src/data_structure/' . $tb . '.sql');
* Create img optm table and sync data from wp_postmeta
public function tb_create($tb)
Debug2::debug2('[Data] Checking table ' . $tb);
// Check if table exists first
if ($this->tb_exist($tb)) {
Debug2::debug2('[Data] Existed');
Debug2::debug('[Data] Creating ' . $tb);
'CREATE TABLE IF NOT EXISTS `%1$s` (' . $this->_tb_structure($tb) . ') %2$s;',
$wpdb->get_charset_collate() // 'DEFAULT CHARSET=utf8'
$res = $wpdb->query($sql);
Debug2::debug('[Data] Warning! Creating table failed!', $sql);
Admin_Display::error(Error::msg('failed_tb_creation', array('<code>' . $tb . '</code>', '<code>' . $sql . '</code>')));
public function tb_del($tb)
if (!$this->tb_exist($tb)) {
Debug2::debug('[Data] Deleting table ' . $tb);
$q = 'DROP TABLE IF EXISTS ' . $this->tb($tb);
public function tables_del()
$this->tb_del('crawler');
$this->tb_del('crawler_blacklist');
$this->tb_del('url_file');
// Deleting img_optm only can be done when destroy all optm images
* Keep table but clear all data
public function table_truncate($tb)
$q = 'TRUNCATE TABLE ' . $this->tb($tb);
* Clean certain type of url_file
public function url_file_clean($file_type)
if (!$this->tb_exist('url_file')) {
$type = $this->_url_file_types[$file_type];
$q = 'DELETE FROM ' . $this->tb('url_file') . ' WHERE `type` = %d';
$wpdb->query($wpdb->prepare($q, $type));
// Added to cleanup url table. See issue: https://wordpress.org/support/topic/wp_litespeed_url-1-1-gb-in-db-huge-big/
'` AS f ON d.`id` = f.`url_id`
WHERE f.`url_id` IS NULL'
* Generate filename based on URL, if content md5 existed, reuse existing file.
public function save_url($request_url, $vary, $file_type, $filecon_md5, $path, $mobile = false, $webp = false)
if (strlen($vary) > 32) {
$type = $this->_url_file_types[$file_type];
$tb_url = $this->tb('url');
$tb_url_file = $this->tb('url_file');
$q = "SELECT * FROM `$tb_url` WHERE url=%s";
$url_row = $wpdb->get_row($wpdb->prepare($q, $request_url), ARRAY_A);