qa-install.php 11.3 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
			}
			else {
				$success .= 'Your Question2Answer database has been created for external user identity management. Please read the online documentation to complete integration.';
			}
Scott committed
156
		}
Scott committed
157 158
		else {
			$success .= 'Your Question2Answer database has been created.';
Scott committed
159
		}
Scott committed
160
	}
Scott committed
161

Scott committed
162 163 164 165
	if (qa_clicked('nonuser')) {
		qa_db_install_tables();
		$success .= 'The additional Question2Answer database tables have been created.';
	}
Scott committed
166

Scott committed
167 168 169 170
	if (qa_clicked('upgrade')) {
		qa_db_upgrade_tables();
		$success .= 'Your Question2Answer database has been updated.';
	}
Scott committed
171

Scott committed
172 173 174 175
	if (qa_clicked('repair')) {
		qa_db_install_tables();
		$success .= 'The Question2Answer database tables have been repaired.';
	}
Scott committed
176

Scott committed
177 178 179
	if (qa_clicked('module')) {
		$moduletype = qa_post_text('moduletype');
		$modulename = qa_post_text('modulename');
Scott committed
180

Scott committed
181
		$module = qa_load_module($moduletype, $modulename);
Scott committed
182

Scott committed
183
		$queries = $module->init_queries(qa_db_list_tables());
Scott committed
184

Scott committed
185 186 187
		if (!empty($queries)) {
			if (!is_array($queries))
				$queries = array($queries);
Scott committed
188

Scott committed
189 190
			foreach ($queries as $query)
				qa_db_upgrade_query($query);
Scott committed
191 192
		}

Scott committed
193
		$success .= 'The '.$modulename.' '.$moduletype.' module has completed database initialization.';
Scott committed
194 195
	}

Scott committed
196
}
Scott committed
197

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

Scott committed
201 202 203 204
	switch ($check) {
		case 'none':
			if (@$pass_failure_errno == 1146) // don't show error if we're in installation process
				$errorhtml = '';
Scott committed
205

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

Scott committed
208 209 210 211 212 213
			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.";
				}
				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
214 215
				}

Scott committed
216
				$buttons = array('create' => 'Set up the Database');
Scott committed
217 218 219
			}
			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
220
				$buttons = array('create' => 'Set up the Database including User Management');
Scott committed
221 222 223 224 225 226 227 228 229 230
			}
			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.';
231
			$buttons = array('upgrade' => 'Upgrade the Database');
Scott committed
232 233 234 235
			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
236
			$buttons = array('nonuser' => 'Set up the Tables');
Scott committed
237 238 239 240
			break;

		case 'table-missing':
			$errorhtml .= 'One or more tables are missing from your Question2Answer database.';
241
			$buttons = array('repair' => 'Repair the Database');
Scott committed
242 243 244 245
			break;

		case 'column-missing':
			$errorhtml .= 'One or more Question2Answer database tables are missing a column.';
246
			$buttons = array('repair' => 'Repair the Database');
Scott committed
247 248 249 250 251 252 253 254 255 256 257 258
			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
259
				$buttons = array('super' => 'Set up the Super Administrator');
Scott committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
			}
			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' => '',
							));

280
							$buttons = array('module' => 'Initialize the Database');
Scott committed
281 282 283 284

							$hidden['moduletype'] = $moduletype;
							$hidden['modulename'] = $modulename;
							break;
Scott committed
285 286 287
						}
					}
				}
Scott committed
288 289
			}
			break;
Scott committed
290
	}
Scott committed
291
}
Scott committed
292

Scott committed
293 294 295
if (empty($errorhtml)) {
	if (empty($success))
		$success = 'Your Question2Answer database has been checked with no problems.';
Scott committed
296

Scott committed
297 298
	$suggest = '<a href="'.qa_path_html('admin', null, null, QA_URL_FORMAT_SAFEST).'">Go to admin center</a>';
}
Scott committed
299 300 301 302 303 304 305

?>

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

<?php

Scott committed
306 307
if (strlen($success))
	echo '<p class="msg-success">'.nl2br(qa_html($success)).'</p>';
Scott committed
308

Scott committed
309 310
if (strlen($errorhtml))
	echo '<p class="msg-error">'.nl2br($errorhtml).'</p>';
Scott committed
311

Scott committed
312 313
if (strlen($suggest))
	echo '<p>'.$suggest.'</p>';
Scott committed
314 315 316 317


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

Scott committed
318 319 320 321 322 323 324 325 326 327 328 329 330
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
331

Scott committed
332 333
	echo '</table>';
}
Scott committed
334

Scott committed
335 336
foreach ($buttons as $name => $value)
	echo '<input type="submit" name="'.qa_html($name).'" value="'.qa_html($value).'">';
Scott committed
337

Scott committed
338 339
foreach ($hidden as $name => $value)
	echo '<input type="hidden" name="'.qa_html($name).'" value="'.qa_html($value).'">';
Scott committed
340

Scott committed
341
qa_db_disconnect();
Scott committed
342 343 344 345 346

?>

		</form>
	</body>
347
</html>