2 /************************************************************************
3 * Mailer v0.2.1-FINAL Start: 10/22/2009 *
4 * =================== Last change: 10/22/2009 *
6 * -------------------------------------------------------------------- *
7 * File : install-functions.php *
8 * -------------------------------------------------------------------- *
9 * Short description : Functions for installation procedure *
10 * -------------------------------------------------------------------- *
11 * Kurzbeschreibung : Funktionen fuer die Installationsroutine *
12 * -------------------------------------------------------------------- *
15 * $Tag:: 0.2.1-FINAL $ *
17 * -------------------------------------------------------------------- *
18 * Copyright (c) 2003 - 2009 by Roland Haeder *
19 * Copyright (c) 2009 - 2012 by Mailer Developer Team *
20 * For more information visit: http://mxchange.org *
22 * This program is free software; you can redistribute it and/or modify *
23 * it under the terms of the GNU General Public License as published by *
24 * the Free Software Foundation; either version 2 of the License, or *
25 * (at your option) any later version. *
27 * This program is distributed in the hope that it will be useful, *
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
30 * GNU General Public License for more details. *
32 * You should have received a copy of the GNU General Public License *
33 * along with this program; if not, write to the Free Software *
34 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
36 ************************************************************************/
38 // Some security stuff...
39 if ((!defined('__SECURITY')) || (!isInstallationPhase())) {
44 function initInstaller () {
45 // Initialize installer group array
46 $GLOBALS['installer_groups'] = array(
48 'base_path' => 'base_data',
49 'base_url' => 'base_data',
50 'main_title' => 'base_data',
51 'slogan' => 'base_data',
52 'webmaster' => 'base_data',
54 'mysql_host' => 'database_config',
55 'mysql_dbase' => 'database_config',
56 'mysql_prefix' => 'database_config',
57 'mysql_type' => 'database_config',
58 'mysql_login' => 'database_config',
59 'mysql_password1' => 'database_config',
60 'mysql_password2' => 'database_config',
62 'smtp_host' => 'smtp_config',
63 'smtp_user' => 'smtp_config',
64 'smtp_password1' => 'smtp_config',
65 'smtp_password2' => 'smtp_config',
67 'output_mode' => 'other_config',
68 'warn_no_pass' => 'other_config',
69 'write_footer' => 'other_config',
70 'enable_backlink' => 'other_config',
74 // Write the local config-local.php file from "template"
75 function doInstallWriteLocalConfigurationFile ($path) {
76 // Copy the config template and verify it
77 copyFileVerified(postRequestElement('spath') . 'inc/config-local.php.dist', postRequestElement('spath') . getCachePath() . 'config-local.php', 0644);
79 // Ok, all done. So we can write the config data to the php files
80 // Do only write these if they differ from auto-detected values
81 if (postRequestElement('spath') != getPath()) changeDataInLocalConfigurationFile('SERVER-PATH', "setConfigEntry('PATH', '", "');", postRequestElement('spath'), 0);
82 if (postRequestElement('burl') != getUrl()) changeDataInLocalConfigurationFile('HOST-URL', "setConfigEntry('URL', '", "');", postRequestElement('burl'), 0);
85 changeDataInLocalConfigurationFile('MAIN-TITLE', "setConfigEntry('MAIN_TITLE', '", "');", postRequestElement('title'), 0);
86 changeDataInLocalConfigurationFile('SLOGAN', "setConfigEntry('SLOGAN', '", "');", postRequestElement('slogan'), 0);
87 changeDataInLocalConfigurationFile('WEBMASTER', "setConfigEntry('WEBMASTER', '", "');", postRequestElement('email'), 0);
88 changeDataInLocalConfigurationFile('NULLPASS-WARNING', "setConfigEntry('WARN_NO_PASS', '", "');", postRequestElement('warn_no_pass'), 0);
89 changeDataInLocalConfigurationFile('WRITE-FOOTER', "setConfigEntry('WRITE_FOOTER', '", "');", postRequestElement('wfooter'), 0);
90 changeDataInLocalConfigurationFile('BACKLINK', "setConfigEntry('ENABLE_BACKLINK', '", "');", postRequestElement('blink'), 0);
91 // @TODO DEACTIVATED: changeDataInLocalConfigurationFile('OUTPUT-MODE', "setConfigEntry('OUTPUT_MODE', '", "');", postRequestElement('omode'), 0);
92 changeDataInLocalConfigurationFile('MYSQL-HOST', " 'host' => '", "',", postRequestElement('mysql','host'), 0);
93 changeDataInLocalConfigurationFile('MYSQL-DBASE', " 'dbase' => '", "',", postRequestElement('mysql','dbase'), 0);
94 changeDataInLocalConfigurationFile('MYSQL-LOGIN', " 'login' => '", "',", postRequestElement('mysql','login'), 0);
95 changeDataInLocalConfigurationFile('MYSQL-PASSWORD', " 'password' => '", "',", postRequestElement('mysql','pass1'), 0);
96 changeDataInLocalConfigurationFile('MYSQL-PREFIX', "setConfigEntry('_MYSQL_PREFIX', '", "');", postRequestElement('mysql','prefix'), 0);
97 changeDataInLocalConfigurationFile('TABLE-TYPE', "setConfigEntry('_TABLE_TYPE', '", "');", postRequestElement('mysql','type'), 0);
98 changeDataInLocalConfigurationFile('SMTP-HOSTNAME', "setConfigEntry('SMTP_HOSTNAME', '", "');", postRequestElement('smtp_host'), 0);
99 changeDataInLocalConfigurationFile('SMTP-USER', "setConfigEntry('SMTP_USER', '", "');", postRequestElement('smtp_user'), 0);
100 changeDataInLocalConfigurationFile('SMTP-PASSWORD', "setConfigEntry('SMTP_PASSWORD', '", "');", postRequestElement('smtp_pass1'), 0);
102 // Generate a long site-key and write it
103 changeDataInLocalConfigurationFile('SITE-KEY', "setConfigEntry('SITE_KEY', '", "');", generatePassword(50), 0);
105 // Script is now installed
106 changeDataInLocalConfigurationFile('INSTALLED', "setConfigEntry('MXCHANGE_INSTALLED', '", "');", 'Y', 0);
109 // Adds a given template with content to install output stream
110 function addTemplateToInstallContent ($template, $content = array()) {
112 $out = loadTemplate($template, TRUE, $content);
115 addToInstallContent($out);
118 // Add it to install content
119 function addToInstallContent ($out) {
121 if (!isset($GLOBALS['install_content'])) {
123 $GLOBALS['install_content'] = $out;
126 $GLOBALS['install_content'] .= $out;
130 // Somewhat getter for installer content
131 function getInstallerContent () {
133 if (isset($GLOBALS['install_content'])) {
135 $content = $GLOBALS['install_content'];
137 // Nothing found, this needs fixing
138 $content = displayMessage('{--INSTALLER_CONTENT_404--}', TRUE);
145 // Read a given SQL dump
146 function readSqlDump ($FQFN) {
148 $content = readFromFile($FQFN);
150 // Remove some unwanted chars
151 $content = str_replace(chr(13), '', $content);
152 $content = str_replace("\n\n", chr(10), $content);
154 // Return the content
158 // Generates the installer menu by simply loading another template
159 function generateInstallerMenu () {
160 // Load installer menu template
161 $OUT = loadTemplate('install_menu', TRUE);
163 // Return loaded content
167 // Generate the install footer navigation by simply loading another template
168 function generateInstallerFooterNavigation () {
169 // Load installer menu template
170 $OUT = loadTemplate('install_footer', TRUE);
172 // Return loaded content
176 // Generate an option list for database types for given default value
177 function generateInstallerDatabaseTypeOptions () {
178 return generateOptions(
180 array('MyISAM', 'InnoDB'),
181 array('{--INSTALLER_TABLE_TYPE_MYISAM--}', '{--INSTALLER_TABLE_TYPE_INNODB--}'),
182 getSession('mysql_type')
186 // Generate an option list for output mode types for given default value
187 function generateInstallerOutputModeOptions ($defaultValue) {
188 return generateOptions(
190 array('render', 'direct'),
191 array('{--INSTALLER_MODE_RENDER--}', '{--INSTALLER_MODE_DIRECT--}'),
196 // Checks whether we have an AJAX-enabled installer which defaults to red pill
197 function isAjaxInstaller () {
198 // Get the session data and compare it against 'ajax'
199 $isAjaxInstaller = (getSession('installer') == 'ajax');
202 return $isAjaxInstaller;
205 // Checks whether we have an plain installer which defaults to red pill
206 function isPlainInstaller () {
207 // Get the session data and compare it against 'plain'
208 $isPlainInstaller = (getSession('installer') == 'plain');
211 return $isPlainInstaller;
214 // Checks given key/value pair if it is valid by a call-back
215 function isInstallerDataValid (&$saveStatus, $key, $value) {
216 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value=' . $value . ' - ENTERED!');
217 // Generate call-back function based on given key
218 $callbackName = 'isInstaller' . capitalizeUnderscoreString($key) . 'Valid';
220 // Is the function there?
221 if (!function_exists($callbackName)) {
222 // Not found, which is not bad, but it means this data is always valid
223 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' not found. saveStatus[status]=' . $saveStatus['status'] . ', key=' . $key . ', value=' . $value);
225 // All fine (CAREFULL!)
230 $isValid = (bool) call_user_func($callbackName, $value);
233 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value=' . $value . ',isValid=' . intval($isValid));
234 if ($isValid === FALSE) {
235 // Then add it to saveStatus
236 array_push($saveStatus['failed_fields'], $key);
240 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value=' . $value . ',isValid=' . intval($isValid) . ' - EXIT!');
244 // Post-check on installer data
245 function doInstallerPostCheck ($currentTab, &$saveStatus) {
247 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'currentTab=' . $currentTab . ',saveStatus[status]=' . $saveStatus['status'] . ' - ENTERED!');
249 // Create the call-back function on 'tab'
250 $callbackName = 'isInstallerPost' . capitalizeUnderscoreString($currentTab) . 'Valid';
252 // Is the function there?
253 if (!function_exists($callbackName)) {
254 // Not found, which is not bad, but it means the post-check won't be run
255 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' not found. saveStatus[status]=' . $saveStatus['status'] . ', currentTab=' . $currentTab);
261 // Init 'tab-specific error message'
262 $GLOBALS['installer_post_error'][$currentTab] = '';
263 $GLOBALS['installer_failed_fields'][$currentTab] = array();
266 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Calling function ' . $callbackName . ',currentTab=' . $currentTab . ',saveStatus[status]=' . $saveStatus['status']);
269 $isValid = (bool) call_user_func($callbackName, $currentTab);
272 if (($isValid === FALSE) || (count($GLOBALS['installer_failed_fields'][$currentTab]) > 0)) {
273 // Then change status and message
274 $saveStatus['status'] = 'failed';
275 $saveStatus['message'] = '{%message,INSTALLER_POST_CHECK_' . strtoupper($currentTab) . '_FAILED=' . $GLOBALS['installer_post_error'][$currentTab] . '%}';
277 // Is there failed fields?
278 if (count($GLOBALS['installer_failed_fields'][$currentTab]) > 0) {
280 $saveStatus['failed_fields'] = merge_array($saveStatus['failed_fields'], $GLOBALS['installer_failed_fields'][$currentTab]);
285 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'currentTab=' . $currentTab . ',saveStatus[status]=' . $saveStatus['status'] . ' - EXIT!');
288 // Determines an installer group by given key
289 function determineInstallerGroupByKey ($key) {
291 if (!isset($GLOBALS['installer_groups'][$key])) {
293 logDebugMessage(__FUNCTION__, __LINE__, 'Cannot determine installer group, returning dummy group. key=' . $key);
295 // Return dummy group
300 return $GLOBALS['installer_groups'][$key];
303 // Adds given key/value pair to an overview group
304 function addKeyValueToInstallerOverviewGroup ($key, $value) {
305 // First determine the group by given key
306 $group = determineInstallerGroupByKey($key);
308 // Depending on the group, add it for later usage (to render the overview page)
309 $GLOBALS['installer_overview'][$group][$key] = $value;
312 //-----------------------------------------------------------------------------
313 // Call-back functions to check validity
314 //-----------------------------------------------------------------------------
316 // ----------------- Base data -----------------
318 // Call-back function to check validity of 'base_path'
319 function isInstallerBasePathValid ($value) {
320 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'value=' . $value . ' - ENTERED!');
321 // Is it a directory and if some typical files could be found
323 // Is it a directory?
324 (isDirectory($value))
326 // Is there a trailing slash?
327 (substr($value, -1, 1) == '/')
329 // Is mysql-manager.php there?
330 (isFileReadable($value . 'inc/mysql-manager.php'))
332 // What about gen_sql_patches.php?
333 (isFileReadable($value . 'inc/gen_sql_patches.php'))
337 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'value=' . $value . ',isValid=' . intval($isValid) . ' - EXIT');
341 // Call-back function to check validity of 'base_url'
342 function isInstallerBaseUrlValid ($value) {
343 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'value=' . $value . ' - ENTERED!');
349 // Starts with http:// or https:// ?
350 ((substr($value, 0, 7) == 'http://') || (substr($value, 0, 8) == 'https://'))
352 // Has no trailing slash?
353 (substr($value, -1, 1) != '/')
355 // And total length is at least 6+8=14 chars long? (https://foo.ba)
356 (strlen($value) >= 14)
363 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'value=' . $value . ',isValid=' . intval($isValid) . ' - EXIT');
367 // Call-back function to check validity of 'webmaster'
368 function isInstallerWebmasterValid ($value) {
369 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'value=' . $value . ' - ENTERED!');
370 // Is it a valid email address?
372 // Is it a valid email address?
373 (isEmailValid($value))
375 // Or is there 'localhost/127.0.0.1' as hostname? Then don't check email address (e.g. you@localhost)
376 (in_array(detectServerName(), array('localhost', '127.0.0.1')))
380 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'value=' . $value . ',isValid=' . intval($isValid) . ' - EXIT');
384 // ----------------- Database configuration -----------------
386 // Call-back function to check validity of 'mysql_host'
387 function isInstallerMysqlHostValid ($value) {
388 // This value must match a hostname or IP address
390 // Is localhost/127.0.0.1? (mostly the case)
391 (in_array($value, array('localhost', '127.0.0.1')))
393 // IP number match (this regex was taken from www.regexlib.com)
394 (preg_match('/((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9]))/', $value))
397 (preg_match('/([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}/', $value))
404 // Call-back function to check validity of 'mysql_type'
405 function isInstallerMysqlTypeValid ($value) {
406 // This value must be 'MyISAM' or 'InnoDB'
407 $isValid = in_array($value, array('MyISAM', 'InnoDB'));
413 // ----------------- SMTP configuration -----------------
415 // ----------------- Other configuration -----------------
417 //-----------------------------------------------------------------------------
418 // Call-back functions to post-check validity
419 //-----------------------------------------------------------------------------
421 // Call-back function to check if database configuration in POST is valid
422 function isInstallerPostDatabaseConfigValid ($currentTab) {
423 // By default nothing is valid
425 $engineValid = FALSE;
428 // Do both passwords match?
429 if ((!isPostRequestElementSet('mysql_password1')) && (isPostRequestElementSet('mysql_password2'))) {
430 // Password 1 not set
431 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_PASSWORD1_EMPTY--}';
432 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_password1');
434 } elseif ((isPostRequestElementSet('mysql_password1')) && (!isPostRequestElementSet('mysql_password2'))) {
435 // Password 2 not set
436 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_PASSWORD2_EMPTY--}';
437 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_password2');
439 } elseif (postRequestElement('mysql_password1') != postRequestElement('mysql_password2')) {
440 // Passwords mismatch
441 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_PASSWORDS_MISMATCH--}';
442 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_password1', 'mysql_password2');
446 // Restore PHP's own error handler
447 if (!restore_error_handler()) {
449 reportBug(__FUNCTION__, __LINE__, 'Could not unregister error handler.');
452 // Try to connect to the database
453 $linkResource = SQL_CONNECT(postRequestElement('mysql_host'), postRequestElement('mysql_login'), postRequestElement('mysql_password1'), __FUNCTION__, __LINE__);
456 if (!is_resource($linkResource)) {
457 // Restore own error handler again
458 set_error_handler('__errorHandler');
460 // Cannot connect to database
461 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_CONNECT_ERROR--}';
462 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_login', 'mysql_password1', 'mysql_password2');
466 // Then attempt to select the database
467 if (!SQL_SELECT_DB(postRequestElement('mysql_dbase'), __FUNCTION__, __LINE__)) {
468 // Restore own error handler again
469 set_error_handler('__errorHandler');
471 // Could not find database
472 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_SELECT_FAILED--}';
473 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_dbase');
477 // Set database name and prefix
478 setConfigEntry('__DB_NAME' , postRequestElement('mysql_dbase'));
479 setConfigEntry('_MYSQL_PREFIX', postRequestElement('mysql_prefix'));
481 // Restore own error handler again
482 set_error_handler('__errorHandler');
484 // Get an array of all supported engines
485 $engines = getArrayFromSupportedSqlEngines();
488 if (!is_array($engines)) {
489 // Restore own error handler again
490 set_error_handler('__errorHandler');
492 // Something bad happened
493 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_ENGINES_SQL_ERROR--}';
494 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_type');
496 } elseif (count($engines) == 0) {
497 // Restore own error handler again
498 set_error_handler('__errorHandler');
500 // No engine is active
501 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_NO_ENGINES_ACTIVE--}';
502 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_type');
506 // Then check all, if the requested is working
507 foreach ($engines as $engineArray) {
508 // By default the selected engine is not valid
509 $engineValid = FALSE;
511 // Is the engine there?
512 if (strtolower($engineArray['Engine']) == strtolower(postRequestElement('mysql_type'))) {
513 // Okay, engine is found
519 // So, is the engine found?
520 if ($engineValid === FALSE) {
521 // Restore own error handler again
522 set_error_handler('__errorHandler');
524 // Requested engine is not active
525 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_ENGINE_UNSUPPORTED--}';
526 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_type');
530 // Init some known tables
535 'admin_menu' => TRUE,
541 'extensions' => TRUE,
543 'guest_menu' => TRUE,
545 'max_receive' => TRUE,
547 'member_menu' => TRUE,
561 'task_system' => TRUE,
564 // So check if all tables are not there
565 foreach ($tables as $tableName => $isFound) {
567 $tables[$tableName] = ifSqlTableExists($tableName);
569 // Is it (hopefully not) there?
570 if ($tables[$tableName] === FALSE) {
571 // This does not exist
576 // Determine final status (simply compare both counts
577 $isValid = (count($tables) == $missingTables);
579 // Disconnect here, we don't need idle database connections laying around
580 SQL_CLOSE(__FUNCTION__, __LINE__);
582 // Restore own error handler again
583 set_error_handler('__errorHandler');
585 // If the status is true, disconnect the database
586 if ($isValid === FALSE) {
587 // Still something bad happened (e.g. tables found)
588 $GLOBALS['installer_post_error'][$currentTab] = '{--INSTALLER_POST_DATABASE_IN_USE--}';
589 array_push($GLOBALS['installer_failed_fields'][$currentTab], 'mysql_dbase');
596 // Call-back function to check if enable_backlink is Y/N
597 function isInstallerEnableBacklinkValid ($currentTab) {
598 // Check and return it
599 return in_array($currentTab, array('Y', 'N'));
602 // Call-back function to check if warn_no_pass is Y/N
603 function isInstallerWarnNoPassValid ($currentTab) {
604 // Check and return it
605 return in_array($currentTab, array('Y', 'N'));
608 // Call-back function to check if write_footer is Y/N
609 function isInstallerWriteFooterValid ($currentTab) {
610 // Check and return it
611 return in_array($currentTab, array('Y', 'N'));
614 // Call-back function to check if output_mode is Y/N
615 function isInstallerOutputModeValid ($currentTab) {
616 // Check and return it
617 return in_array($currentTab, array('render', 'direct'));