PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/wp-responder-email-autoresponder-and-newsletter-plugin/lib/database_integrity_checker.php

https://gitlab.com/Gashler/sg
PHP | 384 lines | 271 code | 78 blank | 35 comment | 64 complexity | b299c85de5e1595e0f56bcc8ae2887e9 MD5 | raw file
  1. <?php
  2. class DatabaseChecker
  3. {
  4. var $structure;
  5. var $tables;
  6. var $db;
  7. function __construct()
  8. {
  9. global $wpdb;
  10. $database_structure = $GLOBALS['data_structure'];
  11. $this->db = &$wpdb;
  12. $this->structure = $database_structure;
  13. }
  14. function perform_check()
  15. {
  16. foreach ($this->structure as $table_name=>$structure)
  17. {
  18. if (!$this->table_exists($table_name))
  19. $this->create_table($table_name);
  20. else
  21. {
  22. $this->modify_table_to_structure($table_name);
  23. }
  24. }
  25. }
  26. function add_prefix(&$table_name)
  27. {
  28. $table_name = $this->db->prefix.$table_name;
  29. }
  30. function create_table($table_name)
  31. {
  32. $table = $this->structure[$table_name];
  33. $this->add_prefix($table_name);
  34. if (!$table)
  35. {
  36. throw new UndefinedTableException();
  37. }
  38. if (!$this->isValidPrimaryKey($table['primary_key'], $table))
  39. {
  40. $table['primary_key'] = array();
  41. }
  42. if (!$this->isValidAutoIncrement($table['auto_increment'],$table))
  43. {
  44. $table['auto_increment'] = "";
  45. }
  46. $tableColumnDefinitions = array();
  47. $aSingleColumnPrimaryKeyExists = (isset($table['primary_key']) && is_string($table['primary_key']))?true:false;
  48. foreach ($table['columns'] as $columnname=>$columndefinition)
  49. {
  50. $columnDefinition = "`$columnname` $columndefinition";
  51. if ($aSingleColumnPrimaryKeyExists)
  52. {
  53. if ($columnname == $table['auto_increment'])
  54. $columnDefinition = "$columnDefinition AUTO_INCREMENT";
  55. }
  56. array_push($tableColumnDefinitions,$columnDefinition);
  57. }
  58. $tableColumnDefinitionsOfQuery = implode(" ," ,$tableColumnDefinitions);
  59. if (count($table['primary_key']))
  60. {
  61. $primary_key = $table['primary_key'];
  62. if (is_array($primary_key))
  63. {
  64. $primary_key_identifier = implode("`,`",$primary_key);
  65. $primary_key_identifier = "`$primary_key_identifier`";
  66. }
  67. else if (is_string($primary_key))
  68. {
  69. $primary_key_identifier = " `$primary_key` ";
  70. }
  71. $primary_key_clause = ", PRIMARY KEY ($primary_key_identifier)";
  72. }
  73. if (count($table['unique']) > 0 )
  74. {
  75. $uniques = $table['unique'];
  76. $uniqueClauses = array();
  77. foreach ($uniques as $unique_name=>$unique_columns)
  78. {
  79. if (is_array($unique_columns))
  80. $uniqueColumns = implode("`,`",$unique_columns);
  81. else if (is_string($unique_columns))
  82. $uniqueColumns = $unique_columns;
  83. $uniqueClause = "UNIQUE KEY `$unique_name` (`$uniqueColumns`)";
  84. array_push($uniqueClauses,$uniqueClause);
  85. }
  86. $unique_definitions = implode(",", $uniqueClauses);
  87. $unique_definitions = ", $unique_definitions";
  88. }
  89. $completeCreateTableQuery = "CREATE TABLE $table_name ( $tableColumnDefinitionsOfQuery $primary_key_clause $unique_definitions);";
  90. $this->db->query($completeCreateTableQuery);
  91. }
  92. function isValidAutoIncrement($auto_increment,$table)
  93. {
  94. //if the auto increment is one of the columns in a primary key then it is valid.
  95. if (is_string($table['primary_key']))
  96. {
  97. if ($auto_increment == $table['primary_key'])
  98. return true;
  99. }
  100. else if (is_array($table['primary_key']))
  101. {
  102. if (in_array($auto_increment,$table['primary_key']))
  103. return true;
  104. }
  105. return false;
  106. }
  107. function isValidPrimaryKey($primary_key,$table)
  108. {
  109. //if primary key only has columns from the defined table structure
  110. //the primary key is valid
  111. if (empty($primary_key))
  112. return false;
  113. if (is_string($primary_key))
  114. $pkey = array($primary_key);
  115. else
  116. $pkey = $primary_key;
  117. $table_columns = array_keys($table['columns']);
  118. $intersectionOfPrimaryKeyAndTableColumns = array_intersect($table_columns,$pkey);
  119. //if there are no common columns
  120. if (count($intersectionOfPrimaryKeyAndTableColumns) == 0)
  121. {
  122. //If teh primary key specification has columns that are not in the columns sepcification then throw an exception.
  123. throw new Exception("Invalid primary key specification for table. Undefined columns in primary key specification.");
  124. }
  125. if (count($intersectionOfPrimaryKeyAndTableColumns) != count($pkey))
  126. {
  127. throw new Exception("Invalid primary key specification for table. Undefined columns in primary key specification.");
  128. }
  129. return true;
  130. }
  131. /*
  132. * modify_table_to_structure
  133. *
  134. * This function takes the name of a column in the $database_strucutre
  135. * array to modify. It will modify the existing table to conform to the
  136. * spec in the $database_structure array.
  137. *
  138. *
  139. * Preconditions:
  140. * 1. The specified table $table_name exists.
  141. * 2. The table definition for the same was specified in the
  142. * $database_structure global array
  143. *
  144. * Postconditions:
  145. * 1. The table has been modified as per the specification for this
  146. * table, the unique columns have been added
  147. * 2. Only the unique keys as specified in the database table spec
  148. * in the $database_structure array exist. No other unique keys exist.
  149. * 3. The primary key is as specified in $database_structure
  150. * specification, any other primary key is dropped.
  151. */
  152. function modify_table_to_structure($table_name)
  153. {
  154. $table = $this->structure[$table_name];
  155. if (!$table)
  156. throw new UndefinedTableException();
  157. if (!$this->isValidPrimaryKey($table['primary_key'], $table))
  158. {
  159. $table['primary_key'] = array();
  160. }
  161. if (!$this->isValidAutoIncrement($table['auto_increment'],$table))
  162. {
  163. $table['auto_increment'] = "";
  164. }
  165. //list of expected table columns
  166. $columns = array_keys($table['columns']);
  167. //get list of columns in the table
  168. $this->add_prefix($table_name);
  169. $getTableColumnsQuery = "SHOW COLUMNS FROM $table_name;";
  170. $columnsExisting = $this->db->get_col($getTableColumnsQuery,0);
  171. //get the full definitions
  172. $extraInTableDefinitionExisting = $this->db->get_col($getTableColumnsQuery,5);
  173. $whetherHasAutoIncrementColumn = in_array("auto_increment",$extraInTableDefinitionExisting);
  174. $non_existing_columns = array_diff($columns,$columnsExisting);
  175. $primary_key = (array) $table['primary_key'];
  176. if (count($non_existing_columns) > 0 )
  177. {
  178. $primary_key_columns_to_be_added = array_intersect($non_existing_columns,$primary_key);
  179. $non_existing_columns = array_diff($non_existing_columns,$primary_key_columns_to_be_added);
  180. foreach ($non_existing_columns as $column)
  181. {
  182. $columnDefinition = $table['columns'][$column];
  183. $addColumnQuery = "ALTER TABLE $table_name ADD `$column` $columnDefinition ";
  184. $columnAddQuery = "$addColumnQuery ;";
  185. $this->db->query($columnAddQuery);
  186. }
  187. }
  188. $existing_columns_from_required_structure = array_intersect($columns, $columnsExisting);
  189. if (count($existing_columns_from_required_structure) > 0 )
  190. {
  191. //remove teh auto increment element
  192. $existing_columns_of_primary_key = array_intersect($existing_columns_from_required_structure,$primary_key);
  193. $existing_columns_from_required_structure = array_diff($existing_columns_from_required_structure,$primary_key);
  194. foreach ($existing_columns_from_required_structure as $column)
  195. {
  196. $column_def = $table['columns'][$column];
  197. $alterColumnQuery = "ALTER TABLE `$table_name` CHANGE `$column` `$column` $column_def";
  198. $this->db->query($alterColumnQuery);
  199. }
  200. }
  201. //adding primary key
  202. if (isset($table['primary_key']) && false == $whetherHasAutoIncrementColumn)
  203. {
  204. $primary_key = $table['primary_key'];
  205. if (is_string($primary_key))
  206. {
  207. $primary_key_identifier = $primary_key;
  208. }
  209. else if (is_array($primary_key))
  210. {
  211. $primary_key_identifier = implode("`,`",$primary_key);
  212. }
  213. $array_of_column_defs = array();
  214. //get the table definitions for non existing columns
  215. if (count($existing_columns_of_primary_key))
  216. foreach ($existing_columns_of_primary_key as $existing_column)
  217. {
  218. $modification_clause = "CHANGE `$existing_column` `$existing_column` ".$table['columns'][$existing_column];
  219. if ($existing_column == $table['auto_increment'])
  220. {
  221. $modification_clause .= " AUTO_INCREMENT ";
  222. }
  223. $array_of_column_defs[] = $modification_clause;
  224. }
  225. if (isset($primary_key_columns_to_be_added) && 0 != count($primary_key_columns_to_be_added))
  226. foreach ($primary_key_columns_to_be_added as $new_column)
  227. {
  228. $column_def_clause = "ADD `$new_column` ".$table['columns'][$new_column];
  229. if ($new_column == $table['auto_increment'])
  230. {
  231. $column_def_clause .= " AUTO_INCREMENT";
  232. }
  233. $array_of_column_defs[] = $column_def_clause;
  234. }
  235. $primarykeyDropQuery = "ALTER TABLE `$table_name` DROP PRIMARY KEY;";
  236. $this->db->query($primarykeyDropQuery);
  237. $primaryKeyColumnDefinitions = implode(",",$array_of_column_defs);
  238. if (!empty($primaryKeyColumnDefinitions))
  239. $primaryKeyColumnDefinitions = "$primaryKeyColumnDefinitions , ";
  240. $primarykeyAdditionQuery = "ALTER TABLE `$table_name` $primaryKeyColumnDefinitions ADD PRIMARY KEY (`$primary_key_identifier`);";
  241. $this->db->query($primarykeyAdditionQuery);
  242. }
  243. $unique_indexes = (array) $table['unique'];
  244. $unique_indexes = array_keys($unique_indexes);
  245. $existingIndexes = $this->db->get_results("SHOW INDEX FROM `$table_name`;");
  246. $existingUniques = array();
  247. foreach ($existingIndexes as $index)
  248. {
  249. if ($index->Non_unique == 1)
  250. continue;
  251. if ($index->Key_name == "PRIMARY")
  252. continue;
  253. array_push($existingUniques,$index->Key_name);
  254. }
  255. $existingUniques = array_unique($existingUniques);
  256. $uniquesToDrop = $existingUniques;
  257. foreach ($uniquesToDrop as $index)
  258. {
  259. $dropIndexQuery = "DROP INDEX `$index` ON `$table_name`;";
  260. $this->db->query($dropIndexQuery);
  261. }
  262. //unique key
  263. if (isset($table['unique']))
  264. {
  265. foreach ($table['unique'] as $unique_key_name=>$unique_key)
  266. {
  267. $whetherSingleColumnUnique=false;
  268. if (is_string($unique_key) || 1 == count($unique_key))
  269. $whetherSingleColumnUnique=true;
  270. if (is_array($unique_key))
  271. {
  272. $unique_identifier = implode("`,`",$unique_key);
  273. }
  274. else if (is_string($unique_key))
  275. {
  276. $unique_identifier = "`$unique_key`";
  277. }
  278. else
  279. continue;
  280. //HACK ALERT!!
  281. if ($unique_key_name == "meta_key_is_unique")
  282. {
  283. $setMetaKeyColumnToMd5OfIdQuery=sprintf("UPDATE %swpr_queue SET meta_key=MD5(id) WHERE meta_key='';",$this->db->prefix);
  284. $this->db->query($setMetaKeyColumnToMd5OfIdQuery);
  285. }
  286. $addUniqueKeyQuery = "ALTER TABLE `$table_name` ADD UNIQUE KEY `$unique_key_name` (`$unique_identifier`);";
  287. $this->db->query($addUniqueKeyQuery);
  288. }
  289. }
  290. //drop other indexes.
  291. }
  292. function table_exists($table_name)
  293. {
  294. if (count($this->tables)==0)
  295. {
  296. $getTablesQuery = "SHOW TABLES;";
  297. $tables = $this->db->get_col($getTablesQuery);
  298. $this->tables = $tables;
  299. }
  300. $this->add_prefix($table_name);
  301. return (in_array($table_name,$this->tables))?true:false;
  302. }
  303. }
  304. class UndefinedTableException extends Exception
  305. {
  306. }