diff --git a/wordpress-oceanbase-plugin/README.md b/wordpress-oceanbase-plugin/README.md index 815a0851..ce2c7669 100644 --- a/wordpress-oceanbase-plugin/README.md +++ b/wordpress-oceanbase-plugin/README.md @@ -33,4 +33,4 @@ We welcome issues and pull requests to improve this project. For questions or su ## 📄 License -This project is licensed under the [Apache License 2.0](https://github.com/oceanbase/ecology-plugins/LICENSE). \ No newline at end of file +This project is licensed under the [Apache License 2.0](https://github.com/oceanbase/ecology-plugins/blob/main/wordpress-oceanbase-plugin/LICENSE). \ No newline at end of file diff --git a/wordpress-oceanbase-plugin/README_CN.md b/wordpress-oceanbase-plugin/README_CN.md index 32b0ac90..42c99ca6 100644 --- a/wordpress-oceanbase-plugin/README_CN.md +++ b/wordpress-oceanbase-plugin/README_CN.md @@ -46,4 +46,4 @@ OceanBase 当前不支持在单条 SQL 查询中对同一张表使用多个别 ## 📄 授权协议 -本项目采用 [Apache License 2.0](https://github.com/oceanbase/ecology-plugins/LICENSE) 协议开源。 \ No newline at end of file +本项目采用 [Apache License 2.0](https://github.com/oceanbase/ecology-plugins/blob/main/wordpress-oceanbase-plugin/LICENSE) 协议开源。 \ No newline at end of file diff --git a/wordpress-oceanbase-plugin/oceanBase-delete-expired-transients.php b/wordpress-oceanbase-plugin/oceanBase-delete-expired-transients.php deleted file mode 100644 index 83ab8280..00000000 --- a/wordpress-oceanbase-plugin/oceanBase-delete-expired-transients.php +++ /dev/null @@ -1,110 +0,0 @@ -options, '/') . '\s+\w+,\s+' . preg_quote($wpdb->options, '/') . '\s+\w+\s+WHERE/i', $query)) { - // Modify the query to select option_id - $modified_query = preg_replace('/DELETE\s+\w+,\s+\w+\s+FROM/i', "SELECT a.option_id AS a_option_id, b.option_id AS b_option_id FROM", $query); - - // Execute the modified SELECT query (wrapped with prepare per review guidance) - if (preg_match('/%[dsf]/', $modified_query)) { - // If placeholders are included, the sql precheck fails - $results = []; - } else { - // There are no placeholders. Execute directly - // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is constructed from original WordPress query and sanitized - $results = $wpdb->get_results($modified_query, ARRAY_A); - } - - // Initialize an array to store all the ID objects - $ids_to_delete = array(); - - // Iterate over the results, combining a.option_id and b.option_id into $ids_to_delete - foreach ($results as $row) { - $ids_to_delete[] = intval($row['a_option_id']); - $ids_to_delete[] = intval($row['b_option_id']); - } - - if (!empty($ids_to_delete)) { - // Construct placeholders for IN clause and execute with prepare to avoid SQL injection - $placeholders = implode(',', array_fill(0, count($ids_to_delete), '%d')); - $final_delete_query = $wpdb->prepare( - "DELETE FROM {$wpdb->options} WHERE option_id IN ($placeholders)", - $ids_to_delete - ); - - return $final_delete_query; - } - - // Return an empty string to prevent the original DELETE query from executing - return ''; - } - - // Check for DELETE query targeting wp_sitemeta - if (preg_match('/DELETE\s+\w+,\s+\w+\s+FROM\s+' . preg_quote($wpdb->sitemeta, '/') . '\s+\w+,\s+' . preg_quote($wpdb->sitemeta, '/') . '\s+\w+\s+WHERE/i', $query)) { - // Modify the query to select meta_id - $modified_query = preg_replace('/DELETE\s+\w+,\s+\w+\s+FROM/i', "SELECT a.meta_id AS a_meta_id, b.meta_id AS b_meta_id FROM", $query); - - // Execute the modified SELECT query (wrapped with prepare per review guidance) - if (preg_match('/%[dsf]/', $modified_query)) { - // If placeholders are included, the sql precheck fails - $results = []; - } else { - // There are no placeholders. Execute directly - // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is constructed from original WordPress query and sanitized - $results = $wpdb->get_results($modified_query, ARRAY_A); - } - // Initialize an array to store all the ID objects - $ids_to_delete = array(); - - // Iterate over the results, combining a.option_id and b.option_id into $ids_to_delete - foreach ($results as $row) { - $ids_to_delete[] = intval($row['a_meta_id']); - $ids_to_delete[] = intval($row['b_meta_id']); - } - - if (!empty($ids_to_delete)) { - // Construct placeholders for IN clause and execute with prepare to avoid SQL injection - $placeholders = implode(',', array_fill(0, count($ids_to_delete), '%d')); - $final_delete_query = $wpdb->prepare( - "DELETE FROM {$wpdb->sitemeta} WHERE meta_id IN ($placeholders)", - $ids_to_delete - ); - - return $final_delete_query; - } - - // Return an empty string to prevent the original DELETE query from executing - return ''; - } - - // Return the original query if no changes are needed - return $query; - } -} - -// Initialize the plugin -new OceanBase_Delete_Expired_Transients(); \ No newline at end of file diff --git a/wordpress-oceanbase-plugin/oceanbase-compatibility.php b/wordpress-oceanbase-plugin/oceanbase-compatibility.php new file mode 100644 index 00000000..34eef4fb --- /dev/null +++ b/wordpress-oceanbase-plugin/oceanbase-compatibility.php @@ -0,0 +1,134 @@ +options) !== false) ? $wpdb->options : $wpdb->sitemeta; + $column = (strpos($original_query, $wpdb->options) !== false) ? "option_id" : "meta_id"; + return $wpdb->prepare( + "DELETE FROM $table WHERE $column IN ($placeholders)", + $ids_to_delete + ); + } + + return ''; + } + + public function modify_delete_expired_transients($query) { + global $wpdb; + + $regex_options = '/^DELETE\s+\w+,\s+\w+\s+FROM\s+' . preg_quote($wpdb->options, '/') . '\s+(\w+),\s+' . preg_quote($wpdb->options, '/') . '\s+(\w+)\s+WHERE\s+' . + '.*?a\.option_name\s+LIKE\s+\'(.+?)\'.*?' . + '.*?AND\s+a\.option_name\s+NOT\s+LIKE\s+\'(.+?)\'.*?' . + '.*?AND\s+b\.option_value\s*<\s*(\d+)\s*$/is'; + + $regex_sitemeta = ''; + if (is_string($wpdb->sitemeta)) { + $regex_sitemeta = '/^DELETE\s+\w+,\s+\w+\s+FROM\s+' . preg_quote($wpdb->sitemeta, '/') . '\s+(\w+),\s+' . preg_quote($wpdb->sitemeta, '/') . '\s+(\w+)\s+WHERE\s+' . + '.*?a\.meta_key\s+LIKE\s+\'(.+?)\'.*?' . + '.*?AND\s+a\.meta_key\s+NOT\s+LIKE\s+\'(.+?)\'.*?' . + '.*?AND\s+b\.meta_value\s*<\s*(\d+)\s*$/is'; + } + + if ($regex_sitemeta && preg_match($regex_sitemeta, $query, $matches)) { + if (!isset($matches[3], $matches[4], $matches[5])) { + return $query; + } + $like_pattern = stripslashes($matches[3]); + $not_like_pattern = stripslashes($matches[4]); + $timeout_value = intval($matches[5]); + + $clean_pattern = str_replace('\\', '', $like_pattern); + if (strpos($clean_pattern, needle: '_site_transient_') !== false) { + + $prepared_query = $wpdb->prepare( + "SELECT a.meta_id AS a_id, b.meta_id AS b_id + FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b + WHERE a.meta_key LIKE %s + AND a.meta_key NOT LIKE %s + AND b.meta_key = CONCAT('_site_transient_timeout_', SUBSTRING(a.meta_key, 17)) + AND b.meta_value < %d", + $like_pattern, $not_like_pattern, $timeout_value + ); + }else{ + return $query; + } + $results = $wpdb->get_results($prepared_query, ARRAY_A); + return $this->build_delete_query($query, $results); + } + + + if (preg_match($regex_options, $query, $matches)) { + + if (!isset($matches[3], $matches[4], $matches[5])) { + return $query; + } + $like_pattern = stripslashes($matches[3]); + $not_like_pattern = stripslashes($matches[4]); + $timeout_value = intval($matches[5]); + + $clean_pattern = str_replace('\\', '', $like_pattern); + if (strpos($clean_pattern, needle: '_site_transient_') !== false) { + + $prepared_query = $wpdb->prepare( + "SELECT a.option_id AS a_id, b.option_id AS b_id + FROM {$wpdb->options} a, {$wpdb->options} b + WHERE a.option_name LIKE %s + AND a.option_name NOT LIKE %s + AND b.option_name = CONCAT('_site_transient_timeout_', SUBSTRING(a.option_name, 17)) + AND b.option_value < %d", + $like_pattern, $not_like_pattern, $timeout_value + ); + }elseif (strpos($clean_pattern, needle: '_transient_') !== false) { + + $prepared_query = $wpdb->prepare( + "SELECT a.option_id AS a_id, b.option_id AS b_id + FROM {$wpdb->options} a, {$wpdb->options} b + WHERE a.option_name LIKE %s + AND a.option_name NOT LIKE %s + AND b.option_name = CONCAT('_transient_timeout_', SUBSTRING(a.option_name, 12)) + AND b.option_value < %d", + $like_pattern, $not_like_pattern, $timeout_value + ); + } else { + return $query; + } + + $results = $wpdb->get_results($prepared_query, ARRAY_A); + return $this->build_delete_query($query, $results); + } + return $query; + + } +} + +// Initialize the plugin +new OceanBase_Delete_Expired_Transients(); \ No newline at end of file