PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/installwizard/installWizard.php

http://github.com/jelix/jelix
PHP | 376 lines | 257 code | 63 blank | 56 comment | 82 complexity | 13132e98c3675fc5dcdc29ddc73bebbd MD5 | raw file
Possible License(s): BSD-3-Clause, JSON, GPL-3.0, LGPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * Installation wizard
  4. *
  5. * @package InstallWizard
  6. * @author Laurent Jouanneau
  7. * @copyright 2010-2015 Laurent Jouanneau
  8. * @link http://jelix.org
  9. * @licence GNU General Public Licence see LICENCE file or http://www.gnu.org/licenses/gpl.html
  10. */
  11. require(__DIR__.'/installWizardPage.php');
  12. /**
  13. * main class of the wizard
  14. *
  15. */
  16. class installWizard {
  17. protected $config;
  18. protected $configPath;
  19. protected $lang = 'en';
  20. protected $pages = array();
  21. protected $customPath = '';
  22. protected $tempPath = '';
  23. protected $stepName = "";
  24. protected $locales = array();
  25. /**
  26. * @var \Jelix\Castor\Config
  27. */
  28. protected $tplConfig;
  29. /**
  30. * @param string $config an ini file for the installation
  31. * should contain this parameter:
  32. * -
  33. */
  34. function __construct($configFile) {
  35. $this->configPath = $configFile;
  36. session_start();
  37. date_default_timezone_set("Europe/Paris");
  38. }
  39. /**
  40. * read the configuration file
  41. */
  42. protected function readConfiguration() {
  43. $conf = parse_ini_file($this->configPath, true, INI_SCANNER_TYPED);
  44. if (!$conf)
  45. throw new Exception('Impossible to read the configuration file');
  46. $this->config = $conf;
  47. if (isset($this->config['supportedLang'])) {
  48. $this->config['supportedLang'] = preg_split('/ *, */',$this->config['supportedLang']);
  49. }
  50. else
  51. $this->config['supportedLang'] = array('en');
  52. }
  53. /**
  54. * read and prepare all paths of pages, of temp dir etc.
  55. */
  56. protected function initPath() {
  57. $list = preg_split('/ *, */',$this->config['pagesPath']);
  58. $basepath = dirname($this->configPath).'/';
  59. foreach($list as $k=>$path){
  60. if(trim($path) == '') continue;
  61. $p = realpath($basepath.$path);
  62. if ($p== '' || !file_exists($p))
  63. throw new Exception ('The path, '.$path.' given in the configuration doesn\'t exist !');
  64. if (substr($p,-1) !='/')
  65. $p.='/';
  66. if ($handle = opendir($p)) {
  67. while (false !== ($f = readdir($handle))) {
  68. if ($f[0] != '.' && is_dir($p.$f) && isset($this->config[$f.'.step'])) {
  69. $this->pages[$f] = $p.$f.'/';
  70. }
  71. }
  72. closedir($handle);
  73. }
  74. }
  75. if (isset($this->config['customPath']) && $this->config['customPath'] != '') {
  76. $this->customPath = realpath($basepath.$this->config['customPath']);
  77. if ($this->customPath)
  78. $this->customPath .= '/';
  79. }
  80. if (isset($this->config['tempPath']) && $this->config['tempPath'] != '') {
  81. $this->tempPath = realpath($basepath.$this->config['tempPath']);
  82. if (!$this->tempPath)
  83. throw new Exception("no temp directory");
  84. if (!is_writable($this->tempPath))
  85. throw new Exception("The temp directory ".$this->config['tempPath']." is not writable. Change the rights on this directory to allow the web server to write in it.");
  86. $this->tempPath .= '/';
  87. }
  88. else
  89. throw new Exception("no temp directory");
  90. }
  91. /**
  92. * filled a __previous variable into data of each step.
  93. * @return string the name of the last step
  94. */
  95. protected function initPrevious($step='', $previousStep='') {
  96. if ($step == '') {
  97. if (isset($this->config['start']))
  98. $step = $this->config['start'];
  99. else
  100. return '';
  101. }
  102. if (!isset($this->pages[$step]) || !isset($this->config[$step.'.step'])) {
  103. return '';
  104. }
  105. if (isset($this->config[$step.'.step']['__previous'])) {
  106. return '';
  107. }
  108. if (isset($this->config[$step.'.step']['noprevious']) && $this->config[$step.'.step']['noprevious'])
  109. $this->config[$step.'.step']['__previous'] = '';
  110. else
  111. $this->config[$step.'.step']['__previous'] = $previousStep;
  112. if (!isset($this->config[$step.'.step']['next'])) {
  113. return $step;
  114. }
  115. $last = '';
  116. if (is_array($this->config[$step.'.step']['next'])) {
  117. foreach($this->config[$step.'.step']['next'] as $next) {
  118. $rv = $this->initPrevious($next, $step);
  119. if ($rv != '')
  120. $last = $rv;
  121. }
  122. }
  123. else
  124. $last = $this->initPrevious($this->config[$step.'.step']['next'], $step);
  125. return $last;
  126. }
  127. /**
  128. * setup the language by analysing the lang of the browser
  129. */
  130. protected function guessLanguage($lang = '') {
  131. if($lang == '' && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
  132. $languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
  133. foreach($languages as $bl){
  134. // pour les user-agents qui livrent un code internationnal
  135. if(preg_match("/^([a-zA-Z]{2})(?:[-_]([a-zA-Z]{2}))?(;q=[0-9]\\.[0-9])?$/",$bl,$match)){
  136. $lang = strtolower($match[1]);
  137. break;
  138. }
  139. }
  140. }elseif(preg_match("/^([a-zA-Z]{2})(?:[-_]([a-zA-Z]{2}))?$/",$lang,$match)){
  141. $lang = strtolower($match[1]);
  142. }
  143. if($lang == '' || !in_array($lang, $this->config['supportedLang'])){
  144. $lang = 'en';
  145. }
  146. return $lang;
  147. }
  148. /**
  149. * retrieve the name of the current step
  150. * @return string the name
  151. */
  152. protected function getStepName() {
  153. if (isset($_REQUEST['step'])) {
  154. $stepname = $_REQUEST['step'];
  155. }
  156. elseif (isset($this->config['start'])) {
  157. $stepname = $this->config['start'];
  158. }
  159. else {
  160. throw new Exception('No step start in the configuration');
  161. }
  162. if (!isset($this->pages[$stepname])) {
  163. throw new Exception('Unknow step');
  164. }
  165. return $stepname;
  166. }
  167. /**
  168. * return the name of the next step after the current page
  169. * @param installWizardPage $page the current page
  170. * @param integer $result the return code of the process method of the current page
  171. * @return string the name
  172. */
  173. protected function getNextStep($page, $result=0) {
  174. if (is_array($page->config['next'])) {
  175. if (is_numeric($result))
  176. $nextStep = $page->config['next'][$result];
  177. else
  178. $nextStep = $page->config['next'][0];
  179. }
  180. else
  181. $nextStep = $page->config['next'];
  182. return $nextStep;
  183. }
  184. function run ($isAlreadyDone = false) {
  185. try {
  186. $this->readConfiguration();
  187. $this->initPath();
  188. $laststep = $this->initPrevious();
  189. $this->lang = $this->guessLanguage();
  190. if ($isAlreadyDone && !isset($_SESSION['__install__wizard'])) {
  191. if (isset($this->config['onalreadydone']))
  192. $laststep = $this->config['onalreadydone'];
  193. if ($laststep != '' && isset($this->pages[$laststep])) {
  194. $this->stepName = $laststep;
  195. }
  196. else {
  197. throw new Exception("Application is installed. The script cannot be runned.");
  198. }
  199. }
  200. else {
  201. if (!isset($_SESSION['__install__wizard']) && !$isAlreadyDone)
  202. $_SESSION['__install__wizard'] = true;
  203. $this->stepName = $this->getStepName();
  204. }
  205. $this->tplConfig = new \Jelix\Castor\Config($this->tempPath);
  206. $this->tplConfig->setLang($this->lang);
  207. $this->tplConfig->localesGetter = array($this, 'getLocale');
  208. $page = $this->loadPage();
  209. if (isset($_POST['doprocess']) && $_POST['doprocess'] == "1") {
  210. //if ($isAlreadyDone)
  211. // $result = true;
  212. //else
  213. $result = $page->process();
  214. if ($result !== false) {
  215. header("location: ?step=".$this->getNextStep($page, $result));
  216. exit(0);
  217. }
  218. }
  219. $tpl = new \Jelix\Castor\Castor($this->tplConfig);
  220. $tpl->assign($page->config);
  221. $tpl->assign($page->getErrors());
  222. $tpl->assign('appname', isset($this->config['appname'])?$this->config['appname']:'');
  223. $continue = $page->show($tpl);
  224. $content = $tpl->fetch($this->stepName.'.tpl', 'html');
  225. $this->showMainTemplate($page, $content, $continue);
  226. if ($laststep == $this->stepName) {
  227. session_destroy();
  228. }
  229. } catch (Exception $e) {
  230. $error = $e->getMessage();
  231. header("HTTP/1.1 500 Application error");
  232. if ($this->customPath && file_exists($this->customPath.'error.php'))
  233. require($this->customPath.'error.php');
  234. else
  235. require(__DIR__.'/error.php');
  236. exit(1);
  237. }
  238. }
  239. protected function loadPage() {
  240. $stepname = $this->stepName;
  241. // load the class which run the step
  242. require($this->pages[$stepname].$stepname.'.page.php');
  243. $class = $stepname.'WizPage';
  244. if (!class_exists($stepname.'WizPage'))
  245. throw new Exception ('No class for the given step');
  246. // load the locales
  247. $this->loadLocales($stepname, $stepname);
  248. // load the template
  249. $tplfile = $this->getRealPath($stepname, $stepname.'.tpl');
  250. if ($tplfile === false)
  251. throw new Exception ("No template file for the given step");
  252. $this->tplConfig->templatePath = dirname($tplfile).'/';
  253. $page = new $class($this->config[$stepname.'.step'], $this->locales);
  254. return $page;
  255. }
  256. protected function showMainTemplate($page, $content, $continue) {
  257. $filename = "wiz_layout.tpl";
  258. $path = $this->getRealPath('', $filename);
  259. $this->tplConfig->templatePath = dirname($path).'/';
  260. $this->loadLocales('', 'wiz_layout');
  261. $conf = $this->config[$this->stepName.'.step'];
  262. $tpl = new \Jelix\Castor\Castor($this->tplConfig);
  263. $tpl->assign('title', $page->getLocale($page->title));
  264. if (isset($conf['messageHeader']))
  265. $tpl->assign('messageHeader', $conf['messageHeader']);
  266. else
  267. $tpl->assign('messageHeader', '');
  268. if (isset($conf['messageFooter']))
  269. $tpl->assign('messageFooter', $conf['messageFooter']);
  270. else
  271. $tpl->assign('messageFooter', '');
  272. $tpl->assign ('MAIN', $content);
  273. $tpl->assign (array_merge(array('enctype'=>''),$conf));
  274. $tpl->assign ('stepname', $this->stepName);
  275. $tpl->assign ('lang', $this->lang);
  276. $tpl->assign('next', ($continue && isset($conf['next'])));
  277. $tpl->assign('previous', isset($conf['__previous'])?$conf['__previous']:'');
  278. $tpl->assign('appname', isset($this->config['appname'])?$this->config['appname']:'Application');
  279. $tpl->display($filename, 'html');
  280. }
  281. protected function getRealPath($stepname, $fileName) {
  282. if ($this->customPath) {
  283. if (file_exists($this->customPath.$fileName))
  284. return $this->customPath.$fileName;
  285. }
  286. if ($stepname)
  287. $path = $this->pages[$stepname];
  288. else
  289. $path = __DIR__."/";
  290. if (file_exists($path.$fileName))
  291. return $path.$fileName;
  292. return false;
  293. }
  294. protected function loadLocales($stepname, $prefix) {
  295. $localeFile = $this->getRealPath($stepname, $prefix.'.'.$this->lang.'.php');
  296. if ($localeFile === false && $this->lang != 'en')
  297. $localeFile = $this->getRealPath($stepname, $prefix.'.en.php');
  298. if ($localeFile === false)
  299. throw new Exception ("No lang file for the given step");
  300. require($localeFile); // load a php array $locales
  301. $this->locales = $locales;
  302. }
  303. /**
  304. * function for the template engine, to retrieve a localized string
  305. * @param string $name the key of the localized string
  306. * @return string the localized string or the given key if it doesn't exists
  307. */
  308. public function getLocale($name) {
  309. if (isset($this->locales[$name]))
  310. return $this->locales[$name];
  311. else return $name;
  312. }
  313. }