PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/public/upgrade/scripts/OnionUpgradeScript.class.php

https://github.com/fb83/Project-Pier
PHP | 394 lines | 254 code | 54 blank | 86 comment | 52 complexity | a5a26d5b9ef834db8db799b0aa907909 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, AGPL-3.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * Onion upgrade script will upgrade alpha1 or activeCollab 0.6 to activeCollab 0.7
  4. *
  5. * @package ScriptUpgrader.scripts
  6. * @version 1.0
  7. * @http://www.projectpier.org/
  8. */
  9. class OnionUpgradeScript extends ScriptUpgraderScript {
  10. /**
  11. * Database connection link
  12. *
  13. * @var resource
  14. */
  15. private $database_connection = null;
  16. /**
  17. * Array of files and folders that need to be writable
  18. *
  19. * @var array
  20. */
  21. private $check_is_writable = array(
  22. '/config/config.php',
  23. '/public/files',
  24. '/cache',
  25. '/upload'
  26. ); // array
  27. /**
  28. * Array of extensions taht need to be loaded
  29. *
  30. * @var array
  31. */
  32. private $check_extensions = array(
  33. 'mysql', 'gd', 'simplexml'
  34. ); // array
  35. /**
  36. * Construct the OnionUpgradeScript
  37. *
  38. * @param Output $output
  39. * @return OnionUpgradeScript
  40. */
  41. function __construct(Output $output) {
  42. parent::__construct($output);
  43. $this->setVersionFrom('0.6');
  44. $this->setVersionTo('0.7');
  45. } // __construct
  46. /**
  47. * Execute the script
  48. *
  49. * @param void
  50. * @return boolean
  51. */
  52. function execute() {
  53. define('ROOT', realpath(dirname(__FILE__) . '/../../../'));
  54. // ---------------------------------------------------
  55. // Load config
  56. // ---------------------------------------------------
  57. $config_is_set = require_once INSTALLATION_PATH . '/config/config.php';
  58. if (!$config_is_set) {
  59. $this->printMessage('Valid config file was not found!', true);
  60. return false;
  61. } else {
  62. $this->printMessage('Config file found and loaded.');
  63. } // if
  64. // ---------------------------------------------------
  65. // Check for version match (pre-0.7.0 had no version?)
  66. // ---------------------------------------------------
  67. if (defined('PRODUCT_VERSION') && PRODUCT_VERSION !== '0.6') {
  68. $this->printMessage('This upgrade script can be used only to upgrade 0.6 to 0.7', true);
  69. return false;
  70. } // if
  71. // ---------------------------------------------------
  72. // Check if files and folders are writable
  73. // ---------------------------------------------------
  74. foreach ($this->check_is_writable as $relative_path) {
  75. $path = ROOT . $relative_path;
  76. if (is_file($path)) {
  77. if (file_is_writable($path)) {
  78. $this->printMessage("File '$relative_path' exists and is writable");
  79. } else {
  80. $this->printMessage("File '$relative_path' is not writable", true);
  81. return false;
  82. } // if
  83. } elseif (is_dir($path)) {
  84. if (folder_is_writable($path)) {
  85. $this->printMessage("Folder '$relative_path' exists and is writable");
  86. } else {
  87. $this->printMessage("Folder '$relative_path' is not writable", true);
  88. return false;
  89. } // if
  90. } else {
  91. $this->printMessage("'$relative_path' does not exists on the system", true);
  92. return false;
  93. } // if
  94. } // foreach
  95. // ---------------------------------------------------
  96. // Check if extensions are loaded
  97. // ---------------------------------------------------
  98. foreach ($this->check_extensions as $extension_name) {
  99. if (extension_loaded($extension_name)) {
  100. $this->printMessage("Extension '$extension_name' is loaded");
  101. } else {
  102. $this->printMessage("Extension '$extension_name' is not loaded", true);
  103. return false;
  104. } // if
  105. } // foreach
  106. // ---------------------------------------------------
  107. // Connect to database
  108. // ---------------------------------------------------
  109. if ($this->database_connection = mysql_connect(DB_HOST, DB_USER, DB_PASS)) {
  110. if (mysql_select_db(DB_NAME, $this->database_connection)) {
  111. $this->printMessage('Upgrade script has connected to the database.');
  112. } else {
  113. $this->printMessage('Failed to select database ' . DB_NAME);
  114. return false;
  115. } // if
  116. } else {
  117. $this->printMessage('Failed to connect to database');
  118. return false;
  119. } // if
  120. // ---------------------------------------------------
  121. // Check MySQL version
  122. // ---------------------------------------------------
  123. $mysql_version = mysql_get_server_info($this->database_connection);
  124. if ($mysql_version && version_compare($mysql_version, '4.1', '>=')) {
  125. $constants['DB_CHARSET'] = 'utf8';
  126. @mysql_query("SET NAMES 'utf8'", $this->database_connection);
  127. tpl_assign('default_collation', $default_collation = 'collate utf8_unicode_ci');
  128. tpl_assign('default_charset', $default_charset = 'DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci');
  129. } else {
  130. tpl_assign('default_collation', $default_collation = '');
  131. tpl_assign('default_charset', $default_charset = '');
  132. } // if
  133. tpl_assign('table_prefix', TABLE_PREFIX);
  134. // ---------------------------------------------------
  135. // Check test query
  136. // ---------------------------------------------------
  137. $test_table_name = TABLE_PREFIX . 'test_table';
  138. $test_table_sql = "CREATE TABLE `$test_table_name` (
  139. `id` int(10) unsigned NOT NULL auto_increment,
  140. `name` varchar(50) $default_collation NOT NULL default '',
  141. PRIMARY KEY (`id`)
  142. ) ENGINE=InnoDB $default_charset;";
  143. if (@mysql_query($test_table_sql, $this->database_connection)) {
  144. $this->printMessage('Test query has been executed. Its safe to proceed with database migration.');
  145. @mysql_query("DROP TABLE `$test_table_name`", $this->database_connection);
  146. } else {
  147. $this->printMessage('Failed to executed test query. MySQL said: ' . mysql_error($this->database_connection), true);
  148. return false;
  149. } // if
  150. //return ;
  151. // ---------------------------------------------------
  152. // Execute migration
  153. // ---------------------------------------------------
  154. $total_queries = 0;
  155. $executed_queries = 0;
  156. $upgrade_script = tpl_fetch(get_template_path('db_migration/onion'));
  157. if ($this->executeMultipleQueries($upgrade_script, $total_queries, $executed_queries, $this->database_connection)) {
  158. $this->printMessage("Database schema transformations executed (total queries: $total_queries)");
  159. } else {
  160. $this->printMessage('Failed to execute DB schema transformations. MySQL said: ' . mysql_error(), true);
  161. return false;
  162. } // if
  163. if (!$this->importMessageComments()) {
  164. return false;
  165. } // if
  166. if (!$this->importProjectDocuments()) {
  167. return false;
  168. } // if
  169. $this->cleanApplicationLogs();
  170. $this->fixConfigFile();
  171. $this->printMessage('ProjectPier has been upgraded. You are now running ProjectPier 0.7. Enjoy!');
  172. } // execute
  173. /**
  174. * Import message comments
  175. *
  176. * @param void
  177. * @return boolean
  178. */
  179. private function importMessageComments() {
  180. $this->printMessage('Starting to import comments...');
  181. if ($result = mysql_query('SELECT * FROM `' . TABLE_PREFIX . 'message_comments', $this->database_connection)) {
  182. mysql_query('BEGIN WORK', $this->database_connection);
  183. $counter = 0;
  184. while ($row = mysql_fetch_assoc($result)) {
  185. $sql = sprintf("INSERT INTO `%scomments` (`rel_object_id`, `rel_object_manager`, `text`, `is_private`, `created_on`, `created_by_id`, `updated_on`, `updated_by_id`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
  186. TABLE_PREFIX, $row['message_id'], 'ProjectMessages', mysql_real_escape_string($row['text']), $row['is_private'], $row['created_on'], $row['created_by_id'], $row['updated_on'], $row['updated_by_id']);
  187. if (!mysql_query($sql, $this->database_connection)) {
  188. mysql_query('ROLLBACK', $this->database_connection);
  189. $this->printMessage('Failed to move message comments. MySQL said: ' . mysql_error(), true);
  190. return false;
  191. } // if
  192. $counter++;
  193. } // while
  194. mysql_query('COMMIT');
  195. $this->printMessage("$counter message comments moved");
  196. if (mysql_query('DROP TABLE IF EXISTS `' . TABLE_PREFIX . 'message_comments', $this->database_connection)) {
  197. $this->printMessage('`' . TABLE_PREFIX . 'message_comments` table dropped');
  198. } else {
  199. $this->printMessage('Warning: Failed to drop old message comments table. MySQL said: ' . mysql_error(), true);
  200. }
  201. } // if
  202. return true;
  203. } // importMessageComments
  204. /**
  205. * This function will import project documents into the new files section and preserve message / file relations
  206. *
  207. * @param void
  208. * @return boolean
  209. */
  210. function importProjectDocuments() {
  211. $this->printMessage('Starting to import documents...');
  212. if ($result = mysql_query('SELECT * FROM `' . TABLE_PREFIX . 'project_documents`')) {
  213. mysql_query('BEGIN WORK', $this->database_connection);
  214. $counter = 0;
  215. while ($row = mysql_fetch_assoc($result)) {
  216. $sql = sprintf("INSERT INTO `%sproject_files` (`project_id`, `filename`, `description`, `is_private`, `is_visible`, `created_on`, `created_by_id`, `updated_on`, `updated_by_id`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
  217. TABLE_PREFIX, $row['project_id'], mysql_real_escape_string($row['filename']), mysql_real_escape_string($row['description']), $row['is_private'], 1, $row['created_on'], $row['created_by_id'], $row['updated_on'], $row['updated_by_id']);
  218. if (!mysql_query($sql, $this->database_connection)) {
  219. mysql_query('ROLLBACK', $this->database_connection);
  220. $this->printMessage('Failed to move project documents. MySQL said: ' . mysql_error(), true);
  221. return false;
  222. } // if
  223. $file_id = mysql_insert_id($this->database_connection);
  224. $file_type_id = 0;
  225. $sql = sprintf("SELECT `id` FROM `%sfile_types` WHERE `extension` = '%s'", TABLE_PREFIX, mysql_real_escape_string(strtolower(get_file_extension($row['filename']))));
  226. if ($file_type_result = mysql_query($sql)) {
  227. if ($file_type_row = mysql_fetch_assoc($file_type_result)) {
  228. $file_type_id = (integer) $file_type_row['id'];
  229. } // if
  230. } // if
  231. $repository_id = '';
  232. $file_path = INSTALLATION_PATH . '/public/files/project_documents/' . $row['project_id'] . '/' . $row['filename'];
  233. if (is_file($file_path)) {
  234. do {
  235. $repository_id = sha1(uniqid(rand(), true));
  236. $repository_entry_exists = false;
  237. if ($check_repository_id_result = mysql_query(sprintf(("SELECT COUNT (`id`) AS 'row_count' FROM `%sfile_repo` WHERE `id` = '%s'"), TABLE_PREFIX, $repository_id))) {
  238. if ($check_repository_id_row = mysql_fetch_assoc($check_repository_id_result)) {
  239. $repository_entry_exists = (boolean) $check_repository_id_row['row_count'];
  240. } // if
  241. } // if
  242. } while ($repository_entry_exists);
  243. $sql = sprintf("INSERT INTO `%sfile_repo` (`id`, `content`) VALUES ('%s', '%s')",
  244. TABLE_PREFIX, $repository_id, mysql_real_escape_string(file_get_contents($file_path), $this->database_connection)
  245. ); // sprintf
  246. if (!mysql_query($sql, $this->database_connection)) {
  247. mysql_query('ROLLBACK', $this->database_connection);
  248. $this->printMessage('Failed to insert file content into file repository. MySQL said: ' . mysql_error(), true);
  249. return false;
  250. } // if
  251. } // if
  252. $sql = sprintf("INSERT INTO `%sproject_file_revisions` (`file_id`, `file_type_id`, `repository_id`, `revision_number`, `type_string`, `filesize`, `created_on`, `created_by_id`, `updated_on`, `updated_by_id`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
  253. TABLE_PREFIX, $file_id, $file_type_id, $repository_id, 1, $row['type'], $row['size'], $row['created_on'], $row['created_by_id'], $row['updated_on'], $row['updated_by_id']
  254. ); // sprintf
  255. if (!mysql_query($sql, $this->database_connection)) {
  256. mysql_query('ROLLBACK', $this->database_connection);
  257. $this->printMessage('Failed to move project documents. MySQL said: ' . mysql_error(), true);
  258. return false;
  259. } // if
  260. // Now, relations with messages...
  261. if ($related_messages_result = mysql_query(sprintf("SELECT * FROM `%smessage_documents` WHERE `document_id` = '%s'", TABLE_PREFIX, $row['id']), $this->database_connection)) {
  262. while ($related_messages_row = mysql_fetch_assoc($related_messages_result)) {
  263. $sql = sprintf("INSERT INTO `%sattached_files` (`rel_object_manager`, `rel_object_id`, `file_id`, `created_on`, `created_by_id`) VALUES ('%s', '%s', '%s', '%s', '%s')",
  264. TABLE_PREFIX, 'ProjectMessages', $related_messages_row['message_id'], $file_id, $row['created_on'], $row['created_by_id']
  265. ); // sprintf
  266. if (!mysql_query($sql, $this->database_connection)) {
  267. mysql_query('ROLLBACK', $this->database_connection);
  268. $this->printMessage('Failed to add message - file relation. MySQL said: ' . mysql_error(), true);
  269. return false;
  270. } // if
  271. } // while
  272. } // if
  273. $counter++;
  274. } // while
  275. mysql_query('COMMIT');
  276. $this->printMessage("$counter documents moved");
  277. // Drop tables
  278. if (mysql_query('DROP TABLE IF EXISTS `' . TABLE_PREFIX . 'project_documents', $this->database_connection)) {
  279. $this->printMessage('`' . TABLE_PREFIX . 'project_documents` table dropped');
  280. } else {
  281. $this->printMessage('Warning: Failed to drop old documents table. MySQL said: ' . mysql_error(), true);
  282. } // if
  283. if (mysql_query('DROP TABLE IF EXISTS `' . TABLE_PREFIX . 'document_downloads', $this->database_connection)) {
  284. $this->printMessage('`' . TABLE_PREFIX . 'document_downloads` table dropped');
  285. } else {
  286. $this->printMessage('Warning: Failed to drop old document downloads table. MySQL said: ' . mysql_error(), true);
  287. } // if
  288. if (mysql_query('DROP TABLE IF EXISTS `' . TABLE_PREFIX . 'message_documents', $this->database_connection)) {
  289. $this->printMessage('`' . TABLE_PREFIX . 'message_documents` table dropped');
  290. } else {
  291. $this->printMessage('Warning: Failed to drop old message - documents table. MySQL said: ' . mysql_error(), true);
  292. } // if
  293. } // if
  294. return true;
  295. } // importProjectDocuments
  296. /**
  297. * This function will clean up application logs and remove entries related to objects that are removed in 0.7
  298. * (message comments and project documents)
  299. *
  300. * @param void
  301. * @return null
  302. */
  303. function cleanApplicationLogs() {
  304. $this->printMessage('Updating application logs');
  305. mysql_query(sprintf("DELETE FROM `%sapplication_logs` WHERE `rel_object_manager` = '%s'", TABLE_PREFIX, 'MessageComments'));
  306. mysql_query(sprintf("DELETE FROM `%sapplication_logs` WHERE `rel_object_manager` = '%s'", TABLE_PREFIX, 'ProjectDocuments'));
  307. $this->printMessage('Application logs updated');
  308. } // cleanApplicationLogs
  309. /**
  310. * This function will configuration file
  311. *
  312. * @param void
  313. * @return null
  314. */
  315. function fixConfigFile() {
  316. $this->printMessage('Updating configuration file');
  317. $constants = array(
  318. 'DB_ADAPTER' => DB_ADAPTER,
  319. 'DB_HOST' => DB_HOST,
  320. 'DB_USER' => DB_USER,
  321. 'DB_PASS' => DB_PASS,
  322. 'DB_NAME' => DB_NAME,
  323. 'DB_PERSIST' => true,
  324. 'TABLE_PREFIX' => TABLE_PREFIX,
  325. 'ROOT_URL' => ROOT_URL,
  326. 'DEFAULT_LOCALIZATION' => DEFAULT_LOCALIZATION,
  327. 'DEBUG' => false,
  328. 'PRODUCT_VERSION' => $this->getVersionTo(),
  329. ); // array
  330. tpl_assign('config_file_constants', $constants);
  331. if (file_put_contents(INSTALLATION_PATH . '/config/config.php', tpl_fetch(get_template_path('config_file')))) {
  332. $this->printMessage('Configuration file updated');
  333. return true;
  334. } else {
  335. $this->printMessage('Failed to update configuration file', true);
  336. return false;
  337. } // if
  338. } // fixConfigFile
  339. } // OnionUpgradeScript
  340. ?>