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

/QuickApps/Controller/InstallController.php

http://github.com/QuickAppsCMS/QuickApps-CMS
PHP | 403 lines | 303 code | 59 blank | 41 comment | 45 complexity | a0e54a7951dd60481215a8d5521d306d MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-3.0
  1. <?php
  2. /**
  3. * Install Controller
  4. *
  5. * PHP version 5
  6. *
  7. * @package QuickApps.Controller
  8. * @version 1.0
  9. * @author Christopher Castro <chris@quickapps.es>
  10. * @link http://www.quickappscms.org
  11. */
  12. App::uses('Controller', 'Controller');
  13. class InstallController extends Controller {
  14. public $name = 'Install';
  15. public $uses = array();
  16. public $components = array('HookCollection', 'Session');
  17. public $helpers = array('HookCollection', 'Layout', 'Html', 'Form');
  18. private $__defaultDbConfig = array(
  19. 'name' => 'default',
  20. 'datasource'=> 'Database/Mysql',
  21. 'persistent'=> false,
  22. 'host'=> 'localhost',
  23. 'login'=> 'root',
  24. 'password'=> '',
  25. 'database'=> 'quickapps',
  26. 'schema'=> null,
  27. 'prefix'=> 'qa_',
  28. 'encoding' => 'UTF8',
  29. 'port' => '3306'
  30. );
  31. public function beforeFilter() {
  32. $this->viewClass = 'View';
  33. $this->layout = 'install';
  34. // already installed ?
  35. if (file_exists(ROOT . DS . 'Config' . DS . 'database.php') && file_exists(ROOT . DS . 'Config' . DS . 'install')) {
  36. $this->redirect('/');
  37. }
  38. if (!CakeSession::read('Config.language')) {
  39. Configure::write('Config.language', 'eng');
  40. }
  41. }
  42. /**
  43. * Step 0, Select language.
  44. *
  45. * @return void
  46. */
  47. public function index() {
  48. App::uses('I18n', 'I18n');
  49. if (isset($this->params['named']['lang']) && preg_match('/^[a-z]{3}$/', $this->params['named']['lang'])) {
  50. CakeSession::write('Config.language', $this->params['named']['lang']);
  51. $this->redirect('/install/license');
  52. }
  53. $Folder = new Folder(ROOT . DS . 'Locale' . DS);
  54. $langs = $Folder->read(true, false);
  55. $languages = array();
  56. foreach ($langs[0] as $l) {
  57. $file = ROOT . DS . 'Locale' . DS . $l . DS . 'LC_MESSAGES' . DS . 'default.po';
  58. if ($l != 'eng' && file_exists($file)) {
  59. $languages[$l] = array(
  60. 'welcome' => I18n::translate('Welcome to QuickApps CMS', null, null, 6, null, $l),
  61. 'action' => I18n::translate('Click here to install in English', null, null, 6, null, $l)
  62. );
  63. }
  64. }
  65. if (empty($languages)) {
  66. CakeSession::write('Config.language', 'eng');
  67. $this->redirect('/install/license');
  68. }
  69. $this->set('languages', $languages);
  70. }
  71. /**
  72. * Step 1, License agreement
  73. *
  74. * @return void
  75. */
  76. public function license() {
  77. if (isset($this->data['License'])) {
  78. $this->__stepSuccess('license');
  79. $this->redirect('/install/server_test');
  80. }
  81. }
  82. /**
  83. * Step 2, Server test
  84. *
  85. * @return void
  86. */
  87. public function server_test() {
  88. if (!$this->__stepSuccess('license', true)) {
  89. $this->redirect('/install/license');
  90. }
  91. if (!empty($this->data['Test'])) {
  92. $this->__stepSuccess('server_test');
  93. $this->redirect('/install/database');
  94. }
  95. $tests = array(
  96. 'php' => array(
  97. 'test' => version_compare(PHP_VERSION, '5.2.8', '>='),
  98. 'msg' => __t('Your php version is not supported. check that your version is 5.2.8 or newer.')
  99. ),
  100. 'mysql' => array(
  101. 'test' => (extension_loaded('mysql') || extension_loaded('mysqli')),
  102. 'msg' => __t('MySQL extension is not loaded on your server.')
  103. ),
  104. 'no_safe_mode' => array(
  105. 'test' => (ini_get('safe_mode') == false || ini_get('safe_mode') == '' || strtolower(ini_get('safe_mode')) == 'off'),
  106. 'msg' => __t('Your server has SafeMode on, please turn it off before continuing.')
  107. ),
  108. 'tmp_writable' => array(
  109. 'test' => is_writable(TMP),
  110. 'msg' => __t('tmp folder is not writable.')
  111. ),
  112. 'cache_writable' => array(
  113. 'test' => is_writable(TMP . 'cache'),
  114. 'msg' => __t('tmp/cache folder is not writable.')
  115. ),
  116. 'installer_writable' => array(
  117. 'test' => is_writable(TMP . 'cache' . DS . 'installer'),
  118. 'msg' => __t('tmp/cache/installer folder is not writable.')
  119. ),
  120. 'models_writable' => array(
  121. 'test' => is_writable(TMP . 'cache' . DS . 'models'),
  122. 'msg' => __t('tmp/cache/models folder is not writable.')
  123. ),
  124. 'persistent_writable' => array(
  125. 'test' => is_writable(TMP . 'cache' . DS . 'persistent'),
  126. 'msg' => __t('tmp/cache/persistent folder is not writable.')
  127. ),
  128. 'i18n_writable' => array(
  129. 'test' => is_writable(TMP . 'cache' . DS . 'i18n'),
  130. 'msg' => __t('tmp/cache/i18n folder is not writable.')
  131. ),
  132. 'Config_writable' => array(
  133. 'test' => is_writable(ROOT . DS . 'Config'),
  134. 'msg' => __t('Config folder is not writable.')
  135. ),
  136. 'core.php_writable' => array(
  137. 'test' => is_writable(ROOT . DS . 'Config' . DS . 'core.php'),
  138. 'msg' => __t('Config/core.php file is not writable.')
  139. )
  140. );
  141. $results = array_unique(Hash::extract($tests, '{s}.test'));
  142. if (!(count($results) === 1 && $results[0] === true)) {
  143. $this->set('success', false);
  144. $this->set('tests', $tests);
  145. } else {
  146. $this->set('success', true);
  147. }
  148. }
  149. /**
  150. * Step 3, Database
  151. *
  152. * @return void
  153. */
  154. public function database() {
  155. if (!$this->__stepSuccess(array('license', 'server_test'), true)) {
  156. $this->redirect('/install/license');
  157. }
  158. if (!empty($this->data)) {
  159. App::uses('ConnectionManager', 'Model');
  160. $data = $this->data;
  161. $data['datasource'] = 'Database/Mysql';
  162. $data['persistent'] = false;
  163. $data = Hash::merge($this->__defaultDbConfig, $data);
  164. if ($this->__writeDatabaseFile($data)) {
  165. if (!$this->__checkDatabaseConnection($data)) {
  166. $this->Session->setFlash(__t('Could not connect to database.'), 'default', 'error');
  167. $this->__removeDatabaseFile();
  168. return;
  169. }
  170. $db = ConnectionManager::getDataSource('default');
  171. App::uses('Model', 'Model');
  172. App::uses('CakeSchema', 'Model');
  173. $schema = new CakeSchema(array('name' => 'QuickApps', 'file' => 'QuickApps.php'));
  174. $schema = $schema->load();
  175. $execute = array();
  176. foreach(array_keys($schema->tables) as $table) {
  177. $tableExists = $db->query("SHOW TABLES LIKE \"{$data['prefix']}{$table}\";");
  178. if (!empty($tableExists)) {
  179. $this->Session->setFlash(__t('A QuickApps CMS database already exists, please drop it or change the prefix.'), 'default', 'error');
  180. return;
  181. }
  182. }
  183. foreach($schema->tables as $table => $fields) {
  184. $create = $db->createSchema($schema, $table);
  185. $execute[] = $db->execute($create);
  186. $db->reconnect();
  187. }
  188. $dataPath = APP . 'Config' . DS . 'Schema' . DS . 'data' . DS;
  189. $modelDataObjects = App::objects('class', $dataPath, false);
  190. foreach ($modelDataObjects as $model) {
  191. include_once $dataPath . $model . '.php';
  192. $model = new $model;
  193. $Model = new Model(
  194. array(
  195. 'name' => get_class($model),
  196. 'table' => $model->table,
  197. 'ds' => 'default'
  198. )
  199. );
  200. $Model->cacheSources = false;
  201. if (isset($model->records) && !empty($model->records)) {
  202. foreach($model->records as $record) {
  203. $Model->create($record);
  204. $execute[] = $Model->save();
  205. }
  206. }
  207. }
  208. if (!in_array(false, array_values($execute), true)) {
  209. App::uses('Security', 'Utility');
  210. App::load('Security');
  211. $salt = Security::generateAuthKey();
  212. $seed = mt_rand() . mt_rand();
  213. $file = new File(ROOT . DS . 'Config' . DS . 'core.php');
  214. $contents = $file->read();
  215. $contents = preg_replace('/(?<=Configure::write\(\'Security.salt\', \')([^\' ]+)(?=\'\))/', $salt, $contents);
  216. $contents = preg_replace('/(?<=Configure::write\(\'Security.cipherSeed\', \')(\d+)(?=\'\))/', $seed, $contents);
  217. $file->write($contents);
  218. Cache::write('QaInstallDatabase', 'success'); // fix: Security keys change
  219. $this->redirect('/install/user_account');
  220. } else {
  221. $this->Session->setFlash(__t('Could not dump database.'), 'default', 'error');
  222. }
  223. } else {
  224. $this->Session->setFlash(__t('Could not write database.php file.'), 'default', 'error');
  225. }
  226. }
  227. }
  228. /**
  229. * Step 4, User account
  230. *
  231. * @return void
  232. */
  233. public function user_account() {
  234. if (Cache::read('QaInstallDatabase') == 'success' ||
  235. $this->__stepSuccess(array('license', 'server_test', 'database'), true)
  236. ) {
  237. $this->__stepSuccess('license');
  238. $this->__stepSuccess('server_test');
  239. $this->__stepSuccess('database');
  240. Cache::delete('QaInstallDatabase');
  241. } else {
  242. $this->redirect('/install/license');
  243. }
  244. if (isset($this->data['User'])) {
  245. $this->loadModel('User.User');
  246. $data = $this->data;
  247. $data['User']['status'] = 1;
  248. $data['Role']['Role'] = array(1);
  249. if ($this->User->save($data)) {
  250. $this->__stepSuccess('user_account');
  251. $this->redirect('/install/finish');
  252. } else {
  253. $errors = '';
  254. foreach ($this->User->invalidFields() as $field => $error) {
  255. $errors .= "<b>{$field}:</b> {$error}<br/>";
  256. }
  257. $this->Session->setFlash(
  258. '<b>' . __t('Could not create new user, please try again.') . "</b><br/>" .
  259. $errors
  260. , 'default', 'error');
  261. }
  262. }
  263. }
  264. /**
  265. * Step 5, Finish
  266. *
  267. * @return void
  268. */
  269. public function finish() {
  270. if (!$this->__stepSuccess(array('license', 'server_test', 'database', 'user_account'), true)) {
  271. $this->redirect('/install/license');
  272. }
  273. App::import('Utility', 'File');
  274. $file = new File(ROOT . DS . 'Config' . DS . 'install', true);
  275. if ($file->write(time())) {
  276. $this->__stepSuccess('finish');
  277. $this->Session->delete('QaInstall');
  278. CakeSession::write('Config.language', 'eng');
  279. $this->redirect('/admin');
  280. } else {
  281. $this->Session->setFlash(__t("Could not write 'install' file. Check file/folder permissions and refresh this page."), 'default', 'error');
  282. }
  283. }
  284. private function __writeDatabaseFile($data) {
  285. App::import('Utility', 'File');
  286. if (!copy(APP . 'Config' . DS . 'database.php.install', ROOT . DS . 'Config' . DS . 'database.php')) {
  287. return false;
  288. }
  289. $file = new File(ROOT . DS . 'Config' . DS . 'database.php', true);
  290. $dbSettings = $file->read();
  291. $dbSettings = str_replace(
  292. array(
  293. '{db_datasource}',
  294. '{db_persistent}',
  295. '{db_host}',
  296. '{db_login}',
  297. '{db_password}',
  298. '{db_database}',
  299. '{db_prefix}'
  300. ),
  301. array(
  302. $data['datasource'],
  303. ($data['persistent'] ? 'true' : 'false'),
  304. $data['host'],
  305. $data['login'],
  306. $data['password'],
  307. $data['database'],
  308. $data['prefix']
  309. ),
  310. $dbSettings
  311. );
  312. $r = $file->write($dbSettings);
  313. $file->close();
  314. return $r;
  315. }
  316. private function __removeDatabaseFile() {
  317. @unlink(ROOT . DS . 'Config' . DS . 'database.php');
  318. }
  319. private function __checkDatabaseConnection($data) {
  320. $MySQLConn = @mysql_connect(
  321. $data['host'] . ':' . $data['port'],
  322. $data['login'],
  323. $data['password'],
  324. true
  325. );
  326. return @mysql_select_db($data['database'], $MySQLConn);
  327. }
  328. private function __stepSuccess($step, $check = false) {
  329. if (!$check) {
  330. return $this->Session->write("QaInstall.{$step}", 'success');
  331. }
  332. if (is_array($step)) {
  333. foreach ($step as $s) {
  334. if (!$this->Session->check("QaInstall.{$s}")) {
  335. return false;
  336. }
  337. }
  338. return true;
  339. } else {
  340. return $this->Session->check("QaInstall.{$step}");
  341. }
  342. return false;
  343. }
  344. }