Escape queries before passing to $wpdb methods

[MAILPOET-4219]
This commit is contained in:
Sam Najian
2022-03-31 16:54:51 +02:00
committed by Veljko V
parent a8d88beec9
commit a2ab1a3cfd
6 changed files with 85 additions and 89 deletions

View File

@@ -198,13 +198,13 @@ class FirstPurchase {
private function getGuestCustomerOrderCountByEmail($customerEmail) { private function getGuestCustomerOrderCountByEmail($customerEmail) {
global $wpdb; global $wpdb;
$count = $wpdb->get_var( "SELECT COUNT(*) $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*)
FROM $wpdb->posts as posts FROM $wpdb->posts as posts
LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
WHERE meta.meta_key = '_billing_email' WHERE meta.meta_key = '_billing_email'
AND posts.post_type = 'shop_order' AND posts.post_type = 'shop_order'
AND meta_value = '" . WPFunctions::get()->escSql($customerEmail) . "' AND meta_value = %s
" ); ", $customerEmail));
return (int)$count; return (int)$count;
} }
} }

View File

@@ -15,6 +15,7 @@ use MailPoet\Util\Notices\AfterMigrationNotice;
use MailPoet\Util\ProgressBar; use MailPoet\Util\ProgressBar;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Idiorm\ORM; use MailPoetVendor\Idiorm\ORM;
use function WP_CLI\Utils\esc_like;
class MP2Migrator { class MP2Migrator {
const IMPORT_TIMEOUT_IN_SECONDS = 7200; // Timeout = 2 hours const IMPORT_TIMEOUT_IN_SECONDS = 7200; // Timeout = 2 hours
@@ -134,7 +135,7 @@ class MP2Migrator {
global $wpdb; global $wpdb;
try { try {
$sql = "SHOW TABLES LIKE '{$table}'"; $sql = $wpdb->prepare("SHOW TABLES LIKE %s", $table);
$result = $wpdb->query($sql); $result = $wpdb->query($sql);
return !empty($result); return !empty($result);
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -369,14 +370,14 @@ class MP2Migrator {
global $wpdb; global $wpdb;
$lastId = intval($this->settings->get('last_imported_list_id', 0)); $lastId = intval($this->settings->get('last_imported_list_id', 0));
$table = $this->mp2ListTable; $table = esc_sql($this->mp2ListTable);
$sql = " $sql = $wpdb->prepare("
SELECT l.list_id, l.name, l.description, l.is_enabled, l.created_at SELECT l.list_id, l.name, l.description, l.is_enabled, l.created_at
FROM `$table` l FROM `$table` l
WHERE l.list_id > '$lastId' WHERE l.list_id > %s
ORDER BY l.list_id ORDER BY l.list_id
LIMIT $limit LIMIT %d
"; ", $lastId, $limit);
$lists = $wpdb->get_results($sql, ARRAY_A); $lists = $wpdb->get_results($sql, ARRAY_A);
return $lists; return $lists;
@@ -446,7 +447,7 @@ class MP2Migrator {
global $wpdb; global $wpdb;
$customFields = []; $customFields = [];
$table = $this->mp2CustomFieldTable; $table = esc_sql($this->mp2CustomFieldTable);
$sql = " $sql = "
SELECT cf.id, cf.name, cf.type, cf.required, cf.settings SELECT cf.id, cf.name, cf.type, cf.required, cf.settings
FROM `$table` cf FROM `$table` cf
@@ -606,14 +607,14 @@ class MP2Migrator {
private function getUsers($limit) { private function getUsers($limit) {
global $wpdb; global $wpdb;
$lastId = intval($this->settings->get('last_imported_user_id', 0)); $lastId = intval($this->settings->get('last_imported_user_id', 0));
$table = $this->mp2UserTable; $table = esc_sql($this->mp2UserTable);
$sql = " $sql = $wpdb->prepare("
SELECT u.* SELECT u.*
FROM `$table` u FROM `$table` u
WHERE u.user_id > '$lastId' WHERE u.user_id > %d
ORDER BY u.user_id ORDER BY u.user_id
LIMIT $limit LIMIT %d
"; ", $lastId, $limit);
$users = $wpdb->get_results($sql, ARRAY_A); $users = $wpdb->get_results($sql, ARRAY_A);
return $users; return $users;
@@ -703,12 +704,12 @@ class MP2Migrator {
private function getUserLists($userId) { private function getUserLists($userId) {
global $wpdb; global $wpdb;
$table = $this->mp2UserListTable; $table = esc_sql($this->mp2UserListTable);
$sql = " $sql = $wpdb->prepare("
SELECT ul.list_id, ul.sub_date, ul.unsub_date SELECT ul.list_id, ul.sub_date, ul.unsub_date
FROM `$table` ul FROM `$table` ul
WHERE ul.user_id = '$userId' WHERE ul.user_id = %s
"; ", $userId);
$userLists = $wpdb->get_results($sql, ARRAY_A); $userLists = $wpdb->get_results($sql, ARRAY_A);
return $userLists; return $userLists;
@@ -853,14 +854,14 @@ class MP2Migrator {
global $wpdb; global $wpdb;
$lastId = intval($this->settings->get('last_imported_form_id', 0)); $lastId = intval($this->settings->get('last_imported_form_id', 0));
$table = $this->mp2FormTable; $table = esc_sql($this->mp2FormTable);
$sql = " $sql = $wpdb->prepare("
SELECT f.* SELECT f.*
FROM `$table` f FROM `$table` f
WHERE f.form_id > '$lastId' WHERE f.form_id > %s
ORDER BY f.form_id ORDER BY f.form_id
LIMIT $limit LIMIT %d
"; ", $lastId, $limit);
$forms = $wpdb->get_results($sql, ARRAY_A); $forms = $wpdb->get_results($sql, ARRAY_A);
return $forms; return $forms;
@@ -1117,12 +1118,12 @@ class MP2Migrator {
global $wpdb; global $wpdb;
$email = []; $email = [];
$table = $this->mp2EmailTable; $table = esc_sql($this->mp2EmailTable);
$sql = " $sql = $wpdb->prepare("
SELECT e.* SELECT e.*
FROM `$table` e FROM `$table` e
WHERE e.email_id = '$emailId' WHERE e.email_id = %s
"; ", $emailId);
$email = $wpdb->get_row($sql, ARRAY_A); $email = $wpdb->get_row($sql, ARRAY_A);
return $email; return $email;

View File

@@ -100,7 +100,7 @@ class Migrator {
$_this = $this; $_this = $this;
$dropTable = function($model) use($wpdb, $_this) { $dropTable = function($model) use($wpdb, $_this) {
$table = $_this->prefix . $model; $table = esc_sql($_this->prefix . $model);
$wpdb->query("DROP TABLE {$table}"); $wpdb->query("DROP TABLE {$table}");
}; };
@@ -642,8 +642,9 @@ class Migrator {
if (version_compare((string)$this->settings->get('db_version', '3.47.6'), '3.47.6', '>')) { if (version_compare((string)$this->settings->get('db_version', '3.47.6'), '3.47.6', '>')) {
return false; return false;
} }
$table = esc_sql("{$this->prefix}statistics_unsubscribes");
$query = " $query = "
ALTER TABLE `{$this->prefix}statistics_unsubscribes` ALTER TABLE `{$table}`
CHANGE `newsletter_id` `newsletter_id` int(11) unsigned NULL, CHANGE `newsletter_id` `newsletter_id` int(11) unsigned NULL,
CHANGE `queue_id` `queue_id` int(11) unsigned NULL; CHANGE `queue_id` `queue_id` int(11) unsigned NULL;
"; ";
@@ -665,7 +666,7 @@ class Migrator {
} }
global $wpdb; global $wpdb;
$scheduledTasksSubscribersTable = "{$this->prefix}scheduled_task_subscribers"; $scheduledTasksSubscribersTable = esc_sql("{$this->prefix}scheduled_task_subscribers");
// Remove default CURRENT_TIMESTAMP from created_at // Remove default CURRENT_TIMESTAMP from created_at
$updateCreatedAtQuery = " $updateCreatedAtQuery = "
ALTER TABLE `$scheduledTasksSubscribersTable` ALTER TABLE `$scheduledTasksSubscribersTable`
@@ -674,11 +675,11 @@ class Migrator {
$wpdb->query($updateCreatedAtQuery); $wpdb->query($updateCreatedAtQuery);
// Add updated_at column in case it doesn't exist // Add updated_at column in case it doesn't exist
$updatedAtColumnExists = $wpdb->get_results(" $updatedAtColumnExists = $wpdb->get_results($wpdb->prepare("
SELECT COLUMN_NAME SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = '$scheduledTasksSubscribersTable' AND column_name = 'updated_at'; WHERE table_name = %s AND column_name = 'updated_at';
"); ", $scheduledTasksSubscribersTable));
if (empty($updatedAtColumnExists)) { if (empty($updatedAtColumnExists)) {
$addUpdatedAtQuery = " $addUpdatedAtQuery = "
ALTER TABLE `$scheduledTasksSubscribersTable` ALTER TABLE `$scheduledTasksSubscribersTable`
@@ -698,17 +699,17 @@ class Migrator {
$dbName = Env::$dbName; $dbName = Env::$dbName;
$statisticsTables = [ $statisticsTables = [
"{$this->prefix}statistics_clicks", esc_sql("{$this->prefix}statistics_clicks"),
"{$this->prefix}statistics_opens", esc_sql("{$this->prefix}statistics_opens"),
]; ];
foreach ($statisticsTables as $statisticsTable) { foreach ($statisticsTables as $statisticsTable) {
$oldStatisticsIndexExists = $wpdb->get_results(" $oldStatisticsIndexExists = $wpdb->get_results($wpdb->prepare("
SELECT DISTINCT INDEX_NAME SELECT DISTINCT INDEX_NAME
FROM INFORMATION_SCHEMA.STATISTICS FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = '{$dbName}' WHERE TABLE_SCHEMA = %s
AND TABLE_NAME = '$statisticsTable' AND TABLE_NAME = %s
AND INDEX_NAME='newsletter_id_subscriber_id' AND INDEX_NAME='newsletter_id_subscriber_id'
"); ", $dbName, $statisticsTable));
if (!empty($oldStatisticsIndexExists)) { if (!empty($oldStatisticsIndexExists)) {
$dropIndexQuery = " $dropIndexQuery = "
ALTER TABLE `{$statisticsTable}` ALTER TABLE `{$statisticsTable}`
@@ -728,7 +729,7 @@ class Migrator {
return false; return false;
} }
$dynamicSegmentFiltersTable = "{$this->prefix}dynamic_segment_filters"; $dynamicSegmentFiltersTable = esc_sql("{$this->prefix}dynamic_segment_filters");
$dynamicSegmentFilters = $wpdb->get_results(" $dynamicSegmentFilters = $wpdb->get_results("
SELECT id, filter_data, filter_type, `action` SELECT id, filter_data, filter_type, `action`
FROM {$dynamicSegmentFiltersTable} FROM {$dynamicSegmentFiltersTable}
@@ -758,7 +759,7 @@ class Migrator {
return false; return false;
} }
$dynamicSegmentFiltersTable = "{$this->prefix}dynamic_segment_filters"; $dynamicSegmentFiltersTable = esc_sql("{$this->prefix}dynamic_segment_filters");
$filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE; $filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE;
$action = WooCommerceProduct::ACTION_PRODUCT; $action = WooCommerceProduct::ACTION_PRODUCT;
$dynamicSegmentFilters = $wpdb->get_results(" $dynamicSegmentFilters = $wpdb->get_results("
@@ -798,15 +799,15 @@ class Migrator {
return false; return false;
} }
$dynamicSegmentFiltersTable = "{$this->prefix}dynamic_segment_filters"; $dynamicSegmentFiltersTable = esc_sql("{$this->prefix}dynamic_segment_filters");
$filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE; $filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE;
$action = WooCommerceCategory::ACTION_CATEGORY; $action = WooCommerceCategory::ACTION_CATEGORY;
$dynamicSegmentFilters = $wpdb->get_results(" $dynamicSegmentFilters = $wpdb->get_results($wpdb->prepare("
SELECT `id`, `filter_data`, `filter_type`, `action` SELECT `id`, `filter_data`, `filter_type`, `action`
FROM {$dynamicSegmentFiltersTable} FROM {$dynamicSegmentFiltersTable}
WHERE `filter_type` = '{$filterType}' WHERE `filter_type` = %s
AND `action` = '{$action}' AND `action` = %s
", ARRAY_A); ", $filterType, $action), ARRAY_A);
foreach ($dynamicSegmentFilters as $dynamicSegmentFilter) { foreach ($dynamicSegmentFilters as $dynamicSegmentFilter) {
$filterData = unserialize($dynamicSegmentFilter['filter_data']); $filterData = unserialize($dynamicSegmentFilter['filter_data']);
@@ -838,15 +839,15 @@ class Migrator {
return false; return false;
} }
$dynamicSegmentFiltersTable = "{$this->prefix}dynamic_segment_filters"; $dynamicSegmentFiltersTable = esc_sql("{$this->prefix}dynamic_segment_filters");
$filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION; $filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION;
$action = WooCommerceSubscription::ACTION_HAS_ACTIVE; $action = WooCommerceSubscription::ACTION_HAS_ACTIVE;
$dynamicSegmentFilters = $wpdb->get_results(" $dynamicSegmentFilters = $wpdb->get_results($wpdb->prepare("
SELECT `id`, `filter_data`, `filter_type`, `action` SELECT `id`, `filter_data`, `filter_type`, `action`
FROM {$dynamicSegmentFiltersTable} FROM {$dynamicSegmentFiltersTable}
WHERE `filter_type` = '{$filterType}' WHERE `filter_type` = %s
AND `action` = '{$action}' AND `action` = %s
", ARRAY_A); ", $filterType, $action), ARRAY_A);
foreach ($dynamicSegmentFilters as $dynamicSegmentFilter) { foreach ($dynamicSegmentFilters as $dynamicSegmentFilter) {
$filterData = unserialize($dynamicSegmentFilter['filter_data']); $filterData = unserialize($dynamicSegmentFilter['filter_data']);
@@ -877,7 +878,7 @@ class Migrator {
return false; return false;
} }
$dynamicSegmentFiltersTable = "{$this->prefix}dynamic_segment_filters"; $dynamicSegmentFiltersTable = esc_sql("{$this->prefix}dynamic_segment_filters");
$filterType = DynamicSegmentFilterData::TYPE_EMAIL; $filterType = DynamicSegmentFilterData::TYPE_EMAIL;
$dynamicSegmentFilters = $wpdb->get_results(" $dynamicSegmentFilters = $wpdb->get_results("
SELECT `id`, `filter_data`, `filter_type`, `action` SELECT `id`, `filter_data`, `filter_type`, `action`

View File

@@ -530,17 +530,17 @@ class Populator {
} }
} }
private function rowExists($table, $columns) { private function rowExists(string $tableName, array $columns): bool {
global $wpdb; global $wpdb;
$conditions = array_map(function($key) { $conditions = array_map(function($key) use ($columns) {
return $key . '=%s'; return "$key='{$columns[$key]}'";
}, array_keys($columns)); }, array_keys($columns));
return $wpdb->get_var($wpdb->prepare( $table = esc_sql($tableName);
"SELECT COUNT(*) FROM $table WHERE " . implode(' AND ', $conditions), return $wpdb->get_var(
array_values($columns) "SELECT COUNT(*) FROM $table WHERE " . implode(' AND ', $conditions)
)) > 0; ) > 0;
} }
private function insertRow($table, $row) { private function insertRow($table, $row) {
@@ -575,7 +575,6 @@ class Populator {
$conditions = implode(' AND ', $conditions); $conditions = implode(' AND ', $conditions);
$sql = "DELETE FROM `$table` WHERE $conditions";
return $wpdb->query( return $wpdb->query(
$wpdb->prepare( $wpdb->prepare(
"DELETE t1 FROM $table t1, $table t2 WHERE t1.id < t2.id AND $conditions", "DELETE t1 FROM $table t1, $table t2 WHERE t1.id < t2.id AND $conditions",
@@ -614,8 +613,7 @@ class Populator {
} }
$tables = [ScheduledTask::$_table, SendingQueue::$_table]; $tables = [ScheduledTask::$_table, SendingQueue::$_table];
foreach ($tables as $table) { foreach ($tables as $table) {
$query = "UPDATE `%s` SET meta = NULL WHERE meta = 'null'"; $wpdb->query("UPDATE `$table` SET meta = NULL WHERE meta = 'null'");
$wpdb->query(sprintf($query, $table));
} }
return true; return true;
} }
@@ -652,12 +650,12 @@ class Populator {
if (version_compare((string)$this->settings->get('db_version', '3.42.1'), '3.42.0', '>')) { if (version_compare((string)$this->settings->get('db_version', '3.42.1'), '3.42.0', '>')) {
return false; return false;
} }
$query = "UPDATE `%s` SET last_subscribed_at = GREATEST(COALESCE(confirmed_at, 0), COALESCE(created_at, 0)) WHERE status != '%s' AND last_subscribed_at IS NULL;"; $table = esc_sql(Subscriber::$_table);
$wpdb->query(sprintf( $query = $wpdb->prepare(
$query, "UPDATE `{$table}` SET last_subscribed_at = GREATEST(COALESCE(confirmed_at, 0), COALESCE(created_at, 0)) WHERE status != %s AND last_subscribed_at IS NULL;",
Subscriber::$_table,
Subscriber::STATUS_UNCONFIRMED Subscriber::STATUS_UNCONFIRMED
)); );
$wpdb->query($query);
return true; return true;
} }
@@ -886,19 +884,14 @@ class Populator {
) )
); );
if ($premiumTableExists) { if ($premiumTableExists) {
$table = esc_sql(Newsletter::$_table);
$query = " $query = "
UPDATE UPDATE
`%s` as n `{$table}` as n
JOIN %s as ped ON n.id=ped.newsletter_id JOIN `$premiumTableName` as ped ON n.id=ped.newsletter_id
SET n.ga_campaign = ped.ga_campaign SET n.ga_campaign = ped.ga_campaign
"; ";
$wpdb->query( $wpdb->query($query);
sprintf(
$query,
Newsletter::$_table,
$premiumTableName
)
);
} }
return true; return true;
} }

View File

@@ -85,7 +85,7 @@ class Migration extends SimpleWorker {
private function checkUnmigratedColumnsExist() { private function checkUnmigratedColumnsExist() {
global $wpdb; global $wpdb;
$existingColumns = $wpdb->get_col('DESC ' . SendingQueueModel::$_table); $existingColumns = $wpdb->get_col('DESC ' . esc_sql(SendingQueueModel::$_table));
return in_array('type', $existingColumns); return in_array('type', $existingColumns);
} }
@@ -145,12 +145,13 @@ class Migration extends SimpleWorker {
)); ));
// link the queue with the task via task_id // link the queue with the task via task_id
$newTaskId = $wpdb->insert_id; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $newTaskId = $wpdb->insert_id; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$wpdb->query(sprintf( $table = esc_sql(MP_SENDING_QUEUES_TABLE);
'UPDATE %1$s SET `task_id` = %2$s WHERE `id` = %3$s', $query = $wpdb->prepare(
MP_SENDING_QUEUES_TABLE, "UPDATE `$table` SET `task_id` = %s WHERE `id` = %s",
$newTaskId, $newTaskId,
$queue['id'] $queue['id']
)); );
$wpdb->query($query);
} }
} }
} }
@@ -195,10 +196,10 @@ class Migration extends SimpleWorker {
$migratedUnprocessedCount = ScheduledTaskSubscriber::getUnprocessedCount($taskId); $migratedUnprocessedCount = ScheduledTaskSubscriber::getUnprocessedCount($taskId);
$migratedProcessedCount = ScheduledTaskSubscriber::getProcessedCount($taskId); $migratedProcessedCount = ScheduledTaskSubscriber::getProcessedCount($taskId);
$subscribers = $wpdb->get_var(sprintf( $table = MP_SENDING_QUEUES_TABLE;
'SELECT `subscribers` FROM %1$s WHERE `task_id` = %2$d ' . $subscribers = $wpdb->get_var($wpdb->prepare(
'AND (`count_processed` > %3$d OR `count_to_process` > %4$d)', "SELECT `subscribers` FROM `$table` WHERE `task_id` = %d
MP_SENDING_QUEUES_TABLE, AND (`count_processed` > %d OR `count_to_process` > %d)",
$taskId, $taskId,
$migratedUnprocessedCount, $migratedUnprocessedCount,
$migratedProcessedCount $migratedProcessedCount

View File

@@ -63,10 +63,10 @@ class Helper {
public function getOrdersCountCreatedBefore($dateTime) { public function getOrdersCountCreatedBefore($dateTime) {
global $wpdb; global $wpdb;
$result = $wpdb->get_var(" $result = $wpdb->get_var($wpdb->prepare("
SELECT DISTINCT count(p.ID) FROM {$wpdb->prefix}posts as p SELECT DISTINCT count(p.ID) FROM {$wpdb->prefix}posts as p
WHERE p.post_type = 'shop_order' AND p.post_date < '{$dateTime}' WHERE p.post_type = 'shop_order' AND p.post_date < %s
"); "), $dateTime);
return (int)$result; return (int)$result;
} }