2 /************************************************************************
3 * Mailer v0.2.1-FINAL Start: 06/24/2012 *
4 * =================== Last change: 06/24/2012 *
6 * -------------------------------------------------------------------- *
7 * File : ajax_installer.php *
8 * -------------------------------------------------------------------- *
9 * Short description : AJAX-related functions for installer *
10 * -------------------------------------------------------------------- *
11 * Kurzbeschreibung : AJAX-bezogene Funktionen fuer Installer *
12 * -------------------------------------------------------------------- *
15 * $Tag:: 0.2.1-FINAL $ *
17 * -------------------------------------------------------------------- *
18 * Copyright (c) 2003 - 2009 by Roland Haeder *
19 * Copyright (c) 2009 - 2013 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')) || (!isAjaxOutputMode()) || (!isInstallationPhase())) {
40 header('HTTP/1.1 403 Forbidden');
41 die(json_encode(array('reply_content' => 'Access forbidden'), JSON_FORCE_OBJECT));
44 //-----------------------------------------------------------------------------
45 // Generic call-back functions, they all rely on session data
46 //-----------------------------------------------------------------------------
48 // Establish a database link
49 function establishAjaxInstallerDatabaseLink () {
50 // This requires some session data
51 if (!isSessionDataSet(array('mysql_host', 'mysql_dbase', 'mysql_prefix', 'mysql_login', 'mysql_password1', 'mysql_password2', 'mysql_engine'))) {
52 // Some required session data is not set
53 reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.');
56 // Remove any previous flag
57 unsetSqlLinkUp(__FUNCTION__, __LINE__);
60 $linkResource = sqlConnectToDatabase(getSession('mysql_host'), getSession('mysql_login'), getSession('mysql_password1'), __FUNCTION__, __LINE__);
62 // Is this a link resource?
63 if (!is_resource($linkResource)) {
65 reportBug(__FUNCTION__, __LINE__, 'linkResource[]=' . gettype($linkResource) . ', expected: link resource');
68 // Does selecting the database work?
69 if (!sqlSelectDatabase(getSession('mysql_dbase'), __FUNCTION__, __LINE__)) {
70 // Could not be selected
71 reportBug(__FUNCTION__, __LINE__, 'Could not select database ' . getSession('mysql_dbase'));
72 } elseif ((!isFileReadable(getSession('base_path') . 'install/tables.sql')) || (!isFileReadable(getSession('base_path') . 'install/menu-'.getLanguage().'.sql'))) {
73 // Installation area not found
74 reportBug(__FUNCTION__, __LINE__, 'SQL dumps not found. Please extract ALL files from the archive or checkout all files out from SVN.');
75 } elseif (ifFatalErrorsDetected()) {
76 // Some other fatal error occured
77 reportBug(__FUNCTION__, __LINE__, 'Some fatal error detected, please check debug.log for details.');
80 // Set type, prefix from POST data and database name for later queries
81 setConfigEntry('_TABLE_TYPE' , getSession('mysql_engine'));
82 setConfigEntry('_MYSQL_PREFIX', getSession('mysql_prefix'));
83 setConfigEntry('__DB_NAME' , getSession('mysql_dbase'));
86 //-----------------------------------------------------------------------------
87 // Call-back functions for processing AJAX requests
88 //-----------------------------------------------------------------------------
90 // Processes AJAX requests for installer
91 function doAjaxProcessInstall () {
92 // 'do' must always be set and installation phase must be true
93 if (!isInstallationPhase()) {
94 // This shall not happen
95 reportBug(__FUNCTION__, __LINE__, 'This AJAX request handler was called outside the installer.');
96 } elseif (!isPostRequestElementSet('do')) {
97 // This shall not happen
98 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "do" which is fatal.');
101 // Notify all modules that we are installing
102 $GLOBALS['__mailer_installing'] = TRUE;
104 // Again we do a call-back, so generate a function name depending on 'do'
105 $callbackName = 'doAjaxInstaller' . capitalizeUnderscoreString(postRequestElement('do'));
106 $GLOBALS['ajax_callback_function'] = $callbackName;
108 // Is the call-back function there?
109 if (!function_exists($callbackName)) {
110 // This shall not happen
111 reportBug(__FUNCTION__, __LINE__, 'AJAX call-back ' . $callbackName . ' does not exist.');
115 call_user_func($callbackName);
117 // Is the status fine or template not found (404)?
121 // Processes installer request for testing
122 function doAjaxInstallerTest () {
123 // Load the "test passed" template
124 setAjaxReplyContent(loadTemplate('ajax_test_passed', TRUE));
126 // All okay if we reach this point
127 setHttpStatus('200 OK');
130 // Processes installer requests for footer navigation
131 function doAjaxInstallerFooterNavigation () {
132 // 'tab' must always be set to determine which navigation buttons shall be visible
133 if (!isPostRequestElementSet('tab')) {
134 // This shall not happen
135 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
138 // Init array for footer navigation
139 $enabledNavigations = array();
141 // "Detect" the 'tab' value
142 switch (postRequestElement('tab')) {
143 case 'base_data': // Also 'previous' is valid
144 case 'database_config':
148 array_push($enabledNavigations, 'previous');
149 case 'welcome': // Only 'next' works for welcome page
150 array_push($enabledNavigations, 'next');
153 case 'overview': // Enable only 'previous'
154 array_push($enabledNavigations, 'previous');
155 if (isInstallationDataCompleted()) {
157 array_push($enabledNavigations, 'finish');
161 default: // Unsupported value
162 // This shall not happen
163 reportBug(__FUNCTION__, __LINE__, 'Unsupported "tab" value ' . postRequestElement('tab') . ' detected.');
165 // This will never be reached
169 // Output the array for JSON reply
170 setAjaxReplyContent(encodeJson($enabledNavigations));
172 // All okay if we reach this point
173 setHttpStatus('200 OK');
176 // Processes installer AJAX calls for content-requests
177 function doAjaxInstallerDoStep () {
178 // 'step' must be there
179 if (!isPostRequestElementSet('step')) {
180 // This shall not happen
181 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "step" which is fatal.');
184 // Construct call-back name
185 $callbackName = 'doAjaxInstallerStep' . capitalizeUnderscoreString(postRequestElement('step'));
187 // Is the function there?
188 if (function_exists($callbackName)) {
189 // Call it for setting values in session
190 call_user_func($callbackName);
192 // Log missing functions
193 reportBug(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.');
197 setAjaxReplyContent(encodeJson(postRequestElement('step').'=OK'));
199 // All okay if we reach this point
200 setHttpStatus('200 OK');
203 // Processes installer AJAX calls for content-requests
204 function doAjaxInstallerRequestContent () {
205 // 'tab' must be there
206 if (!isPostRequestElementSet('tab')) {
207 // This shall not happen
208 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
211 // Construct call-back name for value-preset
212 $callbackName = 'doAjaxPrepareInstaller' . capitalizeUnderscoreString(postRequestElement('tab'));
214 // Is the function there?
215 if (function_exists($callbackName)) {
216 // Call it for setting values in session
217 call_user_func($callbackName);
219 // Log missing functions
220 reportBug(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.');
223 // Is the HTTP status still the same? (204 No Content)
224 if (getHttpStatus() == '204 No Content') {
225 // We use the current access level 'install' as prefix and construct a template name
226 setAjaxReplyContent(loadTemplate('install_page_' . trim(postRequestElement('tab')), TRUE));
228 // Has the template been loaded?
229 if (isset($GLOBALS['template_content']['html']['install_page_' . trim(postRequestElement('tab'))])) {
230 // All okay if we reach this point
231 setHttpStatus('200 OK');
234 setHttpStatus('404 Not Found');
239 // Process installer AJAX call for change-warning
240 function doAjaxInstallerChangeWarning () {
241 // 'elements' and 'button' must be there
242 if ((!isPostRequestElementSet('elements')) || (!isPostRequestElementSet('button'))) {
243 // This shall not happen
244 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "elements" and/or "button" which is fatal.');
247 // "Walk" through all elements
249 foreach (explode(':', postRequestElement('elements')) as $element) {
250 // Is it an extension?
251 if (substr($element, 0, 4) == 'ext_') {
252 // Add row for extension
253 $OUT .= '<li>{%message,INSTALLER_CHANGED_ELEMENT_EXTENSION=' . str_replace('_', '-', $element) . '%}</li>';
256 $OUT .= '<li>{--INSTALLER_CHANGED_ELEMENT_' . strtoupper($element) . '--}</li>';
264 'button' => postRequestElement('button'),
265 'message' => '{--INSTALLER_TAB_NAVIGATION_' . strtoupper(postRequestElement('button')) . '_LINK--}',
268 if (in_array(postRequestElement('button'), array('previous', 'next'))) {
269 // Load 'prefixed' template
270 setAjaxReplyContent(loadTemplate('install_warning_' . postRequestElement('button'), TRUE, $content));
272 // Load 'tab' template
273 setAjaxReplyContent(loadTemplate('install_warning_tab', TRUE, $content));
276 // All okay if we reach this point
277 setHttpStatus('200 OK');
280 // Process installer AJAC call for saving changes
281 function doAjaxInstallerSaveChanges () {
282 // 'tab' must always be set to create a post-check-callback
283 if (!isPostRequestElementSet('tab')) {
284 // This shall not happen
285 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
288 // Save the tab for pre-"filtering"
289 $currentTab = postRequestElement('tab');
291 // Remove some elements which should not be saved
292 foreach (array('tab', 'do', 'level') as $removedElement) {
293 // Remove this element from POST data
294 unsetPostRequestElement($removedElement);
297 // Default is failed save attempt (e.g. nothing to save)
299 'status' => 'failed',
300 'message' => '{--INSTALLER_SAVE_CHANGES_FAILED--}',
301 // Don't set this to false, or else it will be returned as 'failed' but is saved
303 'failed_fields' => array()
306 // Init overall status
309 // Now set all remaining data in session
310 foreach (postRequestArray() as $key => $value) {
311 // Set it, if it is valid, else it will be added to $saveStatus (call-by-reference)
312 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value[' . gettype($value) . '=' . $value);
313 $saveStatus['is_saved'] = (
314 // Is the data valid?
315 (isInstallerDataValid($saveStatus, $key, $value))
317 // And can it be stored in session?
318 (setSession($key, $value))
321 // Save the overall status for below final check
322 $isAllSaved = (($isAllSaved === TRUE) && ($saveStatus['is_saved'] === TRUE));
323 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value[' . gettype($value) . '=' . $value . ',is_saved=' . intval($saveStatus['is_saved']) . ',isAllSaved=' . intval($isAllSaved));
326 // 'is_saved' is still true?
327 if ($isAllSaved === TRUE) {
328 // Set 'done' and message
329 $saveStatus['status'] = 'done';
330 $saveStatus['message'] = '{--INSTALLER_SAVE_CHANGES_DONE--}';
332 // Then do the post-check
333 doInstallerPostCheck($currentTab, $saveStatus);
336 // Output the status array for JSON reply
337 setAjaxReplyContent(encodeJson($saveStatus));
339 // All okay if we reach this point
340 setHttpStatus('200 OK');
343 // ----------------------------------------------------------------------------
344 // Call-back functions for preparing installer page requests
345 // ----------------------------------------------------------------------------
347 // Prepare AJAX request 'welcome'
348 function doAjaxPrepareInstallerWelcome () {
349 // Kept empty to prevent logfile entry
352 // Prepare AJAX request 'base_data'
353 function doAjaxPrepareInstallerBaseData () {
354 // Is 'base_path' not set?
355 if (!isSessionVariableSet('base_path')) {
356 // Then set it from PATH
357 setSession('base_path', getPath());
360 // Is 'base_url' not set?
361 if (!isSessionVariableSet('base_url')) {
362 // Then set it from URL
363 setSession('base_url', getUrl());
366 // Is 'main_title' not set?
367 if (!isSessionVariableSet('main_title')) {
368 // Then set it from default main title
369 setSession('main_title', '{--DEFAULT_MAIN_TITLE--}');
372 // Is 'slogan' not set?
373 if (!isSessionVariableSet('slogan')) {
374 // Then set it from default slogan
375 setSession('slogan', '{--DEFAULT_SLOGAN--}');
378 // Is 'webmaster' not set?
379 if (!isSessionVariableSet('webmaster')) {
380 // Then set it from default webmaster email address
381 setSession('webmaster', '{--DEFAULT_WEBMASTER--}');
385 // Prepare AJAX request 'database_config'
386 function doAjaxPrepareInstallerDatabaseConfig () {
387 // Is 'mysql_host' not set?
388 if (!isSessionVariableSet('mysql_host')) {
389 // Then set it directly
390 setSession('mysql_host', 'localhost');
393 // Is 'mysql_dbase' not set?
394 if (!isSessionVariableSet('mysql_dbase')) {
395 // Then set it directly
396 setSession('mysql_dbase', 'your_database');
399 // Is 'mysql_prefix' not set?
400 if (!isSessionVariableSet('mysql_prefix')) {
401 // Then set it directly
402 setSession('mysql_prefix', 'mailer');
405 // Is 'mysql_login' not set?
406 if (!isSessionVariableSet('mysql_login')) {
407 // Then set it directly
408 setSession('mysql_login', 'your_login');
411 // Is 'mysql_dbase' not set?
412 if (!isSessionVariableSet('mysql_password1')) {
413 // Then set it directly
414 setSession('mysql_password1', '');
417 // Is 'mysql_password2' not set?
418 if (!isSessionVariableSet('mysql_password2')) {
419 // Then set it directly
420 setSession('mysql_password2', '');
423 // Is 'mysql_engine' not set?
424 if (!isSessionVariableSet('mysql_engine')) {
425 // Then set it directly
426 setSession('mysql_engine', 'MyISAM');
430 // Prepare AJAX request 'smtp_config'
431 function doAjaxPrepareInstallerSmtpConfig () {
432 // Kept empty to prevent logfile entry because SMTP settings are optional
435 // Prepare AJAX request 'other_config'
436 function doAjaxPrepareInstallerOtherConfig () {
437 // Is 'output_mode' not set?
438 if (!isSessionVariableSet('output_mode')) {
439 // Then set it directly
440 setSession('output_mode', 'render');
443 // Is 'warn_no_pass' not set?
444 if (!isSessionVariableSet('warn_no_pass')) {
445 // Then set it directly
446 setSession('warn_no_pass', 'Y');
449 // Is 'write_footer' not set?
450 if (!isSessionVariableSet('write_footer')) {
451 // Then set it directly
452 setSession('write_footer', 'Y');
455 // Is 'enable_backlink' not set?
456 if (!isSessionVariableSet('enable_backlink')) {
457 // Then set it directly
458 setSession('enable_backlink', 'Y');
462 // Prepare AJAX request 'extensions'
463 function doAjaxPrepareInstallerExtensions () {
464 // Is 'extensions' set?
465 if (!isSessionVariableSet('extensions')) {
467 * At least ext-sql_patches and ext-task should be installed
468 *(ext-sql_patches is a must!)
470 setSession('extensions', 'admins:sql_patches:task');
471 } elseif (strpos(getSession('extensions'), 'sql_patches') === FALSE) {
472 // Add missing ext-sql_patches
473 setSession('extensions', getSession('extensions') . ':sql_patches');
477 // Prepare AJAX request 'overview'
478 function doAjaxPrepareInstallerOverview () {
479 // 'tab' must always be set to create a post-check-callback
480 if (!isPostRequestElementSet('tab')) {
481 // This shall not happen
482 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
485 // Save the tab for pre-"filtering"
486 $currentTab = postRequestElement('tab');
488 // Default is failed save attempt (e.g. nothing to save)
489 $verificationStatus = array(
490 // Status code, can be 'failed' or 'done'
491 'status' => 'failed',
492 // Status message (e.g. for output)
493 'message' => '{--INSTALLER_OVERVIEW_FINAL_CHECK_FAILED--}',
494 // Don't set this to false, or else it will be returned as 'failed' but is saved
497 'failed_fields' => array()
500 // Init overall status and final output
504 // Check all data in session
505 foreach (array_keys($GLOBALS['installer_groups']) as $key) {
506 // Get values from session
507 $value = getSession($key);
509 // Is the data valid?
510 $verificationStatus['is_valid'] = (isInstallerDataValid($verificationStatus, $key, $value));
512 // Is this step okay?
513 if ($verificationStatus['is_valid'] === TRUE) {
514 // Add this key/value pair to a overview group
515 addKeyValueToInstallerOverviewGroup($key, $value);
518 // Save the overall status for below final check
519 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value=' . $value . ',is_valid=' . intval($verificationStatus['is_valid']) . ',isAllValid=' . intval($isAllValid));
520 $isAllValid = (($isAllValid === TRUE) && ($verificationStatus['is_valid'] === TRUE));
524 if ((isInstallationDataCompleted()) && ($isAllValid === TRUE)) {
525 // Set 'done' and message
526 $verificationStatus['status'] = 'done';
527 $verificationStatus['message'] = '{--INSTALLER_OVERVIEW_FINAL_CHECK_DONE--}';
529 // Then do the post-check
530 doInstallerPostCheck($currentTab, $verificationStatus);
533 // Is it still valid?
534 if ($verificationStatus['status'] != 'done') {
536 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Final check on all stored data failed. message=' . $verificationStatus['message']);
538 // Process failed fields
539 $verificationStatus['failed_fields'] = handleInstallerFailedFields($verificationStatus['failed_fields']);
541 // Output the array for JSON reply
542 setAjaxReplyContent(loadTemplate('install_overview_failed', TRUE, $verificationStatus));
545 * Something went wrong, this might happen when e.g. the user has tried
546 * to save invalid database login data but hit reload button on error
549 setHttpStatus('200 OK');
556 // ----------------------------------------------------------------------------
557 // Call-back functions for doing installation steps
558 // ----------------------------------------------------------------------------
560 // Call-back function to import first tables.sql file
561 function doAjaxInstallerStepImportTablesSql () {
562 // Establish database link
563 establishAjaxInstallerDatabaseLink();
569 importInstallSqlDump('tables');
571 // Are some SQLs found?
572 if (countSqls() == 0) {
574 reportBug(__FUNCTION__, __LINE__, '{--INSTALLER_SQL_IMPORT_FAILED--}');
577 // Now run all queries through
578 runFilterChain('run_sqls');
581 sqlCloseLink(__FUNCTION__, __LINE__);
584 // Call-back function to import menu SQL file
585 function doAjaxInstallerStepImportMenuSql () {
586 // Establish database link
587 establishAjaxInstallerDatabaseLink();
593 importInstallSqlDump('menu-' . getLanguage());
595 // Are some SQLs found?
596 if (countSqls() == 0) {
598 reportBug(__FUNCTION__, __LINE__, '{--INSTALLER_SQL_IMPORT_FAILED--}');
601 // Now run all queries through
602 runFilterChain('run_sqls');
605 sqlCloseLink(__FUNCTION__, __LINE__);
608 // Call-back function to install some important extensions
609 function doAjaxInstallerStepInstallExtensions () {
610 // Only one element is required
611 if (!isSessionVariableSet('extensions')) {
612 // Some required session data is not set
613 reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.');
616 // Establish database link
617 establishAjaxInstallerDatabaseLink();
619 // Get all extensions
620 $extensions = explode(':', getSession('extensions'));
622 // Make sure ext-sql_patches is first
623 array_unshift($extensions, 'sql_patches');
625 // "Walk" through all extensions
626 foreach ($extensions as $key => $ext_name) {
627 // Is ext-sql_patches not at key=0?
628 if (($key == 0) && ($ext_name == 'sql_patches')) {
629 // Then skip this entry
631 } elseif ((!loadExtension($ext_name, 'test', '0.0.0', TRUE)) || (!registerExtension($ext_name, NULL))) {
633 reportBug(__FUNCTION__, __LINE__, 'Cannot load/register extension ' . $ext_name . '.');
638 // Call-back function to write local configuration file
639 function doAjaxInstallerStepWriteLocalConfig () {
641 if (!isSessionDataSet(array('base_path', 'base_url', 'main_title', 'slogan', 'webmaster', 'mysql_host', 'mysql_dbase', 'mysql_prefix', 'mysql_login', 'mysql_password1', 'mysql_password2', 'mysql_engine', 'output_mode', 'warn_no_pass', 'write_footer', 'enable_backlink'))) {
642 // Some required session data is not set
643 reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.');
647 if (!doInstallWriteLocalConfigurationFile(
648 getSession('base_path'),
649 getSession('base_url'),
650 getSession('main_title'),
651 getSession('slogan'),
652 getSession('webmaster'),
653 getSession('warn_no_pass'),
654 getSession('write_footer'),
655 getSession('enable_backlink'),
656 getSession('mysql_host'),
657 getSession('mysql_dbase'),
658 getSession('mysql_login'),
659 getSession('mysql_password1'),
660 getSession('mysql_prefix'),
661 getSession('mysql_engine'),
662 getSession('smtp_host'),
663 getSession('smtp_user'),
664 getSession('smtp_password1')
666 // Something bad went wrong
667 removeFile(getSession('base_path') . getCachePath() . 'config-local.php');
668 reportBug(__FUNCTION__, __LINE__, 'Did not fully write config-local.php .');