GdprDumpGdprSqlDump.inc in General Data Protection Regulation 7
File
modules/gdpr_dump/inc/GdprDumpGdprSqlDump.inc
View source
<?php
class GdprDumpGdprSqlDump {
const GDPR_TABLE_PREFIX = 'gdpr_clone_';
protected $gdprOptions = [];
protected $emptyTables = [];
protected $skipTables = [];
protected $plugins;
protected $driver;
public function __construct() {
ctools_include('plugins');
$this->driver = db_driver();
$this->plugins = ctools_get_plugins('gdpr_dump', 'sanitizer');
$this->gdprOptions = variable_get('gdpr_dump_table_map', []);
$this->emptyTables = variable_get('gdpr_dump_empty_tables', []);
}
public function dump() {
$sql = $this
->getInstance();
$this
->prepare();
$results = $sql
->dump(drush_get_option('result-file', FALSE));
$this
->cleanup();
return $results;
}
protected function getInstance(array $dbSpec = NULL) {
$database = drush_get_option('database', 'default');
$target = drush_get_option('target', 'default');
if (!empty($dbSpec)) {
if (!empty($dbSpec['driver'])) {
$className = 'GdprDumpGdprSql' . ucfirst($dbSpec['driver']);
module_load_include('inc', 'gdpr_dump', 'inc/' . $className);
$instance = drush_get_class($className, [
$dbSpec,
]);
if (!empty($instance)) {
return $instance;
}
}
}
elseif ($url = drush_get_option('db-url')) {
$url = \is_array($url) ? $url[$database] : $url;
$dbSpec = drush_convert_db_from_db_url($url);
$dbSpec['db_prefix'] = drush_get_option('db-prefix');
return $this
->getInstance($dbSpec);
}
elseif (($databases = drush_get_option('databases')) && \array_key_exists($database, $databases) && \array_key_exists($target, $databases[$database])) {
$dbSpec = $databases[$database][$target];
return $this
->getInstance($dbSpec);
}
else {
if ($sqlVersion = drush_sql_get_version()) {
if ($dbSpec = $sqlVersion
->get_db_spec()) {
return $this
->getInstance($dbSpec);
}
}
}
}
protected function createCloneQueryString($originalTable) {
if (\array_key_exists($originalTable, $this->skipTables)) {
return NULL;
}
$clonedTable = self::GDPR_TABLE_PREFIX . $originalTable;
switch ($this->driver) {
case 'mysql':
return "CREATE TABLE IF NOT EXISTS `{$clonedTable}` LIKE `{$originalTable}`;";
case 'pgsql':
case 'sqlite':
return "CREATE TABLE IF NOT EXISTS `{$clonedTable}` AS SELECT * FROM `{$originalTable}` WHERE 1=2;";
case 'oracle':
break;
case 'sqlsrv':
break;
}
throw new SqlException("Unsupported database driver detected, can't clone table {$originalTable} for GDPR.");
}
protected function createTableClones() {
$tables = \array_keys($this->gdprOptions);
$transaction = db_transaction('gdpr_drop_table');
try {
foreach ($tables as $table) {
$queryString = $this
->createCloneQueryString($table);
if (NULL === $queryString) {
continue;
}
try {
if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
drush_print("Executing: '{$queryString}'", 0, STDERR);
}
db_query($queryString);
} catch (\Exception $e) {
drush_print("Error while cloning the '{$table}' table.");
$transaction
->rollBack();
}
}
} catch (Exception $e) {
$transaction
->rollBack();
drush_set_error('DRUSH_SQL_DUMP_FAIL', 'Table clone failed');
}
}
protected function sanitizeData() {
foreach ($this->gdprOptions as $table => $sanitationOptions) {
if (\array_key_exists($table, $this->skipTables)) {
continue;
}
$selectQuery = db_select($table);
$selectQuery
->fields($table);
$oldRows = $selectQuery
->execute();
if (NULL === $oldRows) {
continue;
}
$clonedTable = self::GDPR_TABLE_PREFIX . $table;
$describeQueryString = "DESCRIBE `{$table}`";
$describeQuery = db_query($describeQueryString);
$tableColumns = $describeQuery
->fetchCol('Field');
$insertQuery = db_insert($clonedTable);
$insertQuery
->fields($tableColumns);
$unique_data = [];
$schema = drupal_get_schema($table);
$uniq_keys = isset($schema['unique keys']) ? $schema['unique keys'] : [];
$primary_key = isset($schema['primary key'][0]) ? $schema['primary key'][0] : '';
while ($row = $oldRows
->fetchAssoc()) {
foreach ($sanitationOptions as $column => $pluginId) {
$plugin = gdpr_dump_get_sanitizer_plugins($pluginId);
if (function_exists($plugin['sanitize callback'])) {
$tries = 0;
$unique_field = isset($uniq_keys[$column]) || $column == $primary_key;
do {
$is_valid = TRUE;
$value = call_user_func($plugin['sanitize callback'], $row[$column]);
if (isset($schema['fields'][$column]['length']) && strlen($value) > $schema['fields'][$column]['length']) {
$value = truncate_utf8($value, $schema['fields'][$column]['length']);
}
if ($unique_field && in_array($value, $unique_data)) {
$is_valid = FALSE;
}
} while (!$is_valid && $tries++ < 50);
if ($tries >= 50) {
drush_log("Too many tries for column '{$column}'", 'error');
exit;
}
if ($unique_field) {
$unique_data[] = $value;
}
$row[$column] = $value;
}
}
$insertQuery
->values($row);
}
$insertQuery
->execute();
}
}
protected function prepare() {
$this
->cleanup();
$this
->buildSkipTables();
$this
->createTableClones();
$this
->sanitizeData();
}
protected function buildSkipTables() {
$sql = $this
->getInstance();
$table_selection = $sql
->get_expanded_table_selection();
$skipTables = \array_merge($table_selection['skip'], $table_selection['structure']);
$skipTables = \array_flip($skipTables);
$skipTables = $skipTables + $this->emptyTables;
$this->skipTables = $skipTables;
}
protected function cleanup() {
$transaction = db_transaction('gdpr_drop_table');
try {
foreach (\array_keys($this->gdprOptions) as $table) {
$gdprTable = self::GDPR_TABLE_PREFIX . $table;
db_drop_table($gdprTable);
}
} catch (Exception $e) {
$transaction
->rollback();
drush_set_error('DRUSH_SQL_DUMP_FAIL', 'Database Cleanup failed');
}
}
}