qa-install.php 12.7 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
	// prevents browser content encoding error
	header('Content-Encoding: none');
64
}
65

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

74

Scott committed
75
// Process user handling higher up to avoid 'headers already sent' warning
76

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

Scott committed
82 83 84 85
	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');
86

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

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

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

Scott committed
98
			qa_set_option('feedback_email', $inemail);
Scott committed
99

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


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

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


Scott committed
127 128 129 130 131 132
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
133

Scott committed
134 135 136
		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
137

Scott committed
138 139
		case 'query':
			global $pass_failure_from_install;
Scott committed
140

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

Scott committed
151 152
	if (qa_clicked('create')) {
		qa_db_install_tables();
Scott committed
153

Scott committed
154 155 156 157
		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
158

Scott committed
159 160
				// 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
161

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

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

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

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

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

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

Scott committed
203
		$module = qa_load_module($moduletype, $modulename);
Scott committed
204

Scott committed
205
		$queries = $module->init_queries(qa_db_list_tables());
Scott committed
206

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

Scott committed
211 212
			foreach ($queries as $query)
				qa_db_upgrade_query($query);
Scott committed
213 214
		}

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

Scott committed
218
}
Scott committed
219

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

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

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

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

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

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

		case 'column-missing':
			$errorhtml .= 'One or more Question2Answer database tables are missing a column.';
272
			$buttons = array('repair' => 'Repair the Database');
Scott committed
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'),
283
					'email' => array('label' => 'Email address:', 'type' => 'email'),
Scott committed
284
				);
Scott committed
285
				$buttons = array('super' => 'Set up the Super Administrator');
Scott committed
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
			}
			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' => '',
							));

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

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

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

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

?>

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

<?php

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

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

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


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

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

Scott committed
358 359
	echo '</table>';
}
Scott committed
360

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

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

Scott committed
367
qa_db_disconnect();
Scott committed
368 369 370 371 372

?>

		</form>
	</body>
373
</html>