install_upgrade.lib.php 19 KB

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