qa-install.php 12.6 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
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	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
22 23 24 25
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
	header('Location: ../');
	exit;
}
Scott committed
26

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

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


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

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

Scott committed
46 47 48 49 50
		$pass_failure_type = $type;
		$pass_failure_errno = $errno;
		$pass_failure_error = $error;
		$pass_failure_query = $query;
		$pass_failure_from_install = true;
Scott committed
51

Scott committed
52
		require QA_INCLUDE_DIR.'qa-install.php';
Scott committed
53

Scott committed
54
		qa_exit('error');
Scott committed
55
	}
Scott committed
56
}
Scott committed
57 58


59 60
if (ob_get_level() > 0) {
	// clears any current theme output to prevent broken design
61
	ob_end_clean();
62
}
63

Scott committed
64 65 66 67 68 69 70
$success = '';
$errorhtml = '';
$suggest = '';
$buttons = array();
$fields = array();
$fielderrors = array();
$hidden = array();
Scott committed
71

72

Scott committed
73
// Process user handling higher up to avoid 'headers already sent' warning
74

Scott committed
75
if (!isset($pass_failure_type) && qa_clicked('super')) {
Scott committed
76
	require_once QA_INCLUDE_DIR.'db/admin.php';
Scott committed
77 78
	require_once QA_INCLUDE_DIR.'db/users.php';
	require_once QA_INCLUDE_DIR.'app/users-edit.php';
79

Scott committed
80 81 82 83
	if (qa_db_count_users() == 0) { // prevent creating multiple accounts
		$inemail = qa_post_text('email');
		$inpassword = qa_post_text('password');
		$inhandle = qa_post_text('handle');
84

Scott committed
85 86 87 88
		$fielderrors = array_merge(
			qa_handle_email_filter($inhandle, $inemail),
			qa_password_validate($inpassword)
		);
89

Scott committed
90 91
		if (empty($fielderrors)) {
			require_once QA_INCLUDE_DIR.'app/users.php';
92

Scott committed
93 94
			$userid = qa_create_new_user($inemail, $inpassword, $inhandle, QA_USER_LEVEL_SUPER);
			qa_set_logged_in_user($userid, $inhandle);
95

Scott committed
96
			qa_set_option('feedback_email', $inemail);
Scott committed
97

Scott committed
98 99
			$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.";
		}
100
	}
Scott committed
101
}
102 103


Scott committed
104
// Output start of HTML early, so we can see a nicely-formatted list of database queries when upgrading
105 106 107 108 109 110 111 112 113

?><!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; }
114 115 116
			th, td { padding: 2px; }
			th { text-align: right; font-weight: normal; }
			td { text-align: left; }
Scott committed
117
			.msg-success { color: #090; }
118
			.msg-error { color: #b00; }
119 120 121 122 123 124
		</style>
	</head>
	<body>
<?php


Scott committed
125 126 127 128 129 130
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
131

Scott committed
132 133 134
		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
135

Scott committed
136 137
		case 'query':
			global $pass_failure_from_install;
Scott committed
138

Scott committed
139 140 141 142 143 144 145 146 147
			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
Scott committed
148

Scott committed
149 150
	if (qa_clicked('create')) {
		qa_db_install_tables();
Scott committed
151

Scott committed
152 153 154 155
		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
156

Scott committed
157 158
				// 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
159

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

Scott committed
162
			}
163 164 165 166 167 168 169 170 171
			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
172 173 174
			else {
				$success .= 'Your Question2Answer database has been created for external user identity management. Please read the online documentation to complete integration.';
			}
Scott committed
175
		}
Scott committed
176 177
		else {
			$success .= 'Your Question2Answer database has been created.';
Scott committed
178
		}
Scott committed
179
	}
Scott committed
180

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

Scott committed
186 187 188 189
	if (qa_clicked('upgrade')) {
		qa_db_upgrade_tables();
		$success .= 'Your Question2Answer database has been updated.';
	}
Scott committed
190

Scott committed
191 192 193 194
	if (qa_clicked('repair')) {
		qa_db_install_tables();
		$success .= 'The Question2Answer database tables have been repaired.';
	}
Scott committed
195

Scott committed
196
	qa_initialize_postdb_plugins();
Scott committed
197 198 199
	if (qa_clicked('module')) {
		$moduletype = qa_post_text('moduletype');
		$modulename = qa_post_text('modulename');
Scott committed
200

Scott committed
201
		$module = qa_load_module($moduletype, $modulename);
Scott committed
202

Scott committed
203
		$queries = $module->init_queries(qa_db_list_tables());
Scott committed
204

Scott committed
205 206 207
		if (!empty($queries)) {
			if (!is_array($queries))
				$queries = array($queries);
Scott committed
208

Scott committed
209 210
			foreach ($queries as $query)
				qa_db_upgrade_query($query);
Scott committed
211 212
		}

Scott committed
213
		$success .= 'The '.$modulename.' '.$moduletype.' module has completed database initialization.';
Scott committed
214 215
	}

Scott committed
216
}
Scott committed
217

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

Scott committed
221 222 223 224
	switch ($check) {
		case 'none':
			if (@$pass_failure_errno == 1146) // don't show error if we're in installation process
				$errorhtml = '';
Scott committed
225

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

Scott committed
228 229 230 231
			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.";
				}
232
				elseif (defined('QA_FINAL_JOOMLA_INTEGRATE_PATH')) {
233
					$jconfig = new JConfig();
234
					$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.";
235
				}
Scott committed
236 237
				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
238 239
				}

Scott committed
240
				$buttons = array('create' => 'Set up the Database');
Scott committed
241 242 243
			}
			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
244
				$buttons = array('create' => 'Set up the Database including User Management');
Scott committed
245 246 247 248 249 250 251 252 253 254
			}
			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.';
255
			$buttons = array('upgrade' => 'Upgrade the Database');
Scott committed
256 257 258 259
			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
260
			$buttons = array('nonuser' => 'Set up the Tables');
Scott committed
261 262 263 264
			break;

		case 'table-missing':
			$errorhtml .= 'One or more tables are missing from your Question2Answer database.';
265
			$buttons = array('repair' => 'Repair the Database');
Scott committed
266 267 268 269
			break;

		case 'column-missing':
			$errorhtml .= 'One or more Question2Answer database tables are missing a column.';
270
			$buttons = array('repair' => 'Repair the Database');
Scott committed
271 272 273 274 275 276 277 278 279 280 281 282
			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
283
				$buttons = array('super' => 'Set up the Super Administrator');
Scott committed
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
			}
			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' => '',
							));

304
							$buttons = array('module' => 'Initialize the Database');
Scott committed
305 306 307 308

							$hidden['moduletype'] = $moduletype;
							$hidden['modulename'] = $modulename;
							break;
Scott committed
309 310 311
						}
					}
				}
Scott committed
312 313
			}
			break;
Scott committed
314
	}
Scott committed
315
}
Scott committed
316

Scott committed
317 318 319
if (empty($errorhtml)) {
	if (empty($success))
		$success = 'Your Question2Answer database has been checked with no problems.';
Scott committed
320

Scott committed
321 322
	$suggest = '<a href="'.qa_path_html('admin', null, null, QA_URL_FORMAT_SAFEST).'">Go to admin center</a>';
}
Scott committed
323 324 325 326 327 328 329

?>

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

<?php

Scott committed
330 331
if (strlen($success))
	echo '<p class="msg-success">'.nl2br(qa_html($success)).'</p>';
Scott committed
332

Scott committed
333 334
if (strlen($errorhtml))
	echo '<p class="msg-error">'.nl2br($errorhtml).'</p>';
Scott committed
335

Scott committed
336 337
if (strlen($suggest))
	echo '<p>'.$suggest.'</p>';
Scott committed
338 339


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

Scott committed
342 343 344 345 346 347 348 349 350 351 352 353 354
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
355

Scott committed
356 357
	echo '</table>';
}
Scott committed
358

Scott committed
359 360
foreach ($buttons as $name => $value)
	echo '<input type="submit" name="'.qa_html($name).'" value="'.qa_html($value).'">';
Scott committed
361

Scott committed
362 363
foreach ($hidden as $name => $value)
	echo '<input type="hidden" name="'.qa_html($name).'" value="'.qa_html($value).'">';
Scott committed
364

Scott committed
365
qa_db_disconnect();
Scott committed
366 367 368 369 370

?>

		</form>
	</body>
371
</html>