install_upgrade.lib.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. <?php
  2. /*
  3. ==============================================================================
  4. Dokeos - elearning and course management software
  5. Copyright (c) 2004-2005 Dokeos S.A.
  6. Copyright (c) Roan Embrechts, Vrije Universiteit Brussel
  7. Copyright (c) Bart Mollet, Hogeschool Gent
  8. For a full list of contributors, see "credits.txt".
  9. The full license can be read in "license.txt".
  10. This program is free software; you can redistribute it and/or
  11. modify it under the terms of the GNU General Public License
  12. as published by the Free Software Foundation; either version 2
  13. of the License, or (at your option) any later version.
  14. See the GNU General Public License for more details.
  15. Contact address: Dokeos, 44 rue des palais, B-1030 Brussels, Belgium
  16. Mail: info@dokeos.com
  17. ==============================================================================
  18. */
  19. /**
  20. ==============================================================================
  21. * This file contains functions used by the install and upgrade scripts.
  22. * The current functions are used to
  23. * - fill existing tables with data;
  24. * - write a .htaccess file in the courses folder for extra security;
  25. * - write the Dokeos config file containing important settings like database names
  26. * and paswords and other options.
  27. *
  28. * Ideas for future additions:
  29. * - a function get_old_version_settings to retrieve the config file settings
  30. * of older versions before upgrading.
  31. ==============================================================================
  32. */
  33. /*
  34. ==============================================================================
  35. CONSTANTS
  36. ==============================================================================
  37. */
  38. define("DOKEOS_MAIN_DATABASE_FILE", "dokeos_main.sql");
  39. define("LANGUAGE_DATA_FILENAME", "language_data.csv");
  40. define("COUNTRY_DATA_FILENAME", "country_data.csv");
  41. define("SETTING_OPTION_DATA_FILENAME", "setting_option_data.csv");
  42. define("SETTING_CURRENT_DATA_FILENAME", "setting_current_data.csv");
  43. define("COURSES_HTACCESS_FILENAME", "htaccess.dist");
  44. define("DOKEOS_CONFIG_FILENAME", "configuration.dist.php");
  45. /*
  46. ==============================================================================
  47. DATABASE FUNCTIONS
  48. ==============================================================================
  49. */
  50. /**
  51. * We assume this function is called from install scripts that reside inside
  52. * the install folder.
  53. */
  54. function set_file_folder_permissions()
  55. {
  56. @chmod('.',0755); //set permissions on install dir
  57. @chmod('..',0755); //set permissions on parent dir of install dir
  58. @chmod('language_data.csv',0755);
  59. @chmod('setting_current_data.csv',0755);
  60. @chmod('setting_option_data.csv',0755);
  61. @chmod('country_data.csv.csv',0755);
  62. }
  63. /**
  64. * Fills the language table with all available languages.
  65. */
  66. function fill_language_table($language_table)
  67. {
  68. $file_path = dirname(__FILE__).'/'.LANGUAGE_DATA_FILENAME;
  69. $add_language_sql = "LOAD DATA INFILE '".mysql_real_escape_string($file_path)."' INTO TABLE $language_table FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\'';";
  70. @ mysql_query($add_language_sql);
  71. }
  72. /**
  73. * Fills the current settings table with the Dokeos default settings.
  74. * After using the LOAD DATA INFILE instruction, the database stores some
  75. * variables literally as '$variable'. The instructions after that replace
  76. * that literal by the actual value of the variable.
  77. */
  78. function fill_current_settings_table($current_settings_table, $installation_settings)
  79. {
  80. $institutionForm = $installation_settings['institution_form'];
  81. $institutionUrlForm = $installation_settings['institution_url_form'];
  82. $campusForm = $installation_settings['campus_form'];
  83. $emailForm = $installation_settings['email_form'];
  84. $adminLastName = $installation_settings['admin_last_name'];
  85. $adminFirstName = $installation_settings['admin_first_name'];
  86. $languageForm = $installation_settings['language_form'];
  87. $allowSelfReg = $installation_settings['allow_self_registration'];
  88. $allowSelfRegProf = $installation_settings['allow_teacher_self_registration'];
  89. $adminPhoneForm = $installation_settings['admin_phone_form'];
  90. $file_path = dirname(__FILE__).'/'.SETTING_CURRENT_DATA_FILENAME;
  91. $add_setting_current_sql = "LOAD DATA INFILE '".mysql_real_escape_string($file_path)."' INTO TABLE $current_settings_table FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\'';";
  92. @ mysql_query($add_setting_current_sql);
  93. //replace literal '$variable' by the contents of variable $variable
  94. mysql_query("UPDATE $current_settings_table SET selected_value='$institutionForm' WHERE selected_value='\$institutionForm'");
  95. mysql_query("UPDATE $current_settings_table SET selected_value='$institutionUrlForm' WHERE selected_value='\$institutionUrlForm'");
  96. mysql_query("UPDATE $current_settings_table SET selected_value='$campusForm' WHERE selected_value='\$campusForm'");
  97. mysql_query("UPDATE $current_settings_table SET selected_value='$emailForm' WHERE selected_value='\$emailForm'");
  98. mysql_query("UPDATE $current_settings_table SET selected_value='$adminLastName' WHERE selected_value='\$adminLastName'");
  99. mysql_query("UPDATE $current_settings_table SET selected_value='$adminFirstName' WHERE selected_value='\$adminFirstName'");
  100. mysql_query("UPDATE $current_settings_table SET selected_value='$languageForm' WHERE selected_value='\$languageForm'");
  101. mysql_query("UPDATE $current_settings_table SET selected_value='".trueFalse($allowSelfReg)."' WHERE selected_value='\$allowSelfReg'");
  102. mysql_query("UPDATE $current_settings_table SET selected_value='".trueFalse($allowSelfRegProf)."' WHERE selected_value='\$allowSelfRegProf'");
  103. mysql_query("UPDATE $current_settings_table SET selected_value='$adminPhoneForm' WHERE selected_value='\$adminPhoneForm'");
  104. }
  105. /**
  106. * Fills the table with the possible options for all settings.
  107. */
  108. function fill_settings_options_table($settings_options_table)
  109. {
  110. $file_path = dirname(__FILE__).'/'.SETTING_OPTION_DATA_FILENAME;
  111. $add_setting_option_sql = "LOAD DATA INFILE '".mysql_real_escape_string($file_path)."' INTO TABLE $settings_options_table FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\'';";
  112. @ mysql_query($add_setting_option_sql);
  113. }
  114. /**
  115. * Fills the countries table with a list of countries.
  116. */
  117. function fill_track_countries_table($track_countries_table)
  118. {
  119. $file_path = dirname(__FILE__).'/'.COUNTRY_DATA_FILENAME;
  120. $add_country_sql = "LOAD DATA INFILE '".mysql_real_escape_string($file_path)."' INTO TABLE $track_countries_table FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\'';";
  121. @ mysql_query($add_country_sql);
  122. }
  123. /**
  124. * Add's a .htaccess file to the courses directory
  125. * @param string $url_append The path from your webroot to your dokeos root
  126. */
  127. function write_courses_htaccess_file($url_append)
  128. {
  129. $file_path = dirname(__FILE__).'/'.COURSES_HTACCESS_FILENAME;
  130. $content = file_get_contents($file_path);
  131. $content = str_replace('{DOKEOS_URL_APPEND_PATH}', $url_append, $content);
  132. $fp = @ fopen('../../courses/.htaccess', 'w');
  133. if ($fp)
  134. {
  135. fwrite($fp, $content);
  136. return fclose($fp);
  137. }
  138. return false;
  139. }
  140. /**
  141. * Write the main Dokeos config file
  142. * @param string $path Path to the config file
  143. */
  144. function write_dokeos_config_file($path)
  145. {
  146. global $dokeos_version;
  147. global $dbHostForm;
  148. global $dbUsernameForm;
  149. global $dbPassForm;
  150. global $enableTrackingForm;
  151. global $singleDbForm;
  152. global $dbPrefixForm;
  153. global $dbNameForm;
  154. global $dbStatsForm;
  155. global $dbScormForm;
  156. global $dbUserForm;
  157. global $urlForm;
  158. global $pathForm;
  159. global $urlAppendPath;
  160. global $languageForm;
  161. global $encryptPassForm;
  162. global $installType;
  163. global $updatePath;
  164. $rootSys = realpath($pathForm).'/';
  165. $garbageDir = realpath('../garbage/').'/';
  166. //change paths if updating
  167. //if($installType=='update'){
  168. // $rootSys = $updatePath;
  169. // $garbageDir = realpath($updatePath.'claroline/garbage/').'/';
  170. // $urlAppendPath = '';
  171. //}
  172. $file_path = dirname(__FILE__).'/'.DOKEOS_CONFIG_FILENAME;
  173. $content = file_get_contents($file_path);
  174. $config['{DATE_GENERATED}'] = date('r');
  175. $config['{DATABASE_HOST}'] = $dbHostForm;
  176. $config['{DATABASE_USER}'] = $dbUsernameForm;
  177. $config['{DATABASE_PASSWORD}'] = $dbPassForm;
  178. $config['{TRACKING_ENABLED}'] = trueFalse($enableTrackingForm);
  179. $config['{SINGLE_DATABASE}'] = trueFalse($singleDbForm);
  180. $config['{COURSE_TABLE_PREFIX}'] = ($singleDbForm ? 'crs_' : '');
  181. $config['{DATABASE_GLUE}'] = ($singleDbForm ? '_' : '`.`');
  182. $config['{DATABASE_PREFIX}'] = $dbPrefixForm;
  183. $config['{DATABASE_MAIN}'] = $dbNameForm;
  184. $config['{DATABASE_STATS}'] = ($singleDbForm ? $dbNameForm : $dbStatsForm);
  185. $config['{DATABASE_SCORM}'] = ($singleDbForm ? $dbNameForm : $dbScormForm);
  186. $config['{DATABASE_PERSONAL}'] =($singleDbForm ? $dbNameForm : $dbUserForm);
  187. $config['{ROOT_WEB}'] = $urlForm;
  188. $config['{ROOT_SYS}'] = str_replace('\\', '/', $rootSys);
  189. $config['{URL_APPEND_PATH}'] = $urlAppendPath;
  190. $config['{GARBAGE_DIR}'] = str_replace("\\", '/', $garbageDir);
  191. $config['{PLATFORM_LANGUAGE}'] = $languageForm;
  192. $config['{SECURITY_KEY}'] = md5(uniqid(rand().time()));
  193. $config['{ENCRYPT_PASSWORD}'] = trueFalse($encryptPassForm);
  194. foreach ($config as $key => $value)
  195. {
  196. $content = str_replace($key, $value, $content);
  197. }
  198. $fp = @ fopen($path, 'w');
  199. if (!$fp)
  200. {
  201. echo '<b><font color="red">Your script doesn\'t have write access to the config directory</font></b><br />
  202. <em>('.str_replace('\\', '/', realpath($path)).')</em><br /><br />
  203. You probably do not have write access on Dokeos root directory,
  204. i.e. you should <em>CHMOD 777</em> or <em>755</em> or <em>775</em>.<br /><br />
  205. Your problems can be related on two possible causes:<br />
  206. <ul>
  207. <li>Permission problems.<br />Try initially with <em>chmod -R 777</em> and increase restrictions gradually.</li>
  208. <li>PHP is running in <a href="http://www.php.net/manual/en/features.safe-mode.php" target="_blank">Safe-Mode</a>. If possible, try to switch it off.</li>
  209. </ul>
  210. <a href="http://www.dokeos.com/forum/" target="_blank">Read about this problem in Support Forum</a><br /><br />
  211. Please go back to step 5.
  212. <p><input type="submit" name="step5" value="&lt; Back" /></p>
  213. </td></tr></table></form></body></html>';
  214. exit ();
  215. }
  216. fwrite($fp, $content);
  217. fclose($fp);
  218. }
  219. /**
  220. * Creates the structure of the main database and fills it
  221. * with data. Placeholder symbols in the main database file
  222. * have to be replaced by the settings entered by the user during installation.
  223. *
  224. * @param array $installation_settings list of settings entered by the user
  225. */
  226. function load_main_database($installation_settings)
  227. {
  228. $dokeos_main_sql_file_string = file_get_contents(DOKEOS_MAIN_DATABASE_FILE);
  229. //replace symbolic parameters with user-specified values
  230. foreach ($installation_settings as $key => $value)
  231. {
  232. $dokeos_main_sql_file_string = str_replace($key, mysql_real_escape_string($value), $dokeos_main_sql_file_string);
  233. }
  234. //split in array of sql strings
  235. $sql_instructions = array();
  236. $success = split_sql_file($sql_instructions, $dokeos_main_sql_file_string);
  237. //execute the sql instructions
  238. $count = count($sql_instructions);
  239. for ($i = 0; $i < $count; $i++)
  240. {
  241. $this_sql_query = $sql_instructions[$i]['query'];
  242. mysql_query($this_sql_query);
  243. }
  244. }
  245. /**
  246. * Creates the structure of the stats database
  247. * @param string Name of the file containing the SQL script inside the install directory
  248. */
  249. function load_database_script($db_script)
  250. {
  251. $dokeos_sql_file_string = file_get_contents($db_script);
  252. //split in array of sql strings
  253. $sql_instructions = array();
  254. $success = split_sql_file($sql_instructions, $dokeos_sql_file_string);
  255. //execute the sql instructions
  256. $count = count($sql_instructions);
  257. for ($i = 0; $i < $count; $i++)
  258. {
  259. $this_sql_query = $sql_instructions[$i]['query'];
  260. mysql_query($this_sql_query);
  261. }
  262. }
  263. /**
  264. * Function copied and adapted from phpMyAdmin 2.6.0 PMA_splitSqlFile (also GNU GPL)
  265. *
  266. * Removes comment lines and splits up large sql files into individual queries
  267. *
  268. * Last revision: September 23, 2001 - gandon
  269. *
  270. * @param array the splitted sql commands
  271. * @param string the sql commands
  272. * @param integer the MySQL release number (because certains php3 versions
  273. * can't get the value of a constant from within a function)
  274. *
  275. * @return boolean always true
  276. *
  277. * @access public
  278. */
  279. function split_sql_file(&$ret, $sql)
  280. {
  281. // do not trim, see bug #1030644
  282. //$sql = trim($sql);
  283. $sql = rtrim($sql, "\n\r");
  284. $sql_len = strlen($sql);
  285. $char = '';
  286. $string_start = '';
  287. $in_string = FALSE;
  288. $nothing = TRUE;
  289. $time0 = time();
  290. for ($i = 0; $i < $sql_len; ++$i) {
  291. $char = $sql[$i];
  292. // We are in a string, check for not escaped end of strings except for
  293. // backquotes that can't be escaped
  294. if ($in_string) {
  295. for (;;) {
  296. $i = strpos($sql, $string_start, $i);
  297. // No end of string found -> add the current substring to the
  298. // returned array
  299. if (!$i) {
  300. $ret[] = $sql;
  301. return TRUE;
  302. }
  303. // Backquotes or no backslashes before quotes: it's indeed the
  304. // end of the string -> exit the loop
  305. else if ($string_start == '`' || $sql[$i-1] != '\\') {
  306. $string_start = '';
  307. $in_string = FALSE;
  308. break;
  309. }
  310. // one or more Backslashes before the presumed end of string...
  311. else {
  312. // ... first checks for escaped backslashes
  313. $j = 2;
  314. $escaped_backslash = FALSE;
  315. while ($i-$j > 0 && $sql[$i-$j] == '\\') {
  316. $escaped_backslash = !$escaped_backslash;
  317. $j++;
  318. }
  319. // ... if escaped backslashes: it's really the end of the
  320. // string -> exit the loop
  321. if ($escaped_backslash) {
  322. $string_start = '';
  323. $in_string = FALSE;
  324. break;
  325. }
  326. // ... else loop
  327. else {
  328. $i++;
  329. }
  330. } // end if...elseif...else
  331. } // end for
  332. } // end if (in string)
  333. // lets skip comments (/*, -- and #)
  334. else if (($char == '-' && $sql_len > $i + 2 && $sql[$i + 1] == '-' && $sql[$i + 2] <= ' ') || $char == '#' || ($char == '/' && $sql_len > $i + 1 && $sql[$i + 1] == '*')) {
  335. $i = strpos($sql, $char == '/' ? '*/' : "\n", $i);
  336. // didn't we hit end of string?
  337. if ($i === FALSE) {
  338. break;
  339. }
  340. if ($char == '/') $i++;
  341. }
  342. // We are not in a string, first check for delimiter...
  343. else if ($char == ';') {
  344. // if delimiter found, add the parsed part to the returned array
  345. $ret[] = array('query' => substr($sql, 0, $i), 'empty' => $nothing);
  346. $nothing = TRUE;
  347. $sql = ltrim(substr($sql, min($i + 1, $sql_len)));
  348. $sql_len = strlen($sql);
  349. if ($sql_len) {
  350. $i = -1;
  351. } else {
  352. // The submited statement(s) end(s) here
  353. return TRUE;
  354. }
  355. } // end else if (is delimiter)
  356. // ... then check for start of a string,...
  357. else if (($char == '"') || ($char == '\'') || ($char == '`')) {
  358. $in_string = TRUE;
  359. $nothing = FALSE;
  360. $string_start = $char;
  361. } // end else if (is start of string)
  362. elseif ($nothing) {
  363. $nothing = FALSE;
  364. }
  365. // loic1: send a fake header each 30 sec. to bypass browser timeout
  366. $time1 = time();
  367. if ($time1 >= $time0 + 30) {
  368. $time0 = $time1;
  369. header('X-pmaPing: Pong');
  370. } // end if
  371. } // end for
  372. // add any rest to the returned array
  373. if (!empty($sql) && preg_match('@[^[:space:]]+@', $sql)) {
  374. $ret[] = array('query' => $sql, 'empty' => $nothing);
  375. }
  376. return TRUE;
  377. } // end of the 'PMA_splitSqlFile()' function
  378. /**
  379. * Get an SQL file's contents
  380. *
  381. * This function bases its parsing on the pre-set format of the specific SQL files in
  382. * the install/upgrade procedure:
  383. * Lines starting with "--" are comments (but need to be taken into account as they also hold sections names)
  384. * Other lines are considered to be one-line-per-query lines (this is checked quickly by this function)
  385. * @param string File to parse (in the current directory)
  386. * @param string Section to return
  387. * @param boolean Print (true) or hide (false) error texts when they occur
  388. */
  389. function get_sql_file_contents($file,$section,$print_errors=true)
  390. {
  391. //check given parameters
  392. if(empty($file))
  393. {
  394. $error = "Missing name of file to parse in get_sql_file_contents()";
  395. if($print_errors) echo $error;
  396. return false;
  397. }
  398. if(!in_array($section,array('main','user','stats','scorm','course')))
  399. {
  400. $error = "Section '$section' is not authorized in get_sql_file_contents()";
  401. if($print_errors) echo $error;
  402. return false;
  403. }
  404. $filepath = getcwd().'/'.$file;
  405. if(!is_file($filepath) or !is_readable($filepath))
  406. {
  407. $error = "File $filepath not found or not readable in get_sql_file_contents()";
  408. if($print_errors) echo $error;
  409. return false;
  410. }
  411. //read the file in an array
  412. $file_contents = file($filepath);
  413. if(!is_array($file_contents) or count($file_contents)<1)
  414. {
  415. $error = "File $filepath looks empty in get_sql_file_contents()";
  416. if($print_errors) echo $error;
  417. return false;
  418. }
  419. //prepare the resulting array
  420. $section_contents = array();
  421. $record = false;
  422. foreach($file_contents as $index => $line)
  423. {
  424. if(substr($line,0,2) == '--')
  425. {
  426. //This is a comment. Check if section name, otherwise ignore
  427. $result = array();
  428. if(preg_match('/^-- xx([A-Z]*)xx/',$line,$result))
  429. { //we got a section name here
  430. if($result[1] == strtoupper($section))
  431. { //we have the section we are looking for, start recording
  432. $record = true;
  433. }
  434. else
  435. { //we have another section's header. If we were recording, stop now and exit loop
  436. if($record == true)
  437. {
  438. break;
  439. }
  440. $record = false;
  441. }
  442. }
  443. }else{
  444. if($record == true)
  445. {
  446. if(!empty($line)){
  447. $section_contents[] = $line;
  448. }
  449. }
  450. }
  451. }
  452. //now we have our section's SQL statements group ready, return
  453. return $section_contents;
  454. }
  455. ?>