PageRenderTime 1057ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/upload/install/model/upgrade.php

https://github.com/kstep/opencart
PHP | 381 lines | 254 code | 92 blank | 35 comment | 49 complexity | 9c59922a8b99bc9e3d0c352878fac129 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. <?php
  2. class ModelUpgrade extends Model {
  3. public function mysql() {
  4. // Upgrade script to opgrade opencart to the latest version.
  5. // Oldest version supported is 1.3.2
  6. // Load the sql file
  7. $file = DIR_APPLICATION . 'opencart.sql';
  8. if (!file_exists($file)) {
  9. exit('Could not load sql file: ' . $file);
  10. }
  11. $string = '';
  12. $lines = file($file);
  13. $status = false;
  14. // Get only the create statements
  15. foreach($lines as $line) {
  16. // Set any prefix
  17. $line = str_replace("CREATE TABLE `oc_", "CREATE TABLE `" . DB_PREFIX, $line);
  18. // If line begins with create table we want to start recording
  19. if (substr($line, 0, 12) == 'CREATE TABLE') {
  20. $status = true;
  21. }
  22. if ($status) {
  23. $string .= $line;
  24. }
  25. // If line contains with ; we want to stop recording
  26. if (preg_match('/;/', $line)) {
  27. $status = false;
  28. }
  29. }
  30. $table_new_data = array();
  31. // Trim any spaces
  32. $string = trim($string);
  33. // Trim any ;
  34. $string = trim($string, ';');
  35. // Start reading each create statement
  36. $statements = explode(';', $string);
  37. foreach ($statements as $sql) {
  38. // Get all fields
  39. $field_data = array();
  40. preg_match_all('#`(\w[\w\d]*)`\s+((tinyint|smallint|mediumint|bigint|int|tinytext|text|mediumtext|longtext|tinyblob|blob|mediumblob|longblob|varchar|char|datetime|date|float|double|decimal|timestamp|time|year|enum|set|binary|varbinary)(\((\d+)(,\s*(\d+))?\))?){1}\s*(collate (\w+)\s*)?(unsigned\s*)?((NOT\s*NULL\s*)|(NULL\s*))?(auto_increment\s*)?(default \'([^\']*)\'\s*)?#i', $sql, $match);
  41. foreach(array_keys($match[0]) as $key) {
  42. $field_data[] = array(
  43. 'name' => trim($match[1][$key]),
  44. 'type' => strtoupper(trim($match[3][$key])),
  45. 'size' => str_replace(array('(', ')'), '', trim($match[4][$key])),
  46. 'sizeext' => trim($match[8][$key]),
  47. 'collation' => trim($match[9][$key]),
  48. 'unsigned' => trim($match[10][$key]),
  49. 'notnull' => trim($match[11][$key]),
  50. 'autoincrement' => trim($match[14][$key]),
  51. 'default' => trim($match[16][$key]),
  52. );
  53. }
  54. // Get primary keys
  55. $primary_data = array();
  56. preg_match('#primary\s*key\s*\([^)]+\)#i', $sql, $match);
  57. if (isset($match[0])) {
  58. preg_match_all('#`(\w[\w\d]*)`#', $match[0], $match);
  59. } else{
  60. $match = array();
  61. }
  62. if ($match) {
  63. foreach($match[1] as $primary){
  64. $primary_data[] = $primary;
  65. }
  66. }
  67. // Get indexes
  68. $index_data = array();
  69. $indexes = array();
  70. preg_match_all('#key\s*`\w[\w\d]*`\s*\(.*\)#i', $sql, $match);
  71. foreach($match[0] as $key) {
  72. preg_match_all('#`(\w[\w\d]*)`#', $key, $match);
  73. $indexes[] = $match;
  74. }
  75. foreach($indexes as $index){
  76. $key = '';
  77. foreach($index[1] as $field) {
  78. if ($key == '') {
  79. $key = $field;
  80. } else{
  81. $index_data[$key][] = $field;
  82. }
  83. }
  84. }
  85. // Table options
  86. $option_data = array();
  87. preg_match_all('#(\w+)=(\w+)#', $sql, $option);
  88. foreach(array_keys($option[0]) as $key) {
  89. $option_data[$option[1][$key]] = $option[2][$key];
  90. }
  91. // Get Table Name
  92. preg_match_all('#create\s*table\s*`(\w[\w\d]*)`#i', $sql, $table);
  93. if (isset($table[1][0])) {
  94. $table_new_data[] = array(
  95. 'sql' => $sql,
  96. 'name' => $table[1][0],
  97. 'field' => $field_data,
  98. 'primary' => $primary_data,
  99. 'index' => $index_data,
  100. 'option' => $option_data
  101. );
  102. }
  103. }
  104. $this->db = new DB(DB_DRIVER, DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
  105. // Get all current tables, fields, type, size, etc..
  106. $table_old_data = array();
  107. $table_query = $this->db->query("SHOW TABLES FROM `" . DB_DATABASE . "`");
  108. foreach ($table_query->rows as $table) {
  109. if (utf8_substr($table['Tables_in_' . DB_DATABASE], 0, strlen(DB_PREFIX)) == DB_PREFIX) {
  110. $field_data = array();
  111. $field_query = $this->db->query("SHOW COLUMNS FROM `" . $table['Tables_in_' . DB_DATABASE] . "`");
  112. foreach ($field_query->rows as $field) {
  113. $field_data[] = $field['Field'];
  114. }
  115. $table_old_data[$table['Tables_in_' . DB_DATABASE]] = $field_data;
  116. }
  117. }
  118. foreach ($table_new_data as $table) {
  119. // If table is not found create it
  120. if (!isset($table_old_data[$table['name']])) {
  121. $this->db->query($table['sql']);
  122. } else {
  123. // DB Engine
  124. if (isset($table['option']['ENGINE'])) {
  125. $this->db->query("ALTER TABLE `" . $table['name'] . "` ENGINE = `" . $table['option']['ENGINE'] . "`");
  126. }
  127. // Charset
  128. if (isset($table['option']['CHARSET']) && isset($table['option']['COLLATE'])) {
  129. $this->db->query("ALTER TABLE `" . $table['name'] . "` DEFAULT CHARACTER SET `" . $table['option']['CHARSET'] . "` COLLATE `" . $table['option']['COLLATE'] . "`");
  130. }
  131. $i = 0;
  132. foreach ($table['field'] as $field) {
  133. // If field is not found create it
  134. if (!in_array($field['name'], $table_old_data[$table['name']])) {
  135. $sql = "ALTER TABLE `" . $table['name'] . "` ADD `" . $field['name'] . "` " . $field['type'];
  136. if ($field['size']) {
  137. $sql .= "(" . $field['size'] . ")";
  138. }
  139. if ($field['collation']) {
  140. $sql .= " " . $field['collation'];
  141. }
  142. if ($field['notnull']) {
  143. $sql .= " " . $field['notnull'];
  144. }
  145. if ($field['default']) {
  146. $sql .= " DEFAULT '" . $field['default'] . "'";
  147. }
  148. if (isset($table['field'][$i - 1])) {
  149. $sql .= " AFTER `" . $table['field'][$i - 1]['name'] . "`";
  150. } else {
  151. $sql .= " FIRST";
  152. }
  153. $this->db->query($sql);
  154. } else {
  155. // Remove auto increment from all fields
  156. $sql = "ALTER TABLE `" . $table['name'] . "` CHANGE `" . $field['name'] . "` `" . $field['name'] . "` " . strtoupper($field['type']);
  157. if ($field['size']) {
  158. $sql .= "(" . $field['size'] . ")";
  159. }
  160. if ($field['collation']) {
  161. $sql .= " " . $field['collation'];
  162. }
  163. if ($field['notnull']) {
  164. $sql .= " " . $field['notnull'];
  165. }
  166. if ($field['default']) {
  167. $sql .= " DEFAULT '" . $field['default'] . "'";
  168. }
  169. if (isset($table['field'][$i - 1])) {
  170. $sql .= " AFTER `" . $table['field'][$i - 1]['name'] . "`";
  171. } else {
  172. $sql .= " FIRST";
  173. }
  174. $this->db->query($sql);
  175. }
  176. $i++;
  177. }
  178. $status = false;
  179. // Drop primary keys and indexes.
  180. $query = $this->db->query("SHOW INDEXES FROM `" . $table['name'] . "`");
  181. foreach ($query->rows as $result) {
  182. if ($result['Key_name'] != 'PRIMARY') {
  183. $this->db->query("ALTER TABLE `" . $table['name'] . "` DROP INDEX `" . $result['Key_name'] . "`");
  184. } else {
  185. $status = true;
  186. }
  187. }
  188. if ($status) {
  189. $this->db->query("ALTER TABLE `" . $table['name'] . "` DROP PRIMARY KEY");
  190. }
  191. // Add a new primary key.
  192. $primary_data = array();
  193. foreach ($table['primary'] as $primary) {
  194. $primary_data[] = "`" . $primary . "`";
  195. }
  196. if ($primary_data) {
  197. $this->db->query("ALTER TABLE `" . $table['name'] . "` ADD PRIMARY KEY(" . implode(',', $primary_data) . ")");
  198. }
  199. // Add the new indexes
  200. foreach ($table['index'] as $index) {
  201. $index_data = array();
  202. foreach ($index as $key) {
  203. $index_data[] = '`' . $key . '`';
  204. }
  205. if ($index_data) {
  206. $this->db->query("ALTER TABLE `" . $table['name'] . "` ADD INDEX (" . implode(',', $index_data) . ")");
  207. }
  208. }
  209. // Add auto increment to primary keys again
  210. foreach ($table['field'] as $field) {
  211. if ($field['autoincrement']) {
  212. $sql = "ALTER TABLE `" . $table['name'] . "` CHANGE `" . $field['name'] . "` `" . $field['name'] . "` " . strtoupper($field['type']);
  213. if ($field['size']) {
  214. $sql .= "(" . $field['size'] . ")";
  215. }
  216. if ($field['collation']) {
  217. $sql .= " " . $field['collation'];
  218. }
  219. if ($field['notnull']) {
  220. $sql .= " " . $field['notnull'];
  221. }
  222. if ($field['default']) {
  223. $sql .= " DEFAULT '" . $field['default'] . "'";
  224. }
  225. if ($field['autoincrement']) {
  226. $sql .= " AUTO_INCREMENT";
  227. }
  228. $this->db->query($sql);
  229. }
  230. }
  231. }
  232. }
  233. // Update any additional sql thats required
  234. // Settings
  235. $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "setting` WHERE `store_id` = '0' ORDER BY `store_id` ASC");
  236. foreach ($query->rows as $setting) {
  237. if (!$setting['serialized']) {
  238. $settings[$setting['key']] = $setting['value'];
  239. } else {
  240. $settings[$setting['key']] = unserialize($setting['value']);
  241. }
  242. }
  243. // Set defaults for new voucher min/max fields if not set
  244. if (empty($settings['config_voucher_min'])) {
  245. $this->db->query("INSERT INTO `" . DB_PREFIX . "setting` SET `value` = '1', `key` = 'config_voucher_min', `group` = 'config', `store_id` = 0");
  246. }
  247. if (empty($settings['config_voucher_max'])) {
  248. $this->db->query("INSERT INTO `" . DB_PREFIX . "setting` SET `value` = '1000', `key` = 'config_voucher_max', `group` = 'config', `store_id` = 0");
  249. }
  250. // Update the customer group table
  251. if (in_array('name', $table_old_data[DB_PREFIX . 'customer_group'])) {
  252. // Customer Group 'name' field moved to new customer_group_description table. Need to loop through and move over.
  253. $customer_group_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "customer_group`");
  254. foreach ($customer_group_query->rows as $customer_group) {
  255. $language_query = $this->db->query("SELECT `language_id` FROM `" . DB_PREFIX . "language`");
  256. foreach ($language_query->rows as $language) {
  257. $this->db->query("REPLACE INTO `" . DB_PREFIX . "customer_group_description` SET `customer_group_id` = '" . (int)$customer_group['customer_group_id'] . "', `language_id` = '" . (int)$language['language_id'] . "', `name` = '" . $this->db->escape($customer_group['name']) . "'");
  258. }
  259. }
  260. $this->db->query("ALTER TABLE `" . DB_PREFIX . "customer_group` DROP `name`");
  261. }
  262. // Rename the option_value field to value
  263. if (in_array('option_value', $table_old_data[DB_PREFIX . 'product_option'])) {
  264. $this->db->query("ALTER TABLE `" . DB_PREFIX . "product_option` DROP `value`");
  265. $this->db->query("ALTER TABLE `" . DB_PREFIX . "product_option` CHANGE `option_value` `value` TEXT");
  266. $this->db->query("ALTER TABLE `" . DB_PREFIX . "product_option` DROP `option_value`");
  267. }
  268. // Sort the categories to take advantage of the nested set model
  269. $this->repairCategories(0);
  270. }
  271. // Function to repair any erroneous categories that are not in the category path table.
  272. public function repairCategories($parent_id = 0) {
  273. $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "category` WHERE `parent_id` = '" . (int)$parent_id . "'");
  274. foreach ($query->rows as $category) {
  275. // Delete the path below the current one
  276. $this->db->query("DELETE FROM `" . DB_PREFIX . "category_path` WHERE `category_id` = '" . (int)$category['category_id'] . "'");
  277. // Fix for records with no paths
  278. $level = 0;
  279. $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "category_path` WHERE `category_id` = '" . (int)$parent_id . "' ORDER BY `level` ASC");
  280. foreach ($query->rows as $result) {
  281. $this->db->query("INSERT INTO `" . DB_PREFIX . "category_path` SET `category_id` = '" . (int)$category['category_id'] . "', `path_id` = '" . (int)$result['path_id'] . "', `level` = '" . (int)$level . "'");
  282. $level++;
  283. }
  284. $this->db->query("REPLACE INTO `" . DB_PREFIX . "category_path` SET `category_id` = '" . (int)$category['category_id'] . "', `path_id` = '" . (int)$category['category_id'] . "', `level` = '" . (int)$level . "'");
  285. $this->repairCategories($category['category_id']);
  286. }
  287. }
  288. }
  289. ?>