File "WPDA_Global_Search.php"
Full Path: /home/vantageo/public_html/cache/cache/cache/cache/cache/cache/cache/.wp-cli/wp-content/plugins/wp-data-access/WPDataAccess/Global_Search/WPDA_Global_Search.php
File size: 32 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace WPDataAccess\Global_Search {
use WPDataAccess\Connection\WPDADB;
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
use WPDataAccess\WPDA;
class WPDA_Global_Search {
const NONCE_SEED = 'wpda-global-search-and-replace-';
protected $databases = array();
public function __construct() {
$dbs = WPDA_Dictionary_Lists::get_db_schemas();
foreach ( $dbs as $db ) {
$this->databases[] = $db['schema_name'];
}
}
public function show() {
$this->css();
$this->js();
$esc_attr = 'esc_attr';
?>
<div class="wrap">
<h1 class="wp-heading-inline">
<span style="vertical-align: text-top">Search & Replace</span>
</h1>
<div id="tabs">
<ul>
<li><a href="#tabs-1">Search</a></li>
<li><a href="#tabs-2">Replace</a></li>
</ul>
<div id="tabs-1">
<div>
<input type="text" id="searchbox" placeholder="Search for..." onblur="jQuery('#replace_searchbox').val(jQuery(this).val())" />
<label>
<input type="checkbox" id="searchbox-case" onblur="jQuery('#replace_searchbox-case').prop('checked', jQuery(this).is(':checked'))" />Case-sensitive
</label>
<button type="button" class="button button-primary" onclick="startSearch()">SEARCH</button>
</div>
</div>
<div id="tabs-2">
<div>
<label for="replace_searchbox">
Search
</label>
<input type="text" id="replace_searchbox" placeholder="Search for..." onblur="jQuery('#searchbox').val(jQuery(this).val())" />
<label>
<input type="checkbox" id="replace_searchbox-case" onblur="jQuery('#searchbox-case').prop('checked', jQuery(this).is(':checked'))" />Case-sensitive
</label>
</div>
<div>
<label for="replace_replacebox">
Replace
</label>
<input type="text" id="replace_replacebox" placeholder="Replace with..." />
<button type="button" class="button button-primary" onclick="startReplace()">SEARCH</button>
</div>
</div>
</div>
<fieldset class="wpda_fieldset">
<legend>
Select databases and tables
</legend>
<div id="selectionFrame">
<div id="selectionDatabases">
<div class="selectionFrameHeader">
Available databases
<i class="fas fa-database"></i>
</div>
<div class="selectionFrameBody">
<?php
global $wpdb;
foreach ( $this->databases as $database ) {
$dbname = $database === $wpdb->dbname ? "WordPress database ({$esc_attr( $database )})" : esc_attr( $database );
$dbs = <<< EOL
<div class="selectionFrameBodyElement"
onclick="selectSchema('{$esc_attr( $database )}')"
id="{$esc_attr( $database )}"
>
<input type="checkbox" id="chk_{$esc_attr( $database )}" />
{$dbname}
</div>
EOL;
echo $dbs;
}
?>
</div>
<div class="selectionFrameFooter">
<i class="fas fa-info-circle"></i> Click on a database name to select tables
</div>
</div>
<div id="selectionTables">
<div class="selectionFrameHeader">
<span>
<label>
<input type="checkbox"
title="Select all/Unselect all"
class="wpda_tooltip"
id="toggleAllTables"
onclick="toggleAllTables()"
/>
Available tables
</label>
<label style="padding-left:10px;display:none;" id="showWordPressTables">
<input type="checkbox"
title="Select all/Unselect all"
class="wpda_tooltip"
id="toggleWordPressTables"
onclick="toggleWordPressTables()"
/>
WordPress tables
</label>
</span>
<i class="fas fa-table"></i>
</div>
<div class="selectionFrameBody">
<div class="selectionFrameBodySpinner">
<div>
<i class="fa fa-spinner fa-spin"></i>
<br/><br/>
<span class="blink_me">
Loading tables...
</span>
</div>
</div>
</div>
<div class="selectionFrameFooter">
<i class="fas fa-info-circle"></i> Select tables to be searched
</div>
</div>
</div>
</fieldset>
<fieldset id="wpda_searchresults_panel" class="wpda_fieldset" style="display:none">
<legend>
Search results
</legend>
<div id="wpda_searchresults"></div>
<div class="selectionFrameFooter">
<i class="fas fa-info-circle"></i> <span id="totalMatches">0</span> total rows
</div>
</fieldset>
</div>
<?php
}
private function css() {
?>
<style>
:root {
--height: 30vh;
}
fieldset {
margin-top: 10px;
}
#searchbox {
width: 100%;
}
#selectionFrame {
position: relative;
height: calc(var(--height) + 115px);
overflow: hidden;
}
#selectionDatabases,
#selectionTables {
position: absolute;
top: 0;
width: calc(50% - 5px);
}
#selectionTables {
right: 0;
}
.selectionFrameHeader {
position: relative;
padding: 18px 16px;
background-color: #acacac;
font-weight: bold;
border-radius: 5px 5px 0 0;
}
.selectionFrameHeader i.fas {
display: inline-block;
position: absolute;
top: 22px;
right: 20px;
}
.selectionFrameBody {
height: var(--height);
overflow-y: scroll;
border-left: 1px solid #acacac;
border-right: 1px solid #acacac;
}
.selectionFrameBody > div:nth-child(even) {
background-color: #fff;
}
.selectionFrameBody > div {
padding: 18px 16px;
}
.selectionFrameBody > div:not(.selectionFrameBodySpinner):hover {
background-color: rgba(255, 255, 0, 0.5);
font-weight: bold;
}
.selectionFrameBodyElement {
cursor: pointer;
}
.selectionFrameFooter {
padding: 18px 16px;
background-color: #acacac;
border-radius: 0 0 5px 5px;
}
.selectionFrameFooter i.fas {
margin-right: 10px;
}
.databaseSelected {
background-color: rgba(255, 255, 0) !important;
font-weight: bold;
}
.selectionFrameBodySpinner {
height: calc(var(--height) - 55px);
display: flex;
justify-content: center;
align-items: center;
}
.selectionFrameBodySpinner > div {
text-align: center;
}
.selectionFrameBodySpinner i {
font-size: 300%;
}
.blink_me {
animation: blinker 1s linear infinite;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
#wpda_searchstart {
text-align: end;
margin-top: 2px;
}
#wpda_searchresults .wpdaSchemaOutput {
background-color: #acacac;
padding: 18px 16px;
}
#wpda_searchresults .wpdaTableOutput {
padding: 18px 16px 18px 36px;
border-left: 1px solid #acacac;
border-right: 1px solid #acacac;
display: flex;
justify-content: space-between;
align-items: center;
}
#wpda_searchresults .wpdaTableOutput:nth-child(even) {
background-color: #fff;
}
#wpda_searchresults .wpdaSchemaOutput:first-child {
border-radius: 5px 5px 0 0;
position: relative;
}
#wpda_searchresults .wpdaTableOutput span {
line-height: 30px;
}
#wpda_searchresults .wpdaTableOutput button {
line-height: 28px;
margin-left: 5px;
}
#wpda_searchresults .wpdaSchemaOutput i.fas,
#wpda_searchresults .wpdaTableOutput i.fas {
margin-right: 10px;
}
#wpda_searchresults .wpdaTableOutput:hover {
background-color: rgba(255, 255, 0, 0.5);
font-weight: bold;
}
#wpda_searchresults .wpdaTableOutput a {
text-decoration: none;
}
.match {
display: inline-block;
width: 5px;
height: 0;
border-right: 15px solid transparent;
vertical-align: sub;
}
.matches {
border-top: 8px solid transparent;
border-right: 15px solid #555;
border-bottom: 8px solid transparent;
}
.disableLink {
color: unset;
pointer-events: none;
}
#wpda_searchresults .wpdaSchemaOutput label {
line-height: 30px;
vertical-align: initial;
position: absolute;
right: 12px;
top: 13px;
}
.communication_error {
cursor: pointer;
}
#tabs {
padding: 0;
background: none;
border-width: 0;
}
#tabs .ui-tabs-nav {
padding-left: 0;
background: transparent;
border-width: 0 0 1px 0;
border-color: #ccd0d4;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
#tabs .ui-tabs-panel {
background: #fff;
border-width: 0 1px 1px 1px;
border-color: #ccd0d4;
}
.ui-tabs-anchor {
font-weight: bold;
}
#tabs-1,
#tabs-2 {
margin: 0;
padding: 10px;
}
#tabs-1 label {
text-align: center;
}
#tabs-1 > div {
display: grid;
grid-template-columns: auto 120px 110px;
grid-column-gap: 5px;
align-items: center;
}
#tabs-2 > div:first-child {
display: grid;
grid-template-columns: 65px auto 120px;
align-items: center;
margin-bottom: 5px;
}
#tabs-2 > div:last-child {
display: grid;
grid-template-columns: 65px auto 110px;
align-items: center;
}
#tabs-2 > div:last-child input[type=text] {
margin-right: 10px;
}
#tabs-2 label {
padding-left: 10px;
}
.wpda_tooltip_sar_css {
max-width: 600px;
background: black;
color: white;
border: 2px solid white;
font: bold 10px "Helvetica Neue", Sans-Serif;
box-shadow: 0 0 7px black;
}
</style>
<?php
}
private function js() {
global $wpdb;
$wp_database = $wpdb->dbname;
?>
<script>
var wpdaDatabases = <?php echo json_encode( $this->databases ); ?>;
var wpDatabase = "<?php echo esc_attr( $wp_database ); ?>";
var wpdaTables = [];
var wpTables = <?php echo json_encode( array_keys( WPDA::get_wp_tables() ) ); ?>;
var schemasProcessed = 0;
var totalMatches = 0;
var replaceAllSelectedTables = false;
function updateTotalMatches(n) {
totalMatches += n;
jQuery("#totalMatches").html(totalMatches);
}
function showTableResults(schemaName, tableName, rows) {
jQuery(`#result_${schemaName}_${tableName}`).html(rows + " rows");
jQuery(`#result_${schemaName}_${tableName}`).closest("a").find(".linkSpinner").hide();
if (parseInt(rows)!==NaN && parseInt(rows)>0) {
jQuery(`#result_${schemaName}_${tableName}`).closest("div").find(".match").addClass("matches");
updateTotalMatches(parseInt(rows));
jQuery(`#result_${schemaName}_${tableName}`).closest("a").removeClass("disableLink");
jQuery(`#view_${schemaName}_${tableName}`).closest("span").find("button").show();
}
}
function submitForm(schemaName, tableName) {
if (jQuery("#matchesInNewTab").is(":checked")) {
jQuery(`#view_${schemaName}_${tableName}`).attr("target", "_blank");
} else {
jQuery(`#view_${schemaName}_${tableName}`).removeAttr("target");
}
jQuery(`#view_${schemaName}_${tableName}`).submit();
}
function showTableOutput(schemaName, tableName, addReplaceButtons, searchString, searchCase, replaceString) {
let button = addReplaceButtons ?
`<button type="button" class="button button-secondary replace-table-button" style="display:none" onclick="replace('${schemaName}', '${tableName}', '${searchString}', '${searchCase}', '${replaceString}')">Replace</button>` : '<span></span>';
jQuery("#wpda_searchresults").append(`
<div class="wpdaTableOutput">
<span>
<i class="fas fa-table"></i>
${tableName}
</span>
<span>
<form id="view_${schemaName}_${tableName}" action="?page=wpda" method="post" style="display:none">
<input type="hidden" name="wpdaschema_name" value="${schemaName}" />
<input type="hidden" name="table_name" value="${tableName}" />
<input type="hidden" name="wpda_s" value="${searchString}" />
<input type="hidden" name="wpda_c" value="${searchCase}" />
</form>
<a href="javascript:submitForm('${schemaName}', '${tableName}')" class="disableLink">
<span class="linkSpinner">
<i class="fa fa-spinner fa-spin"></i>
Searching...
</span>
<span id="result_${schemaName}_${tableName}"></span>
</a>
${button}
<span class="match"></span>
</span>
</div>
`);
}
function showSchemaOutput(schemaName, i, addReplaceButtons, searchString, replaceString) {
let selection = "";
let button = addReplaceButtons ?
`<button type="button" class="button button-secondary" onclick="replaceAll('${searchString}', '${replaceString}')">Replace All</button>` :
'<span style="display:inline-block;width:5px"></span>';
if (i===0) {
// Add selection to open links in new tab|window
selection = `<label>
<input type="checkbox" id="matchesInNewTab" checked />
<span>Open rows in new tab or window</span>
${button}
</label>`;
}
jQuery("#wpda_searchresults").append(`
<div class="wpdaSchemaOutput">
<i class="fas fa-database"></i>
${schemaName}
${selection}
</div>
`);
}
function replace(schemaName, tableName, searchString, searchCase, replaceString) {
if (!replaceAllSelectedTables) {
wpda_confirm("Replace?", `Replace all occurences of <strong>${searchString}</strong> with <strong>${replaceString}</strong> in table <strong>${tableName}</strong>?<br/><br/>This action cannot be undone!<br/>Are you sure you want to continue?`).then(function (a) {
if (a) {
replaceTable(schemaName, tableName, searchString, searchCase, replaceString);
}
});
} else {
replaceTable(schemaName, tableName, searchString, searchCase, replaceString);
}
}
function replaceAll(searchString, replaceString) {
wpda_confirm("Replace?",`Replace all occurences of <strong>${searchString}</strong> with <strong>${replaceString}</strong> in all selected tables?<br/><br/>This action cannot be undone!<br/>Are you sure you want to continue?`).then(function(a) {
if (a) {
replaceAllSelectedTables = true; // :-\
jQuery(".replace-table-button:visible").trigger("click", "test");
replaceAllSelectedTables = false; // :-/
}
});
}
function showError(schemaName, tableName) {
jQuery(`#result_${schemaName}_${tableName}`).html("");
jQuery(`#result_${schemaName}_${tableName}`).closest("a").find(".linkSpinner").hide();
jQuery(`#view_${schemaName}_${tableName}`).closest("span").append(`
<span class="communication_error wpda_tooltip" title="Please check the console for more information">
ERROR
<i class="fas fa-exclamation-triangle"></i>
</span>
`);
jQuery(".wpda_tooltip").tooltip();
}
function searchTable(schemaName, tableName, searchString, searchCase) {
jQuery.ajax({
method: "POST",
url: "<?php echo admin_url( 'admin-ajax.php?action=wpda_global_search' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>",
data: {
n: "<?php echo esc_attr( wp_create_nonce( self::NONCE_SEED . WPDA::get_current_user_login() ) ); ?>",
sn: schemaName,
tn: tableName,
q: searchString,
c: searchCase
}
}).done(
function(msg) {
if (msg.status==="OK") {
showTableResults(schemaName, tableName, msg.msg);
} else {
console.error("Communication error on table " + tableName + ":", msg);
showError(schemaName, tableName);
}
}
);
}
function replaceTable(schemaName, tableName, searchString, searchCase, replaceString) {
jQuery.ajax({
method: "POST",
url: "<?php echo admin_url( 'admin-ajax.php?action=wpda_global_replace' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>",
data: {
n: "<?php echo esc_attr( wp_create_nonce( self::NONCE_SEED . WPDA::get_current_user_login() ) ); ?>",
sn: schemaName,
tn: tableName,
q: searchString,
c: searchCase,
r: replaceString
}
}).done(
function(msg) {
if (msg.status==="OK") {
wpda_alert("Update results", "Updated " + msg.msg + " rows in table " + tableName + ".")
} else {
console.error("Communication error on table " + tableName + ":", msg);
showError(schemaName, tableName);
}
}
);
}
function startReplace() {
if (jQuery("#replace_searchbox").val().trim()==="") {
wpda_alert("Oops!", "Nothing to search. Please enter a search string in the search box above.");
return;
}
startSearch(true);
}
function startSearch(addReplaceButtons = false) {
if (jQuery("#searchbox").val().trim()==="") {
wpda_alert("Oops!", "Nothing to search. Please enter a search string in the search box above.");
return;
} else {
jQuery("#wpda_searchresults").empty();
totalMatches = 0;
updateTotalMatches(0);
if (jQuery("#selectionDatabases .selectionFrameBody div input[type=checkbox]:checked").length>0) {
jQuery("#wpda_searchresults_panel").show();
} else {
wpda_alert("No tables selected", "Please select one or more tables and try again.");
}
let searchString = jQuery("#searchbox").val();
let searchCase = jQuery("#searchbox-case").is(":checked");
let replaceString = jQuery("#replace_replacebox").val();
jQuery("#selectionDatabases .selectionFrameBody div input[type=checkbox]:checked").each(function (i, elem) {
schemaName = jQuery(elem).closest("div").attr("id");
showSchemaOutput(schemaName, i, addReplaceButtons, searchString, replaceString);
for (tableName in wpdaTables[schemaName]) {
if (wpdaTables[schemaName][tableName]) {
showTableOutput(schemaName, tableName, addReplaceButtons, searchString, searchCase, replaceString)
searchTable(schemaName, tableName, searchString, searchCase);
}
}
});
}
}
function toggleAllTables() {
let isChecked = jQuery("#toggleAllTables").is(":checked");
jQuery("#selectionTables .selectionFrameBody input[type=checkbox]").prop(
"checked",
isChecked
);
let schemaName = jQuery(".databaseSelected").attr("id");
for (tableName in wpdaTables[schemaName]) {
wpdaTables[schemaName][tableName] = isChecked;
}
jQuery("#chk_" + schemaName).prop(
"checked",
jQuery("#selectionTables .selectionFrameBody input[type=checkbox]:checked").length>0
);
if (!isChecked) {
jQuery("#toggleWordPressTables").prop("checked", false);
}
}
function toggleWordPressTables() {
if (jQuery("#toggleAllTables").is(":checked")) {
return; // nothing to do
}
let isChecked = jQuery("#toggleWordPressTables").is(":checked");
let jumpTo = false;
jQuery("#selectionTables .selectionFrameBody input[type=checkbox]").each(function() {
let tableName = jQuery(this).attr("id");
if (wpTables.includes(tableName)) {
wpdaTables[wpDatabase][tableName] = isChecked;
jQuery("#" + tableName).prop("checked", isChecked);
if (isChecked && !jumpTo) {
jQuery("#" + tableName).focus();
jumpTo = true;
}
}
});
jQuery("#chk_" + wpDatabase).prop(
"checked",
jQuery("#selectionTables .selectionFrameBody input[type=checkbox]:checked").length>0
);
}
function toggleTable(schemaName, tableName) {
if (event.target.type!=="checkbox") {
wpdaTables[schemaName][tableName] = !jQuery("#" + tableName).prop("checked");
jQuery("#" + tableName).prop("checked", wpdaTables[schemaName][tableName]);
} else {
wpdaTables[schemaName][tableName] = jQuery("#" + tableName).prop("checked");
}
if (wpdaTables[schemaName][tableName]) {
// At least one table selected: enable search for current database
jQuery("#chk_" + schemaName).prop("checked", true);
} else {
if (jQuery("#selectionTables .selectionFrameBody input[type=checkbox]:checked").length===0) {
// No tables selected: disable search for current database
jQuery("#chk_" + schemaName).prop("checked", false);
}
}
}
function selectSchema(schemaName) {
if (wpDatabase===schemaName) {
jQuery("#showWordPressTables").show();
} else {
jQuery("#showWordPressTables").hide();
}
jQuery("#selectionTables .selectionFrameBody").empty();
let tables = wpdaTables[schemaName];
if (tables===undefined) {
alert("No tables found for schema " + schemaName);
} else {
for (tableName in tables) {
let checked = tables[tableName] ? 'checked' : '';
let newTable = `
<div class="selectionFrameBodyElement"
onclick="toggleTable('${schemaName}', '${tableName}')"
>
<input type="checkbox" id="${tableName}" ${checked} class="selectionTable" />
${tableName}
</div>`;
jQuery("#selectionTables .selectionFrameBody").append(newTable);
}
jQuery("#selectionDatabases .databaseSelected").removeClass("databaseSelected");
jQuery("#" + schemaName).addClass("databaseSelected");
jQuery("#selectionTables .selectionFrameHeader input[type=checkbox]").prop("checked", false);
}
}
function getTables(schemaName) {
var url = location.pathname + '?action=wpda_get_tables';
var data = {
wpdaschema_name: schemaName,
wpda_wpnonce: '<?php echo esc_attr( wp_create_nonce( 'wpda-getdata-access-' . WPDA::get_current_user_login() ) ); ?>'
};
jQuery.post(
url,
data,
function (data) {
try {
let testIfJson = JSON.parse(data);
if (typeof testIfJson == "object") {
let tables = [];
jQuery.each(testIfJson, function (i, item) {
tables[item.table_name] = false;
});
wpdaTables[schemaName] = tables;
} else {
console.error("Invalid table list for database " + schemaName, testIfJson);
}
} catch {
console.error("Invalid table list for database " + schemaName, data);
} finally {
schemasProcessed++;
if (schemasProcessed===wpdaDatabases.length) {
jQuery(".selectionFrameBodySpinner").remove();
}
}
}
);
}
function getDatabases() {
for (let i=0; i<wpdaDatabases.length; i++) {
getTables(wpdaDatabases[i]);
}
}
function enableTooltip() {
jQuery(".wpda_tooltip_left").tooltip({
tooltipClass: "wpda_tooltip_dashboard",
track: true
});
jQuery(".wpda_tooltip_sar").tooltip({
tooltipClass: "wpda_tooltip_sar_css",
});
}
jQuery(function() {
jQuery("#tabs").tabs();
getDatabases();
enableTooltip();
});
</script>
<?php
}
public static function search() {
self::check_request();
$schema_name = sanitize_text_field( wp_unslash( $_POST['sn'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$table_name = sanitize_text_field( wp_unslash( $_POST['tn'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$search_value = sanitize_text_field( wp_unslash( $_POST['q'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$wpdadb = WPDADB::get_db_connection( $schema_name );
if ( null !== $wpdadb ) {
$wpdadb->suppress_errors( true );
}
// Get column info.
$wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $schema_name, $table_name );
$columns = $wpda_list_columns->get_table_columns();
if ( ! is_array( $columns ) ) {
// Table not found.
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'Internal SQL error' );
die();
}
// Determine case-sensitive search
$search_case = 'true' === $_POST['c'];
// Perform query
$result = self::execute_query( $wpdadb, $schema_name, $table_name, $columns, $search_value, $search_case, true );
// Process query results
if ( '' === $wpdadb->last_error && is_array( $result ) && count( $result ) > 0 ) {//phpcs:ignore - 8.1 proof
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'OK', $result[0][0] );
die();
}
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', $wpdadb->last_error );
die();
}
private static function execute_query( $wpdadb, $schema_name, $table_name, $columns, $search_value, $search_case, $just_count = false ) {
$query = true === $just_count ?
'select count(*) from `%1s`.`%1s`' : 'select * from `%1s`.`%1s`';
// Define query.
$query = $wpdadb->prepare(
$query,
array(
WPDA::remove_backticks( $schema_name ),
WPDA::remove_backticks( $table_name ),
)
);
// Construct where clause.
$where = WPDA::construct_where_clause(
$schema_name,
$table_name,
$columns,
$search_value,
$search_case
);
if ( trim( $where ) !== '' ) {
$query .= " where {$where} ";
}
// Perform query.
return $wpdadb->get_results( $query, ( true === $just_count ? 'ARRAY_N' : 'ARRAY_A' ) );
}
public static function replace() {
self::check_request();
if ( ! isset( $_POST['r'] ) ) {
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'Invalid arguments' );
die();
}
$schema_name = sanitize_text_field( wp_unslash( $_POST['sn'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$table_name = sanitize_text_field( wp_unslash( $_POST['tn'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$search_value = sanitize_text_field( wp_unslash( $_POST['q'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$replace_value = sanitize_text_field( wp_unslash( $_POST['r'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$wpdadb = WPDADB::get_db_connection( $schema_name );
if ( null !== $wpdadb ) {
$wpdadb->suppress_errors( true );
}
// Get column info.
$wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $schema_name, $table_name );
$columns = $wpda_list_columns->get_table_columns();
if ( ! is_array( $columns ) ) {
// Table not found.
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'Internal SQL error' );
die();
}
// Determine case-sensitive search
if ( 'true' === $_POST['c'] ) {
// Case-sensitive search and replace
// Use built-in SQL replace function
// Define query.
$query = $wpdadb->prepare(
'update `%1s`.`%1s` set ', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
array(
WPDA::remove_backticks( $schema_name ),
WPDA::remove_backticks( $table_name ),
)
);
// Add columns to be updated.
$set = '';
foreach ( $columns as $column ) {
if ( 'string' === WPDA::get_type( $column['data_type'] ) ) {
if ( '' !== $set ) {
$set .= ',';
}
$set .= $wpdadb->prepare(
" `%1s` = replace( `%1s`, '%s', '%s' ) ",
array(
WPDA::remove_backticks( $column['column_name'] ),
WPDA::remove_backticks( $column['column_name'] ),
$search_value,
$replace_value
)
);
}
}
if ( '' === $set ) {
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'No updatable columns found in this table' );
die();
}
$query .= $set;
// Construct where clause.
$where = WPDA::construct_where_clause(
$schema_name,
$table_name,
$columns,
$search_value
);
if ( trim( $where ) !== '' ) {
$query .= " where {$where} ";
}
// Perform update.
$wpdadb->get_results( $query, 'ARRAY_A' );
if ( '' === $wpdadb->last_error ) {
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'OK', $wpdadb->rows_affected );
die();
}
} else {
// Case-insensitive search and replace
// There is no standard SQL function to replace case-insensitive, so we need to implement our own solution
// Determine updatable columns
$update_columns = array();
foreach ( $columns as $column ) {
if ( 'string' === WPDA::get_type( $column['data_type'] ) ) {
$update_columns[] = $column['column_name'];
}
}
// Determine primary key for record update
$pk = $wpda_list_columns->get_table_primary_key();
$rows_affected = 0;
// Perform query
$results = self::execute_query( $wpdadb, $schema_name, $table_name, $columns, $search_value, false );
foreach ( $results as $result ) {
$update_values = array();
$pk_values = array();
foreach ( $update_columns as $update_column ) {
if ( false !== stripos( $result[ $update_column ], $search_value ) ) {
$update_values[ $update_column ] = str_ireplace( $search_value, $replace_value, $result[ $update_column ] );
foreach ( $pk as $key ) {
$pk_values[ $key ] = $result[ $key ];
}
}
}
// Update row
$wpdadb->update(
$table_name,
$update_values,
//phpcs:ignore - 8.1 proof
( is_array( $pk ) && count( $pk ) > 0 ? $pk_values : $result ) // fall back to all cols if no pk
);
$rows_affected += $wpdadb->rows_affected;
}
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'OK', $rows_affected );
die();
}
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', $wpdadb->last_error );
die();
}
private static function check_request() {
$wpnonce = isset( $_POST['n'] ) ? sanitize_text_field( wp_unslash( $_POST['n'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! wp_verify_nonce( $wpnonce, self::NONCE_SEED . WPDA::get_current_user_login() ) ) {
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'Not authorized' );
die();
}
if ( ! isset( $_POST['sn'], $_POST['tn'], $_POST['q'], $_POST['c'] ) || '' === $_POST['sn'] || '' === $_POST['tn'] ) {
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'Invalid arguments' );
die();
}
if ( '' === $_POST['q'] ) {
WPDA::sent_header( 'application/json' );
WPDA::sent_msg( 'ERROR', 'Nothing to search' );
die();
}
}
}
}