qa-install.php 12.4 KB
Newer Older
Scott committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	File: qa-include/qa-install.php
	Description: User interface for installing, upgrading and fixing the database


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

Scott committed
23 24 25 26
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
	header('Location: ../');
	exit;
}
Scott committed
27

Scott committed
28
require_once QA_INCLUDE_DIR.'db/install.php';
Scott committed
29

Scott committed
30
qa_report_process_stage('init_install');
Scott committed
31 32


Scott committed
33
// Define database failure handler for install process, if not defined already (file could be included more than once)
Scott committed
34

Scott committed
35 36 37 38 39 40 41
if (!function_exists('qa_install_db_fail_handler')) {
	/**
	 * Handler function for database failures during the installation process
	 */
	function qa_install_db_fail_handler($type, $errno=null, $error=null, $query=null)
	{
		global $pass_failure_from_install;
Scott committed
42

Scott committed
43 44 45 46 47
		$pass_failure_type = $type;
		$pass_failure_errno = $errno;
		$pass_failure_error = $error;
		$pass_failure_query = $query;
		$pass_failure_from_install = true;
Scott committed
48

Scott committed
49
		require QA_INCLUDE_DIR.'qa-install.php';
Scott committed
50

Scott committed
51
		qa_exit('error');
Scott committed
52
	}
Scott committed
53
}
Scott committed
54 55


Scott committed
56 57 58 59 60 61 62
$success = '';
$errorhtml = '';
$suggest = '';
$buttons = array();
$fields = array();
$fielderrors = array();
$hidden = array();
Scott committed
63

64

Scott committed
65
// Process user handling higher up to avoid 'headers already sent' warning
66

Scott committed
67 68 69
if (!isset($pass_failure_type) && qa_clicked('super')) {
	require_once QA_INCLUDE_DIR.'db/users.php';
	require_once QA_INCLUDE_DIR.'app/users-edit.php';
70

Scott committed
71 72 73
	$inemail = qa_post_text('email');
	$inpassword = qa_post_text('password');
	$inhandle = qa_post_text('handle');
74

Scott committed
75 76 77 78
	$fielderrors = array_merge(
		qa_handle_email_filter($inhandle, $inemail),
		qa_password_validate($inpassword)
	);
79

Scott committed
80 81
	if (empty($fielderrors)) {
		require_once QA_INCLUDE_DIR.'app/users.php';
82

Scott committed
83 84
		$userid = qa_create_new_user($inemail, $inpassword, $inhandle, QA_USER_LEVEL_SUPER);
		qa_set_logged_in_user($userid, $inhandle);
85

Scott committed
86 87 88
		qa_set_option('feedback_email', $inemail);

		$success .= "Congratulations - Your Question2Answer site is ready to go!\n\nYou are logged in as the super administrator and can start changing settings.\n\nThank you for installing Question2Answer.";
89
	}
Scott committed
90
}
91 92 93 94 95 96 97 98 99 100 101 102


//	Output start of HTML early, so we can see a nicely-formatted list of database queries when upgrading

?><!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body, input { font: 16px Verdana, Arial, Helvetica, sans-serif; }
			body { text-align: center; width: 640px; margin: 64px auto; }
			table { margin: 16px auto; }
103 104 105
			th, td { padding: 2px; }
			th { text-align: right; font-weight: normal; }
			td { text-align: left; }
Scott committed
106
			.msg-success { color: #090; }
107
			.msg-error { color: #b00; }
108 109 110 111 112 113
		</style>
	</head>
	<body>
<?php


Scott committed
114 115 116 117 118 119
if (isset($pass_failure_type)) {
	// this page was requested due to query failure, via the fail handler
	switch ($pass_failure_type) {
		case 'connect':
			$errorhtml .= 'Could not establish database connection. Please check the username, password and hostname in the config file, and if necessary set up the appropriate MySQL user and privileges.';
			break;
Scott committed
120

Scott committed
121 122 123
		case 'select':
			$errorhtml .= 'Could not switch to the Question2Answer database. Please check the database name in the config file, and if necessary create the database in MySQL and grant appropriate user privileges.';
			break;
Scott committed
124

Scott committed
125 126
		case 'query':
			global $pass_failure_from_install;
Scott committed
127

Scott committed
128 129 130 131 132 133 134 135 136 137
			if (@$pass_failure_from_install)
				$errorhtml .= "Question2Answer was unable to perform the installation query below. Please check the user in the config file has CREATE and ALTER permissions:\n\n".qa_html($pass_failure_query."\n\nError ".$pass_failure_errno.": ".$pass_failure_error."\n\n");
			else
				$errorhtml .= "A Question2Answer database query failed when generating this page.\n\nA full description of the failure is available in the web server's error log file.";
			break;
	}
}
else {
	// this page was requested by user GET/POST, so handle any incoming clicks on buttons
	qa_db_connect('qa_install_db_fail_handler');
Scott committed
138

Scott committed
139 140
	if (qa_clicked('create')) {
		qa_db_install_tables();
Scott committed
141

Scott committed
142 143 144 145
		if (QA_FINAL_EXTERNAL_USERS) {
			if (defined('QA_FINAL_WORDPRESS_INTEGRATE_PATH')) {
				require_once QA_INCLUDE_DIR.'db/admin.php';
				require_once QA_INCLUDE_DIR.'app/format.php';
Scott committed
146

Scott committed
147 148
				// create link back to WordPress home page
				qa_db_page_move(qa_db_page_create(get_option('blogname'), QA_PAGE_FLAGS_EXTERNAL, get_option('home'), null, null, null), 'O', 1);
Scott committed
149

Scott committed
150
				$success .= 'Your Question2Answer database has been created and integrated with your WordPress site.';
Scott committed
151

Scott committed
152
			}
153 154 155 156 157 158 159 160 161
			elseif (defined('QA_FINAL_JOOMLA_INTEGRATE_PATH')) {
				require_once QA_INCLUDE_DIR.'db/admin.php';
				require_once QA_INCLUDE_DIR.'app/format.php';
				$jconfig = new JConfig();

				// create link back to Joomla! home page (Joomla doesn't have a 'home' config setting we can use like WP does, so we'll just assume that the Joomla home is the parent of the Q2A site. If it isn't, the user can fix the link for themselves later)
				qa_db_page_move(qa_db_page_create($jconfig->sitename, QA_PAGE_FLAGS_EXTERNAL, '../', null, null, null), 'O', 1);
				$success .= 'Your Question2Answer database has been created and integrated with your Joomla! site.';
			}
Scott committed
162 163 164
			else {
				$success .= 'Your Question2Answer database has been created for external user identity management. Please read the online documentation to complete integration.';
			}
Scott committed
165
		}
Scott committed
166 167
		else {
			$success .= 'Your Question2Answer database has been created.';
Scott committed
168
		}
Scott committed
169
	}
Scott committed
170

Scott committed
171 172 173 174
	if (qa_clicked('nonuser')) {
		qa_db_install_tables();
		$success .= 'The additional Question2Answer database tables have been created.';
	}
Scott committed
175

Scott committed
176 177 178 179
	if (qa_clicked('upgrade')) {
		qa_db_upgrade_tables();
		$success .= 'Your Question2Answer database has been updated.';
	}
Scott committed
180

Scott committed
181 182 183 184
	if (qa_clicked('repair')) {
		qa_db_install_tables();
		$success .= 'The Question2Answer database tables have been repaired.';
	}
Scott committed
185

Scott committed
186 187 188
	if (qa_clicked('module')) {
		$moduletype = qa_post_text('moduletype');
		$modulename = qa_post_text('modulename');
Scott committed
189

Scott committed
190
		$module = qa_load_module($moduletype, $modulename);
Scott committed
191

Scott committed
192
		$queries = $module->init_queries(qa_db_list_tables());
Scott committed
193

Scott committed
194 195 196
		if (!empty($queries)) {
			if (!is_array($queries))
				$queries = array($queries);
Scott committed
197

Scott committed
198 199
			foreach ($queries as $query)
				qa_db_upgrade_query($query);
Scott committed
200 201
		}

Scott committed
202
		$success .= 'The '.$modulename.' '.$moduletype.' module has completed database initialization.';
Scott committed
203 204
	}

Scott committed
205
}
Scott committed
206

Scott committed
207 208
if (qa_db_connection(false) !== null && !@$pass_failure_from_install) {
	$check = qa_db_check_tables(); // see where the database is at
Scott committed
209

Scott committed
210 211 212 213
	switch ($check) {
		case 'none':
			if (@$pass_failure_errno == 1146) // don't show error if we're in installation process
				$errorhtml = '';
Scott committed
214

Scott committed
215
			$errorhtml .= 'Welcome to Question2Answer. It\'s time to set up your database!';
Scott committed
216

Scott committed
217 218 219 220
			if (QA_FINAL_EXTERNAL_USERS) {
				if (defined('QA_FINAL_WORDPRESS_INTEGRATE_PATH')) {
					$errorhtml .= "\n\nWhen you click below, your Question2Answer site will be set up to integrate with the users of your WordPress site <a href=\"".qa_html(get_option('home'))."\" target=\"_blank\">".qa_html(get_option('blogname'))."</a>. Please consult the online documentation for more information.";
				}
221 222
				elseif (defined('QA_FINAL_JOOMLA_INTEGRATE_PATH')) {
                    $jconfig = new JConfig();
223
					$errorhtml .= "\n\nWhen you click below, your Question2Answer site will be set up to integrate with the users of your Joomla! site <a href=\"../\" target=\"_blank\">".$jconfig->sitename."</a>. It's also recommended to install the Joomla QAIntegration plugin for additional user-access control. Please consult the online documentation for more information.";
224
				}
Scott committed
225 226
				else {
					$errorhtml .= "\n\nWhen you click below, your Question2Answer site will be set up to integrate with your existing user database and management. Users will be referenced with database column type ".qa_html(qa_get_mysql_user_column_type()).". Please consult the online documentation for more information.";
Scott committed
227 228
				}

Scott committed
229
				$buttons = array('create' => 'Set up the Database');
Scott committed
230 231 232
			}
			else {
				$errorhtml .= "\n\nWhen you click below, your Question2Answer database will be set up to manage user identities and logins internally.\n\nIf you want to offer a single sign-on for an existing user base or website, please consult the online documentation before proceeding.";
Scott committed
233
				$buttons = array('create' => 'Set up the Database including User Management');
Scott committed
234 235 236 237 238 239 240 241 242 243
			}
			break;

		case 'old-version':
			// don't show error if we need to upgrade
			if (!@$pass_failure_from_install)
				$errorhtml = '';

			// don't show error before this
			$errorhtml .= 'Your Question2Answer database needs to be upgraded for this version of the software.';
244
			$buttons = array('upgrade' => 'Upgrade the Database');
Scott committed
245 246 247 248
			break;

		case 'non-users-missing':
			$errorhtml = 'This Question2Answer site is sharing its users with another Q2A site, but it needs some additional database tables for its own content. Please click below to create them.';
Scott committed
249
			$buttons = array('nonuser' => 'Set up the Tables');
Scott committed
250 251 252 253
			break;

		case 'table-missing':
			$errorhtml .= 'One or more tables are missing from your Question2Answer database.';
254
			$buttons = array('repair' => 'Repair the Database');
Scott committed
255 256 257 258
			break;

		case 'column-missing':
			$errorhtml .= 'One or more Question2Answer database tables are missing a column.';
259
			$buttons = array('repair' => 'Repair the Database');
Scott committed
260 261 262 263 264 265 266 267 268 269 270 271
			break;

		default:
			require_once QA_INCLUDE_DIR.'db/admin.php';

			if (!QA_FINAL_EXTERNAL_USERS && qa_db_count_users() == 0) {
				$errorhtml .= "There are currently no users in the Question2Answer database.\n\nPlease enter your details below to create the super administrator:";
				$fields = array(
					'handle' => array('label' => 'Username:', 'type' => 'text'),
					'password' => array('label' => 'Password:', 'type' => 'password'),
					'email' => array('label' => 'Email address:', 'type' => 'text'),
				);
Scott committed
272
				$buttons = array('super' => 'Set up the Super Administrator');
Scott committed
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
			}
			else {
				$tables = qa_db_list_tables();

				$moduletypes = qa_list_module_types();

				foreach ($moduletypes as $moduletype) {
					$modules = qa_load_modules_with($moduletype, 'init_queries');

					foreach ($modules as $modulename => $module) {
						$queries = $module->init_queries($tables);
						if (!empty($queries)) {
							// also allows single query to be returned
							$errorhtml = strtr(qa_lang_html('admin/module_x_database_init'), array(
								'^1' => qa_html($modulename),
								'^2' => qa_html($moduletype),
								'^3' => '',
								'^4' => '',
							));

293
							$buttons = array('module' => 'Initialize the Database');
Scott committed
294 295 296 297

							$hidden['moduletype'] = $moduletype;
							$hidden['modulename'] = $modulename;
							break;
Scott committed
298 299 300
						}
					}
				}
Scott committed
301 302
			}
			break;
Scott committed
303
	}
Scott committed
304
}
Scott committed
305

Scott committed
306 307 308
if (empty($errorhtml)) {
	if (empty($success))
		$success = 'Your Question2Answer database has been checked with no problems.';
Scott committed
309

Scott committed
310 311
	$suggest = '<a href="'.qa_path_html('admin', null, null, QA_URL_FORMAT_SAFEST).'">Go to admin center</a>';
}
Scott committed
312 313 314 315 316 317 318

?>

		<form method="post" action="<?php echo qa_path_html('install', null, null, QA_URL_FORMAT_SAFEST)?>">

<?php

Scott committed
319 320
if (strlen($success))
	echo '<p class="msg-success">'.nl2br(qa_html($success)).'</p>';
Scott committed
321

Scott committed
322 323
if (strlen($errorhtml))
	echo '<p class="msg-error">'.nl2br($errorhtml).'</p>';
Scott committed
324

Scott committed
325 326
if (strlen($suggest))
	echo '<p>'.$suggest.'</p>';
Scott committed
327 328 329 330


//	Very simple general form display logic (we don't use theme since it depends on tons of DB options)

Scott committed
331 332 333 334 335 336 337 338 339 340 341 342 343
if (count($fields)) {
	echo '<table>';

	foreach ($fields as $name => $field) {
		echo '<tr>';
		echo '<th>'.qa_html($field['label']).'</th>';
		echo '<td><input type="'.qa_html($field['type']).'" size="24" name="'.qa_html($name).'" value="'.qa_html(@${'in'.$name}).'"></td>';
		if (isset($fielderrors[$name]))
			echo '<td class="msg-error"><small>'.qa_html($fielderrors[$name]).'</small></td>';
		else
			echo '<td></td>';
		echo '</tr>';
	}
Scott committed
344

Scott committed
345 346
	echo '</table>';
}
Scott committed
347

Scott committed
348 349
foreach ($buttons as $name => $value)
	echo '<input type="submit" name="'.qa_html($name).'" value="'.qa_html($value).'">';
Scott committed
350

Scott committed
351 352
foreach ($hidden as $name => $value)
	echo '<input type="hidden" name="'.qa_html($name).'" value="'.qa_html($value).'">';
Scott committed
353

Scott committed
354
qa_db_disconnect();
Scott committed
355 356 357 358 359

?>

		</form>
	</body>
360
</html>