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 - 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')) || (!isAjaxOutputMode()) || (!isInstallationPhase())) {
43 //-----------------------------------------------------------------------------
44 // Generic call-back functions, they all rely on session data
45 //-----------------------------------------------------------------------------
47 // Establish a database link
48 function establishAjaxInstallerDatabaseLink () {
49 // This requires some session data
50 if (!isSessionDataSet(array('mysql_host', 'mysql_dbase', 'mysql_prefix', 'mysql_login', 'mysql_password1', 'mysql_password2', 'mysql_engine'))) {
51 // Some required session data is not set
52 reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.');
55 // Remove any previous flag
56 unsetSqlLinkUp(__FUNCTION__, __LINE__);
59 $linkResource = SQL_CONNECT(getSession('mysql_host'), getSession('mysql_login'), getSession('mysql_password1'), __FUNCTION__, __LINE__);
61 // Is this a link resource?
62 if (!is_resource($linkResource)) {
64 reportBug(__FUNCTION__, __LINE__, 'linkResource[]=' . gettype($linkResource) . ', expected: link resource');
67 // Does selecting the database work?
68 if (!SQL_SELECT_DB(getSession('mysql_dbase'), __FUNCTION__, __LINE__)) {
69 // Could not be selected
70 reportBug(__FUNCTION__, __LINE__, 'Could not select database ' . getSession('mysql_dbase'));
71 } elseif ((!isFileReadable(getSession('base_path') . 'install/tables.sql')) || (!isFileReadable(getSession('base_path') . 'install/menu-'.getLanguage().'.sql'))) {
72 // Installation area not found
73 reportBug(__FUNCTION__, __LINE__, 'SQL dumps not found. Please extract ALL files from the archive or checkout all files out from SVN.');
74 } elseif (ifFatalErrorsDetected()) {
75 // Some other fatal error occured
76 reportBug(__FUNCTION__, __LINE__, 'Some fatal error detected, please check debug.log for details.');
79 // Set type, prefix from POST data and database name for later queries
80 setConfigEntry('_TABLE_TYPE' , getSession('mysql_engine'));
81 setConfigEntry('_MYSQL_PREFIX', getSession('mysql_prefix'));
82 setConfigEntry('__DB_NAME' , getSession('mysql_dbase'));
85 //-----------------------------------------------------------------------------
86 // Call-back functions for processing AJAX requests
87 //-----------------------------------------------------------------------------
89 // Processes AJAX requests for installer
90 function doAjaxProcessInstall () {
91 // 'do' must always be set and installation phase must be true
92 if (!isInstallationPhase()) {
93 // This shall not happen
94 reportBug(__FUNCTION__, __LINE__, 'This AJAX request handler was called outside the installer.');
95 } elseif (!isPostRequestElementSet('do')) {
96 // This shall not happen
97 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "do" which is fatal.');
100 // Notify all modules that we are installing
101 $GLOBALS['__mailer_installing'] = TRUE;
103 // Again we do a call-back, so generate a function name depending on 'do'
104 $callbackName = 'doAjaxInstaller' . capitalizeUnderscoreString(postRequestElement('do'));
106 // Is the call-back function there?
107 if (!function_exists($callbackName)) {
108 // This shall not happen
109 reportBug(__FUNCTION__, __LINE__, 'AJAX call-back ' . $callbackName . ' does not exist.');
113 call_user_func($callbackName);
115 // Is the status fine or template not found (404)?
119 // Processes installer request for testing
120 function doAjaxInstallerTest () {
121 // Load the "test passed" template
122 setAjaxReplyContent(loadTemplate('ajax_test_passed', TRUE));
124 // All okay if we reach this point
125 setHttpStatus('200 OK');
128 // Processes installer requests for footer navigation
129 function doAjaxInstallerFooterNavigation () {
130 // 'tab' must always be set to determine which navigation buttons shall be visible
131 if (!isPostRequestElementSet('tab')) {
132 // This shall not happen
133 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
136 // Init array for footer navigation
137 $enabledNavigations = array();
139 // "Detect" the 'tab' value
140 switch (postRequestElement('tab')) {
141 case 'base_data': // Also 'previous' is valid
142 case 'database_config':
146 array_push($enabledNavigations, 'previous');
147 case 'welcome': // Only 'next' works for welcome page
148 array_push($enabledNavigations, 'next');
151 case 'overview': // Enable only 'previous'
152 array_push($enabledNavigations, 'previous');
153 if (isInstallationDataCompleted()) {
155 array_push($enabledNavigations, 'finish');
159 default: // Unsupported value
160 // This shall not happen
161 reportBug(__FUNCTION__, __LINE__, 'Unsupported "tab" value ' . postRequestElement('tab') . ' detected.');
163 // This will never be reached
167 // Output the array for JSON reply
168 setAjaxReplyContent(encodeJson($enabledNavigations));
170 // All okay if we reach this point
171 setHttpStatus('200 OK');
174 // Processes installer AJAX calls for content-requests
175 function doAjaxInstallerDoStep () {
176 // 'step' must be there
177 if (!isPostRequestElementSet('step')) {
178 // This shall not happen
179 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "step" which is fatal.');
182 // Construct call-back name
183 $callbackName = 'doAjaxInstallerStep' . capitalizeUnderscoreString(postRequestElement('step'));
185 // Is the function there?
186 if (function_exists($callbackName)) {
187 // Call it for setting values in session
188 call_user_func($callbackName);
190 // Log missing functions
191 reportBug(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.');
195 setAjaxReplyContent(encodeJson(postRequestElement('step').'=OK'));
197 // All okay if we reach this point
198 setHttpStatus('200 OK');
201 // Processes installer AJAX calls for content-requests
202 function doAjaxInstallerRequestContent () {
203 // 'tab' must be there
204 if (!isPostRequestElementSet('tab')) {
205 // This shall not happen
206 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
209 // Construct call-back name for value-preset
210 $callbackName = 'doAjaxPrepareInstaller' . capitalizeUnderscoreString(postRequestElement('tab'));
212 // Is the function there?
213 if (function_exists($callbackName)) {
214 // Call it for setting values in session
215 call_user_func($callbackName);
217 // Log missing functions
218 reportBug(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.');
221 // Is the HTTP status still the same? (204 No Content)
222 if (getHttpStatus() == '204 No Content') {
223 // We use the current access level 'install' as prefix and construct a template name
224 setAjaxReplyContent(loadTemplate('install_page_' . trim(postRequestElement('tab')), TRUE));
226 // Has the template been loaded?
227 if (isset($GLOBALS['template_content']['html']['install_page_' . trim(postRequestElement('tab'))])) {
228 // All okay if we reach this point
229 setHttpStatus('200 OK');
232 setHttpStatus('404 Not Found');
237 // Process installer AJAX call for change-warning
238 function doAjaxInstallerChangeWarning () {
239 // 'elements' and 'button' must be there
240 if ((!isPostRequestElementSet('elements')) || (!isPostRequestElementSet('button'))) {
241 // This shall not happen
242 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "elements" and/or "button" which is fatal.');
245 // "Walk" through all elements
247 foreach (explode(':', postRequestElement('elements')) as $element) {
248 // Is it an extension?
249 if (substr($element, 0, 4) == 'ext_') {
250 // Add row for extension
251 $OUT .= '<li>{%message=INSTALLER_CHANGED_ELEMENT_EXTENSION=' . str_replace('_', '-', $element) . '%}</li>';
254 $OUT .= '<li>{--INSTALLER_CHANGED_ELEMENT_' . strtoupper($element) . '--}</li>';
262 'button' => postRequestElement('button'),
263 'message' => '{--INSTALLER_TAB_NAVIGATION_' . strtoupper(postRequestElement('button')) . '_LINK--}',
266 if (in_array(postRequestElement('button'), array('previous', 'next'))) {
267 // Load 'prefixed' template
268 setAjaxReplyContent(loadTemplate('install_warning_' . postRequestElement('button'), TRUE, $content));
270 // Load 'tab' template
271 setAjaxReplyContent(loadTemplate('install_warning_tab', TRUE, $content));
274 // All okay if we reach this point
275 setHttpStatus('200 OK');
278 // Process installer AJAC call for saving changes
279 function doAjaxInstallerSaveChanges () {
280 // 'tab' must always be set to create a post-check-callback
281 if (!isPostRequestElementSet('tab')) {
282 // This shall not happen
283 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
286 // Save the tab for pre-"filtering"
287 $currentTab = postRequestElement('tab');
289 // Remove some elements which should not be saved
290 foreach (array('tab', 'do', 'level') as $removedElement) {
291 // Remove this element from POST data
292 unsetPostRequestElement($removedElement);
295 // Default is failed save attempt (e.g. nothing to save)
297 'status' => 'failed',
298 'message' => '{--INSTALLER_SAVE_CHANGES_FAILED--}',
299 // Don't set this to false, or else it will be returned as 'failed' but is saved
301 'failed_fields' => array()
304 // Init overall status
307 // Now set all remaining data in session
308 foreach (postRequestArray() as $key => $value) {
309 // Set it, if it is valid, else it will be added to $saveStatus (call-by-reference)
310 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value[' . gettype($value) . '=' . $value);
311 $saveStatus['is_saved'] = (
312 // Is the data valid?
313 (isInstallerDataValid($saveStatus, $key, $value))
315 // And can it be stored in session?
316 (setSession($key, $value))
319 // Save the overall status for below final check
320 $isAllSaved = (($isAllSaved === TRUE) && ($saveStatus['is_saved'] === TRUE));
321 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value[' . gettype($value) . '=' . $value . ',is_saved=' . intval($saveStatus['is_saved']) . ',isAllSaved=' . intval($isAllSaved));
324 // 'is_saved' is still true?
325 if ($isAllSaved === TRUE) {
326 // Set 'done' and message
327 $saveStatus['status'] = 'done';
328 $saveStatus['message'] = '{--INSTALLER_SAVE_CHANGES_DONE--}';
330 // Then do the post-check
331 doInstallerPostCheck($currentTab, $saveStatus);
334 // Output the status array for JSON reply
335 setAjaxReplyContent(encodeJson($saveStatus));
337 // All okay if we reach this point
338 setHttpStatus('200 OK');
341 // ----------------------------------------------------------------------------
342 // Call-back functions for preparing installer page requests
343 // ----------------------------------------------------------------------------
345 // Prepare AJAX request 'welcome'
346 function doAjaxPrepareInstallerWelcome () {
347 // Kept empty to prevent logfile entry
350 // Prepare AJAX request 'base_data'
351 function doAjaxPrepareInstallerBaseData () {
352 // Is 'base_path' not set?
353 if (!isSessionVariableSet('base_path')) {
354 // Then set it from PATH
355 setSession('base_path', getPath());
358 // Is 'base_url' not set?
359 if (!isSessionVariableSet('base_url')) {
360 // Then set it from URL
361 setSession('base_url', getUrl());
364 // Is 'main_title' not set?
365 if (!isSessionVariableSet('main_title')) {
366 // Then set it from default main title
367 setSession('main_title', '{--DEFAULT_MAIN_TITLE--}');
370 // Is 'slogan' not set?
371 if (!isSessionVariableSet('slogan')) {
372 // Then set it from default slogan
373 setSession('slogan', '{--DEFAULT_SLOGAN--}');
376 // Is 'webmaster' not set?
377 if (!isSessionVariableSet('webmaster')) {
378 // Then set it from default webmaster email address
379 setSession('webmaster', '{--DEFAULT_WEBMASTER--}');
383 // Prepare AJAX request 'database_config'
384 function doAjaxPrepareInstallerDatabaseConfig () {
385 // Is 'mysql_host' not set?
386 if (!isSessionVariableSet('mysql_host')) {
387 // Then set it directly
388 setSession('mysql_host', 'localhost');
391 // Is 'mysql_dbase' not set?
392 if (!isSessionVariableSet('mysql_dbase')) {
393 // Then set it directly
394 setSession('mysql_dbase', 'your_database');
397 // Is 'mysql_prefix' not set?
398 if (!isSessionVariableSet('mysql_prefix')) {
399 // Then set it directly
400 setSession('mysql_prefix', 'mailer');
403 // Is 'mysql_login' not set?
404 if (!isSessionVariableSet('mysql_login')) {
405 // Then set it directly
406 setSession('mysql_login', 'your_login');
409 // Is 'mysql_dbase' not set?
410 if (!isSessionVariableSet('mysql_password1')) {
411 // Then set it directly
412 setSession('mysql_password1', '');
415 // Is 'mysql_password2' not set?
416 if (!isSessionVariableSet('mysql_password2')) {
417 // Then set it directly
418 setSession('mysql_password2', '');
421 // Is 'mysql_engine' not set?
422 if (!isSessionVariableSet('mysql_engine')) {
423 // Then set it directly
424 setSession('mysql_engine', 'MyISAM');
428 // Prepare AJAX request 'smtp_config'
429 function doAjaxPrepareInstallerSmtpConfig () {
430 // Kept empty to prevent logfile entry because SMTP settings are optional
433 // Prepare AJAX request 'other_config'
434 function doAjaxPrepareInstallerOtherConfig () {
435 // Is 'output_mode' not set?
436 if (!isSessionVariableSet('output_mode')) {
437 // Then set it directly
438 setSession('output_mode', 'render');
441 // Is 'warn_no_pass' not set?
442 if (!isSessionVariableSet('warn_no_pass')) {
443 // Then set it directly
444 setSession('warn_no_pass', 'Y');
447 // Is 'write_footer' not set?
448 if (!isSessionVariableSet('write_footer')) {
449 // Then set it directly
450 setSession('write_footer', 'Y');
453 // Is 'enable_backlink' not set?
454 if (!isSessionVariableSet('enable_backlink')) {
455 // Then set it directly
456 setSession('enable_backlink', 'Y');
460 // Prepare AJAX request 'extensions'
461 function doAjaxPrepareInstallerExtensions () {
462 // Is 'extensions' set?
463 if (!isSessionVariableSet('extensions')) {
465 * At least ext-sql_patches and ext-task should be installed
466 *(ext-sql_patches is a must!)
468 setSession('extensions', 'admins:sql_patches:task');
469 } elseif (strpos(getSession('extensions'), 'sql_patches') === FALSE) {
470 // Add missing ext-sql_patches
471 setSession('extensions', getSession('extensions') . ':sql_patches');
475 // Prepare AJAX request 'overview'
476 function doAjaxPrepareInstallerOverview () {
477 // 'tab' must always be set to create a post-check-callback
478 if (!isPostRequestElementSet('tab')) {
479 // This shall not happen
480 reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "tab" which is fatal.');
483 // Save the tab for pre-"filtering"
484 $currentTab = postRequestElement('tab');
486 // Default is failed save attempt (e.g. nothing to save)
487 $verificationStatus = array(
488 // Status code, can be 'failed' or 'done'
489 'status' => 'failed',
490 // Status message (e.g. for output)
491 'message' => '{--INSTALLER_OVERVIEW_FINAL_CHECK_FAILED--}',
492 // Don't set this to false, or else it will be returned as 'failed' but is saved
495 'failed_fields' => array()
498 // Init overall status and final output
502 // Check all data in session
503 foreach (array_keys($GLOBALS['installer_groups']) as $key) {
504 // Get values from session
505 $value = getSession($key);
507 // Is the data valid?
508 $verificationStatus['is_valid'] = (isInstallerDataValid($verificationStatus, $key, $value));
510 // Is this step okay?
511 if ($verificationStatus['is_valid'] === TRUE) {
512 // Add this key/value pair to a overview group
513 addKeyValueToInstallerOverviewGroup($key, $value);
516 // Save the overall status for below final check
517 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',value=' . $value . ',is_valid=' . intval($verificationStatus['is_valid']) . ',isAllValid=' . intval($isAllValid));
518 $isAllValid = (($isAllValid === TRUE) && ($verificationStatus['is_valid'] === TRUE));
522 if ((isInstallationDataCompleted()) && ($isAllValid === TRUE)) {
523 // Set 'done' and message
524 $verificationStatus['status'] = 'done';
525 $verificationStatus['message'] = '{--INSTALLER_OVERVIEW_FINAL_CHECK_DONE--}';
527 // Then do the post-check
528 doInstallerPostCheck($currentTab, $verificationStatus);
531 // Is it still valid?
532 if ($verificationStatus['status'] != 'done') {
534 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Final check on all stored data failed. message=' . $verificationStatus['message']);
536 // Process failed fields
537 $verificationStatus['failed_fields'] = handleInstallerFailedFields($verificationStatus['failed_fields']);
539 // Output the array for JSON reply
540 setAjaxReplyContent(loadTemplate('install_overview_failed', TRUE, $verificationStatus));
543 * Something went wrong, this might happen when e.g. the user has tried
544 * to save invalid database login data but hit reload button on error
547 setHttpStatus('200 OK');
554 // ----------------------------------------------------------------------------
555 // Call-back functions for doing installation steps
556 // ----------------------------------------------------------------------------
558 // Call-back function to import first tables.sql file
559 function doAjaxInstallerStepImportTablesSql () {
560 // Establish database link
561 establishAjaxInstallerDatabaseLink();
567 importInstallSqlDump('tables');
569 // Are some SQLs found?
570 if (countSqls() == 0) {
572 reportBug(__FUNCTION__, __LINE__, '{--INSTALLER_SQL_IMPORT_FAILED--}');
575 // Now run all queries through
576 runFilterChain('run_sqls');
579 SQL_CLOSE(__FUNCTION__, __LINE__);
582 // Call-back function to import menu SQL file
583 function doAjaxInstallerStepImportMenuSql () {
584 // Establish database link
585 establishAjaxInstallerDatabaseLink();
591 importInstallSqlDump('menu-' . getLanguage());
593 // Are some SQLs found?
594 if (countSqls() == 0) {
596 reportBug(__FUNCTION__, __LINE__, '{--INSTALLER_SQL_IMPORT_FAILED--}');
599 // Now run all queries through
600 runFilterChain('run_sqls');
603 SQL_CLOSE(__FUNCTION__, __LINE__);
606 // Call-back function to install some important extensions
607 function doAjaxInstallerStepInstallExtensions () {
608 // Only one element is required
609 if (!isSessionVariableSet('extensions')) {
610 // Some required session data is not set
611 reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.');
614 // Establish database link
615 establishAjaxInstallerDatabaseLink();
617 // Get all extensions
618 $extensions = explode(':', getSession('extensions'));
620 // Make sure ext-sql_patches is first
621 array_unshift($extensions, 'sql_patches');
623 // "Walk" through all extensions
624 foreach ($extensions as $key => $ext_name) {
625 // Is ext-sql_patches not at key=0?
626 if (($key == 0) && ($ext_name == 'sql_patches')) {
627 // Then skip this entry
629 } elseif ((!loadExtension($ext_name, 'test', '0.0.0', TRUE)) || (!registerExtension($ext_name, NULL))) {
631 reportBug(__FUNCTION__, __LINE__, 'Cannot load/register extension ' . $ext_name . '.');
636 // Call-back function to write local configuration file
637 function doAjaxInstallerStepWriteLocalConfig () {
639 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'))) {
640 // Some required session data is not set
641 reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.');
645 if (!doInstallWriteLocalConfigurationFile(
646 getSession('base_path'),
647 getSession('base_url'),
648 getSession('main_title'),
649 getSession('slogan'),
650 getSession('webmaster'),
651 getSession('warn_no_pass'),
652 getSession('write_footer'),
653 getSession('enable_backlink'),
654 getSession('mysql_host'),
655 getSession('mysql_dbase'),
656 getSession('mysql_login'),
657 getSession('mysql_password1'),
658 getSession('mysql_prefix'),
659 getSession('mysql_engine'),
660 getSession('smtp_host'),
661 getSession('smtp_user'),
662 getSession('smtp_password1')
664 // Something bad went wrong
665 removeFile(getSession('base_path') . getCachePath() . 'config-local.php');
666 reportBug(__FUNCTION__, __LINE__, 'Did not fully write config-local.php .');