improve scoring to store to presubmitted localhost, fix style and
[ViQa-Kissu.git] / install.php
blob61b1137971e98af653272ba95a271dae80cd55a4
1 <?php
2 echo "<pre>";
3 // Installation/upgrade file
4 define('VERSION', '6.1.2');
5 require 'inc/functions.php';
6 loadConfig();
8 // Salt generators
9 class SaltGen {
10 public $salt_length = 128;
12 // Best function I could think of for non-SSL PHP 5
13 private function generate_install_salt() {
14 $ret = "";
16 // This is bad! But what else can we do sans OpenSSL?
17 for ($i = 0; $i < $this->salt_length; ++$i) {
18 $s = pack("c", mt_rand(0,255));
19 $ret = $ret . $s;
22 return base64_encode($ret);
25 // Best function of the lot. Works with any PHP version as long as OpenSSL extension is on
26 private function generate_install_salt_openssl() {
27 $ret = openssl_random_pseudo_bytes($this->salt_length, $strong);
28 if (!$strong) {
29 error(_("Misconfigured system: OpenSSL returning weak salts. Cannot continue."));
31 return base64_encode($ret);
34 private function generate_install_salt_php7() {
35 return base64_encode(random_bytes($this->salt_length));
38 // TODO: Perhaps add mcrypt as an option? Maybe overkill.
39 public function generate() {
40 if (extension_loaded('openssl')) {
41 return "OSSL." . $this->generate_install_salt_openssl();
42 } else if (defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION >= 7) {
43 return "PHP7." . $this->generate_install_salt_php7();
44 } else {
45 return "INSECURE." . $this->generate_install_salt();
50 $step = isset($_GET['step']) ? round($_GET['step']) : 0;
51 $page = array(
52 'config' => $config,
53 'title' => 'Install',
54 'body' => '',
55 'nojavascript' => true
58 // this breaks the display of licenses if enabled
59 $config['minify_html'] = false;
61 if (file_exists($config['has_installed'])) {
63 // Check the version number
64 $version = trim(file_get_contents($config['has_installed']));
65 if (empty($version))
66 $version = 'v0.9.1';
68 function __query($sql) {
69 sql_open();
71 if (mysql_version() >= 50503)
72 return query($sql);
73 else
74 return query(str_replace('utf8mb4', 'utf8', $sql));
77 $boards = listBoards();
79 switch ($version) {
80 case 'v0.9':
81 case 'v0.9.1':
82 // Upgrade to v0.9.2-dev
84 foreach ($boards as &$_board) {
85 // Add `capcode` field after `trip`
86 query(sprintf("ALTER TABLE `posts_%s` ADD `capcode` VARCHAR( 50 ) NULL AFTER `trip`", $_board['uri'])) or error(db_error());
88 // Resize `trip` to 15 characters
89 query(sprintf("ALTER TABLE `posts_%s` CHANGE `trip` `trip` VARCHAR( 15 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL", $_board['uri'])) or error(db_error());
91 case 'v0.9.2-dev':
92 // Upgrade to v0.9.2-dev-1
94 // New table: `theme_settings`
95 query("CREATE TABLE IF NOT EXISTS `theme_settings` ( `name` varchar(40) NOT NULL, `value` text, UNIQUE KEY `name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;") or error(db_error());
97 // New table: `news`
98 query("CREATE TABLE IF NOT EXISTS `news` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text NOT NULL, `time` int(11) NOT NULL, `subject` text NOT NULL, `body` text NOT NULL, UNIQUE KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;") or error(db_error());
99 case 'v0.9.2.1-dev':
100 case 'v0.9.2-dev-1':
101 // Fix broken version number/mistake
102 $version = 'v0.9.2-dev-1';
103 // Upgrade to v0.9.2-dev-2
105 foreach ($boards as &$_board) {
106 // Increase field sizes
107 query(sprintf("ALTER TABLE `posts_%s` CHANGE `subject` `subject` VARCHAR( 50 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL", $_board['uri'])) or error(db_error());
108 query(sprintf("ALTER TABLE `posts_%s` CHANGE `name` `name` VARCHAR( 35 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL", $_board['uri'])) or error(db_error());
110 case 'v0.9.2-dev-2':
111 // Upgrade to v0.9.2-dev-3 (v0.9.2)
113 foreach ($boards as &$_board) {
114 // Add `custom_fields` field
115 query(sprintf("ALTER TABLE `posts_%s` ADD `embed` TEXT NULL", $_board['uri'])) or error(db_error());
117 case 'v0.9.2-dev-3': // v0.9.2-dev-3 == v0.9.2
118 case 'v0.9.2':
119 // Upgrade to v0.9.3-dev-1
121 // Upgrade `theme_settings` table
122 query("TRUNCATE TABLE `theme_settings`") or error(db_error());
123 query("ALTER TABLE `theme_settings` ADD `theme` VARCHAR( 40 ) NOT NULL FIRST") or error(db_error());
124 query("ALTER TABLE `theme_settings` CHANGE `name` `name` VARCHAR( 40 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL") or error(db_error());
125 query("ALTER TABLE `theme_settings` DROP INDEX `name`") or error(db_error());
126 case 'v0.9.3-dev-1':
127 query("ALTER TABLE `mods` ADD `boards` TEXT NOT NULL") or error(db_error());
128 query("UPDATE `mods` SET `boards` = '*'") or error(db_error());
129 case 'v0.9.3-dev-2':
130 foreach ($boards as &$_board) {
131 query(sprintf("ALTER TABLE `posts_%s` CHANGE `filehash` `filehash` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL", $_board['uri'])) or error(db_error());
133 case 'v0.9.3-dev-3':
134 // Board-specifc bans
135 query("ALTER TABLE `bans` ADD `board` SMALLINT NULL AFTER `reason`") or error(db_error());
136 case 'v0.9.3-dev-4':
137 // add ban ID
138 query("ALTER TABLE `bans` ADD `id` INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY ( `id` ), ADD UNIQUE (`id`)");
139 case 'v0.9.3-dev-5':
140 foreach ($boards as &$_board) {
141 // Increase subject field size
142 query(sprintf("ALTER TABLE `posts_%s` CHANGE `subject` `subject` VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL", $_board['uri'])) or error(db_error());
144 case 'v0.9.3-dev-6':
145 // change to MyISAM
146 $tables = array(
147 'bans', 'boards', 'ip_notes', 'modlogs', 'mods', 'mutes', 'noticeboard', 'pms', 'reports', 'robot', 'theme_settings', 'news'
149 foreach ($boards as &$board) {
150 $tables[] = "posts_{$board['uri']}";
153 foreach ($tables as &$table) {
154 query("ALTER TABLE `{$table}` ENGINE = MYISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci") or error(db_error());
156 case 'v0.9.3-dev-7':
157 foreach ($boards as &$board) {
158 query(sprintf("ALTER TABLE `posts_%s` CHANGE `filename` `filename` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL", $board['uri'])) or error(db_error());
160 case 'v0.9.3-dev-8':
161 foreach ($boards as &$board) {
162 query(sprintf("ALTER TABLE `posts_%s` ADD INDEX ( `thread` )", $board['uri'])) or error(db_error());
164 case 'v0.9.3-dev-9':
165 foreach ($boards as &$board) {
166 query(sprintf("ALTER TABLE `posts_%s`ADD INDEX ( `time` )", $board['uri'])) or error(db_error());
167 query(sprintf("ALTER TABLE `posts_%s`ADD FULLTEXT (`body`)", $board['uri'])) or error(db_error());
169 case 'v0.9.3-dev-10':
170 case 'v0.9.3':
171 query("ALTER TABLE `bans` DROP INDEX `id`") or error(db_error());
172 query("ALTER TABLE `pms` DROP INDEX `id`") or error(db_error());
173 query("ALTER TABLE `boards` DROP PRIMARY KEY") or error(db_error());
174 query("ALTER TABLE `reports` DROP INDEX `id`") or error(db_error());
175 query("ALTER TABLE `boards` DROP INDEX `uri`") or error(db_error());
177 query("ALTER IGNORE TABLE `robot` ADD PRIMARY KEY (`hash`)") or error(db_error());
178 query("ALTER TABLE `bans` ADD FULLTEXT (`ip`)") or error(db_error());
179 query("ALTER TABLE `ip_notes` ADD INDEX (`ip`)") or error(db_error());
180 query("ALTER TABLE `modlogs` ADD INDEX (`time`)") or error(db_error());
181 query("ALTER TABLE `boards` ADD PRIMARY KEY(`uri`)") or error(db_error());
182 query("ALTER TABLE `mutes` ADD INDEX (`ip`)") or error(db_error());
183 query("ALTER TABLE `news` ADD INDEX (`time`)") or error(db_error());
184 query("ALTER TABLE `theme_settings` ADD INDEX (`theme`)") or error(db_error());
185 case 'v0.9.4-dev-1':
186 foreach ($boards as &$board) {
187 query(sprintf("ALTER TABLE `posts_%s` ADD `sage` INT( 1 ) NOT NULL AFTER `locked`", $board['uri'])) or error(db_error());
189 case 'v0.9.4-dev-2':
190 if (!isset($_GET['confirm'])) {
191 $page['title'] = 'License Change';
192 $page['body'] = '<p style="text-align:center">You are upgrading to a version which uses an amended license. The licenses included with Tinyboard distributions prior to this version (v0.9.4-dev-2) are still valid for those versions, but no longer apply to this and newer versions.</p>' .
193 '<textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black" disabled>' . htmlentities(file_get_contents('LICENSE.md')) . '</textarea>
194 <p style="text-align:center">
195 <a href="?confirm=1">I have read and understood the agreement. Proceed to upgrading.</a>
196 </p>';
198 file_write($config['has_installed'], 'v0.9.4-dev-2');
200 break;
202 case 'v0.9.4-dev-3':
203 case 'v0.9.4-dev-4':
204 case 'v0.9.4':
205 foreach ($boards as &$board) {
206 query(sprintf("ALTER TABLE `posts_%s`
207 CHANGE `subject` `subject` VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
208 CHANGE `email` `email` VARCHAR( 30 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
209 CHANGE `name` `name` VARCHAR( 35 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL", $board['uri'])) or error(db_error());
211 case 'v0.9.5-dev-1':
212 foreach ($boards as &$board) {
213 query(sprintf("ALTER TABLE `posts_%s` ADD `body_nomarkup` TEXT NULL AFTER `body`", $board['uri'])) or error(db_error());
215 query("CREATE TABLE IF NOT EXISTS `cites` ( `board` varchar(8) NOT NULL, `post` int(11) NOT NULL, `target_board` varchar(8) NOT NULL, `target` int(11) NOT NULL, KEY `target` (`target_board`,`target`), KEY `post` (`board`,`post`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;") or error(db_error());
216 case 'v0.9.5-dev-2':
217 query("ALTER TABLE `boards`
218 CHANGE `uri` `uri` VARCHAR( 15 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
219 CHANGE `title` `title` VARCHAR( 40 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
220 CHANGE `subtitle` `subtitle` VARCHAR( 120 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL") or error(db_error());
221 case 'v0.9.5-dev-3':
222 // v0.9.5
223 case 'v0.9.5':
224 query("ALTER TABLE `boards`
225 CHANGE `uri` `uri` VARCHAR( 50 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
226 CHANGE `title` `title` TINYTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
227 CHANGE `subtitle` `subtitle` TINYTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL") or error(db_error());
228 case 'v0.9.6-dev-1':
229 query("CREATE TABLE IF NOT EXISTS `antispam` (
230 `board` varchar(255) NOT NULL,
231 `thread` int(11) DEFAULT NULL,
232 `hash` bigint(20) NOT NULL,
233 `created` int(11) NOT NULL,
234 `expires` int(11) DEFAULT NULL,
235 `passed` smallint(6) NOT NULL,
236 PRIMARY KEY (`hash`),
237 KEY `board` (`board`,`thread`)
238 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;") or error(db_error());
239 case 'v0.9.6-dev-2':
240 query("ALTER TABLE `boards`
241 DROP `id`,
242 CHANGE `uri` `uri` VARCHAR( 120 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL") or error(db_error());
243 query("ALTER TABLE `bans` CHANGE `board` `board` VARCHAR( 120 ) NULL DEFAULT NULL") or error(db_error());
244 query("ALTER TABLE `reports` CHANGE `board` `board` VARCHAR( 120 ) NULL DEFAULT NULL") or error(db_error());
245 query("ALTER TABLE `modlogs` CHANGE `board` `board` VARCHAR( 120 ) NULL DEFAULT NULL") or error(db_error());
246 foreach ($boards as $board) {
247 $query = prepare("UPDATE `bans` SET `board` = :newboard WHERE `board` = :oldboard");
248 $query->bindValue(':newboard', $board['uri']);
249 $query->bindValue(':oldboard', $board['id']);
250 $query->execute() or error(db_error($query));
252 $query = prepare("UPDATE `modlogs` SET `board` = :newboard WHERE `board` = :oldboard");
253 $query->bindValue(':newboard', $board['uri']);
254 $query->bindValue(':oldboard', $board['id']);
255 $query->execute() or error(db_error($query));
257 $query = prepare("UPDATE `reports` SET `board` = :newboard WHERE `board` = :oldboard");
258 $query->bindValue(':newboard', $board['uri']);
259 $query->bindValue(':oldboard', $board['id']);
260 $query->execute() or error(db_error($query));
262 case 'v0.9.6-dev-3':
263 query("ALTER TABLE `antispam` CHANGE `hash` `hash` CHAR( 40 ) NOT NULL") or error(db_error());
264 case 'v0.9.6-dev-4':
265 query("ALTER TABLE `news` DROP INDEX `id`, ADD PRIMARY KEY ( `id` )") or error(db_error());
266 case 'v0.9.6-dev-5':
267 query("ALTER TABLE `bans` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT") or error(db_error());
268 query("ALTER TABLE `mods` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT") or error(db_error());
269 query("ALTER TABLE `news` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT") or error(db_error());
270 query("ALTER TABLE `noticeboard` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT") or error(db_error());
271 query("ALTER TABLE `pms` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT") or error(db_error());
272 query("ALTER TABLE `reports` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT") or error(db_error());
273 foreach ($boards as $board) {
274 query(sprintf("ALTER TABLE `posts_%s` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT", $board['uri'])) or error(db_error());
276 case 'v0.9.6-dev-6':
277 foreach ($boards as &$_board) {
278 query(sprintf("CREATE INDEX `thread_id` ON `posts_%s` (`thread`, `id`)", $_board['uri'])) or error(db_error());
279 query(sprintf("ALTER TABLE `posts_%s` DROP INDEX `thread`", $_board['uri'])) or error(db_error());
281 case 'v0.9.6-dev-7':
282 case 'v0.9.6-dev-7 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0-gold</a>':
283 query("ALTER TABLE `bans` ADD `seen` BOOLEAN NOT NULL") or error(db_error());
284 case 'v0.9.6-dev-8':
285 case 'v0.9.6-dev-8 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.1</a>':
286 case 'v0.9.6-dev-8 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.2</a>':
287 query("ALTER TABLE `mods` CHANGE `password` `password` CHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'SHA256'") or error(db_error());
288 query("ALTER TABLE `mods` ADD `salt` CHAR( 32 ) NOT NULL AFTER `password`") or error(db_error());
289 $query = query("SELECT `id`,`password` FROM `mods`") or error(db_error());
290 while ($user = $query->fetch(PDO::FETCH_ASSOC)) {
291 if (strlen($user['password']) == 40) {
292 mt_srand(microtime(true) * 100000 + memory_get_usage(true));
293 $salt = md5(uniqid(mt_rand(), true));
295 $user['salt'] = $salt;
296 $user['password'] = hash('sha256', $user['salt'] . $user['password']);
298 $_query = prepare("UPDATE `mods` SET `password` = :password, `salt` = :salt WHERE `id` = :id");
299 $_query->bindValue(':id', $user['id']);
300 $_query->bindValue(':password', $user['password']);
301 $_query->bindValue(':salt', $user['salt']);
302 $_query->execute() or error(db_error($_query));
305 case 'v0.9.6-dev-9':
306 case 'v0.9.6-dev-9 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.3</a>':
307 case 'v0.9.6-dev-9 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.4-gold</a>':
308 case 'v0.9.6-dev-9 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.5-gold</a>':
309 foreach ($boards as &$board) {
310 __query(sprintf("ALTER TABLE `posts_%s`
311 CHANGE `subject` `subject` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
312 CHANGE `email` `email` VARCHAR(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
313 CHANGE `name` `name` VARCHAR(35) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
314 CHANGE `trip` `trip` VARCHAR(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
315 CHANGE `capcode` `capcode` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
316 CHANGE `body` `body` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
317 CHANGE `body_nomarkup` `body_nomarkup` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
318 CHANGE `thumb` `thumb` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
319 CHANGE `thumbwidth` `thumbwidth` INT(11) NULL DEFAULT NULL,
320 CHANGE `thumbheight` `thumbheight` INT(11) NULL DEFAULT NULL,
321 CHANGE `file` `file` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
322 CHANGE `filename` `filename` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
323 CHANGE `filehash` `filehash` TEXT CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT NULL,
324 CHANGE `password` `password` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
325 CHANGE `ip` `ip` VARCHAR(39) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
326 CHANGE `embed` `embed` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
327 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;", $board['uri'])) or error(db_error());
330 __query("ALTER TABLE `antispam`
331 CHANGE `board` `board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
332 CHANGE `hash` `hash` CHAR( 40 ) CHARACTER SET ASCII COLLATE ascii_bin NOT NULL ,
333 DEFAULT CHARACTER SET ASCII COLLATE ascii_bin;") or error(db_error());
334 __query("ALTER TABLE `bans`
335 CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
336 CHANGE `reason` `reason` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL ,
337 CHANGE `board` `board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NULL DEFAULT NULL,
338 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
339 __query("ALTER TABLE `boards`
340 CHANGE `uri` `uri` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
341 CHANGE `title` `title` TINYTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
342 CHANGE `subtitle` `subtitle` TINYTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
343 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
344 __query("ALTER TABLE `cites`
345 CHANGE `board` `board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
346 CHANGE `target_board` `target_board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
347 DEFAULT CHARACTER SET ASCII COLLATE ascii_general_ci;") or error(db_error());
348 __query("ALTER TABLE `ip_notes`
349 CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
350 CHANGE `body` `body` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
351 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
352 __query("ALTER TABLE `modlogs`
353 CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
354 CHANGE `board` `board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NULL DEFAULT NULL ,
355 CHANGE `text` `text` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
356 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
357 __query("ALTER TABLE `mods`
358 CHANGE `username` `username` VARCHAR( 30 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
359 CHANGE `password` `password` CHAR( 64 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL COMMENT 'SHA256',
360 CHANGE `salt` `salt` CHAR( 32 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
361 CHANGE `boards` `boards` TEXT CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
362 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
363 __query("ALTER TABLE `mutes`
364 CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
365 DEFAULT CHARACTER SET ASCII COLLATE ascii_general_ci;") or error(db_error());
366 __query("ALTER TABLE `news`
367 CHANGE `name` `name` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
368 CHANGE `subject` `subject` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
369 CHANGE `body` `body` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
370 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
371 __query("ALTER TABLE `noticeboard`
372 CHANGE `subject` `subject` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
373 CHANGE `body` `body` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
374 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
375 __query("ALTER TABLE `pms`
376 CHANGE `message` `message` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
377 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
378 __query("ALTER TABLE `reports`
379 CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL ,
380 CHANGE `board` `board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NULL DEFAULT NULL ,
381 CHANGE `reason` `reason` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
382 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
383 __query("ALTER TABLE `robot`
384 CHANGE `hash` `hash` VARCHAR( 40 ) CHARACTER SET ASCII COLLATE ascii_bin NOT NULL COMMENT 'SHA1',
385 DEFAULT CHARACTER SET ASCII COLLATE ascii_bin;") or error(db_error());
386 __query("ALTER TABLE `theme_settings`
387 CHANGE `theme` `theme` VARCHAR( 40 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
388 CHANGE `name` `name` VARCHAR( 40 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL ,
389 CHANGE `value` `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL ,
390 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or eror(db_error());
391 case 'v0.9.6-dev-10':
392 query("ALTER TABLE `antispam`
393 CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error());
394 query("ALTER TABLE `bans`
395 CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;") or error(db_error());
396 query("ALTER TABLE `boards`
397 CHANGE `uri` `uri` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error());
398 query("ALTER TABLE `cites`
399 CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
400 CHANGE `target_board` `target_board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
401 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;") or error(db_error());
402 query("ALTER TABLE `modlogs`
403 CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;") or error(db_error());
404 query("ALTER TABLE `mods`
405 CHANGE `boards` `boards` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error());
406 query("ALTER TABLE `reports`
407 CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;") or error(db_error());
408 case 'v0.9.6-dev-11':
409 case 'v0.9.6-dev-11 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.6</a>':
410 case 'v0.9.6-dev-11 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.7-gold</a>':
411 case 'v0.9.6-dev-11 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.8-gold</a>':
412 case 'v0.9.6-dev-11 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.9-gold</a>':
413 foreach ($boards as &$board) {
414 __query(sprintf("ALTER TABLE ``posts_%s``
415 CHANGE `thumb` `thumb` VARCHAR( 255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
416 CHANGE `file` `file` VARCHAR( 255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL ;",
417 $board['uri'])) or error(db_error());
419 case 'v0.9.6-dev-12':
420 case 'v0.9.6-dev-12 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.10</a>':
421 case 'v0.9.6-dev-12 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.11-gold</a>':
422 foreach ($boards as &$board) {
423 query(sprintf("ALTER TABLE ``posts_%s`` ADD INDEX `ip` (`ip`)", $board['uri'])) or error(db_error());
425 case 'v0.9.6-dev-13':
426 query("ALTER TABLE ``antispam`` ADD INDEX `expires` (`expires`)") or error(db_error());
427 case 'v0.9.6-dev-14':
428 case 'v0.9.6-dev-14 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.12</a>':
429 foreach ($boards as &$board) {
430 query(sprintf("ALTER TABLE ``posts_%s``
431 DROP INDEX `body`,
432 ADD INDEX `filehash` (`filehash`(40))", $board['uri'])) or error(db_error());
434 query("ALTER TABLE ``modlogs`` ADD INDEX `mod` (`mod`)") or error(db_error());
435 query("ALTER TABLE ``bans`` DROP INDEX `ip`") or error(db_error());
436 query("ALTER TABLE ``bans`` ADD INDEX `ip` (`ip`)") or error(db_error());
437 query("ALTER TABLE ``noticeboard`` ADD INDEX `time` (`time`)") or error(db_error());
438 query("ALTER TABLE ``pms`` ADD INDEX `to` (`to`, `unread`)") or error(db_error());
439 case 'v0.9.6-dev-15':
440 foreach ($boards as &$board) {
441 query(sprintf("ALTER TABLE ``posts_%s``
442 ADD INDEX `list_threads` (`thread`, `sticky`, `bump`)", $board['uri'])) or error(db_error());
444 case 'v0.9.6-dev-16':
445 case 'v0.9.6-dev-16 + <a href="https://int.vichan.net/devel/">vichan-devel-4.0.13</a>':
446 query("ALTER TABLE ``bans`` ADD INDEX `seen` (`seen`)") or error(db_error());
447 case 'v0.9.6-dev-17':
448 query("ALTER TABLE ``ip_notes``
449 DROP INDEX `ip`,
450 ADD INDEX `ip_lookup` (`ip`, `time`)") or error(db_error());
451 case 'v0.9.6-dev-18':
452 query("CREATE TABLE IF NOT EXISTS ``flood`` (
453 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
454 `ip` varchar(39) NOT NULL,
455 `board` varchar(58) CHARACTER SET utf8 NOT NULL,
456 `time` int(11) NOT NULL,
457 `posthash` char(32) NOT NULL,
458 `filehash` char(32) DEFAULT NULL,
459 `isreply` tinyint(1) NOT NULL,
460 PRIMARY KEY (`id`),
461 KEY `ip` (`ip`),
462 KEY `posthash` (`posthash`),
463 KEY `filehash` (`filehash`),
464 KEY `time` (`time`)
465 ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin AUTO_INCREMENT=1 ;") or error(db_error());
466 case 'v0.9.6-dev-19':
467 query("UPDATE ``mods`` SET `type` = 10 WHERE `type` = 0") or error(db_error());
468 query("UPDATE ``mods`` SET `type` = 20 WHERE `type` = 1") or error(db_error());
469 query("UPDATE ``mods`` SET `type` = 30 WHERE `type` = 2") or error(db_error());
470 query("ALTER TABLE ``mods`` CHANGE `type` `type` smallint(1) NOT NULL") or error(db_error());
471 case 'v0.9.6-dev-20':
472 __query("CREATE TABLE IF NOT EXISTS `bans_new_temp` (
473 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
474 `ipstart` varbinary(16) NOT NULL,
475 `ipend` varbinary(16) DEFAULT NULL,
476 `created` int(10) unsigned NOT NULL,
477 `expires` int(10) unsigned DEFAULT NULL,
478 `board` varchar(58) DEFAULT NULL,
479 `creator` int(10) NOT NULL,
480 `reason` text,
481 `seen` tinyint(1) NOT NULL,
482 `post` blob,
483 PRIMARY KEY (`id`),
484 KEY `expires` (`expires`),
485 KEY `ipstart` (`ipstart`,`ipend`)
486 ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1") or error(db_error());
487 $listquery = query("SELECT * FROM ``bans`` ORDER BY `id`") or error(db_error());
488 while ($ban = $listquery->fetch(PDO::FETCH_ASSOC)) {
489 $query = prepare("INSERT INTO ``bans_new_temp`` VALUES
490 (NULL, :ipstart, :ipend, :created, :expires, :board, :creator, :reason, :seen, NULL)");
492 $range = Bans::parse_range($ban['ip']);
493 if ($range === false) {
494 // Invalid retard ban; just skip it.
495 continue;
498 $query->bindValue(':ipstart', $range[0]);
499 if ($range[1] !== false && $range[1] != $range[0])
500 $query->bindValue(':ipend', $range[1]);
501 else
502 $query->bindValue(':ipend', null, PDO::PARAM_NULL);
504 $query->bindValue(':created', $ban['set']);
506 if ($ban['expires'])
507 $query->bindValue(':expires', $ban['expires']);
508 else
509 $query->bindValue(':expires', null, PDO::PARAM_NULL);
511 if ($ban['board'])
512 $query->bindValue(':board', $ban['board']);
513 else
514 $query->bindValue(':board', null, PDO::PARAM_NULL);
516 $query->bindValue(':creator', $ban['mod']);
518 if ($ban['reason'])
519 $query->bindValue(':reason', $ban['reason']);
520 else
521 $query->bindValue(':reason', null, PDO::PARAM_NULL);
523 $query->bindValue(':seen', $ban['seen']);
524 $query->execute() or error(db_error($query));
527 // Drop old bans table
528 query("DROP TABLE ``bans``") or error(db_error());
529 // Replace with new table
530 query("RENAME TABLE ``bans_new_temp`` TO ``bans``") or error(db_error());
531 case 'v0.9.6-dev-21':
532 case 'v0.9.6-dev-21 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.90</a>':
533 __query("CREATE TABLE IF NOT EXISTS ``ban_appeals`` (
534 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
535 `ban_id` int(10) unsigned NOT NULL,
536 `time` int(10) unsigned NOT NULL,
537 `message` text NOT NULL,
538 `denied` tinyint(1) NOT NULL,
539 PRIMARY KEY (`id`),
540 KEY `ban_id` (`ban_id`)
541 ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;") or error(db_error());
542 case 'v0.9.6-dev-22':
543 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.91</a>':
544 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.92</a>':
545 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.93</a>':
546 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.94</a>':
547 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.95</a>':
548 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.96</a>':
549 case 'v0.9.6-dev-22 + <a href="https://int.vichan.net/devel/">vichan-devel-4.4.97</a>':
550 case '4.4.97':
551 if (!isset($_GET['confirm2'])) {
552 $page['title'] = 'License Change';
553 $page['body'] = '<p style="text-align:center">You are upgrading to a version which uses an amended license. The licenses included with vichan distributions prior to this version (4.4.98) are still valid for those versions, but no longer apply to this and newer versions.</p>' .
554 '<textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black" disabled>' . htmlentities(file_get_contents('LICENSE.md')) . '</textarea>
555 <p style="text-align:center">
556 <a href="?confirm2=1">I have read and understood the agreement. Proceed to upgrading.</a>
557 </p>';
559 file_write($config['has_installed'], '4.4.97');
561 break;
563 case '4.4.98-pre':
564 if (!$twig) load_twig();
565 $twig->clearCacheFiles();
566 case '4.4.98':
567 case '4.5.0':
568 case '4.5.1':
569 case '4.5.2':
570 if (!isset($_GET['confirm3'])) {
571 $page['title'] = 'Breaking change';
572 $page['body'] = '<p style="text-align:center">You are upgrading to the 5.0 branch of vichan. Please back up your database, because the process is irreversible. At the current time, if you want a very stable vichan experience, please use the 4.5 branch. This warning will be lifted as soon as we all agree that 5.0 branch is stable enough</p>
573 <p style="text-align:center">
574 <a href="?confirm3=1">I have read and understood the warning. Proceed to upgrading.</a>
575 </p>';
577 file_write($config['has_installed'], '4.5.2');
579 break;
582 foreach ($boards as &$board) {
583 query(sprintf('ALTER TABLE ``posts_%s`` ADD `files` text DEFAULT NULL AFTER `bump`;', $board['uri'])) or error(db_error());
584 query(sprintf('ALTER TABLE ``posts_%s`` ADD `num_files` int(11) DEFAULT 0 AFTER `files`;', $board['uri'])) or error(db_error());
585 query(sprintf('UPDATE ``posts_%s`` SET `files` = CONCAT(\'[{"file":"\',`file`,\'", "thumb":"\',`thumb`,\'", "filename":"\',`filename`,\'", "size":"\',`filesize`,\'", "width":"\',`filewidth`,\'","height":"\',`fileheight`,\'","thumbwidth":"\',`thumbwidth`,\'","thumbheight":"\',`thumbheight`,\'"}]\') WHERE `file` IS NOT NULL', $board['uri'], $board['uri'], $board['uri'])) or error(db_error());
586 query(sprintf('UPDATE ``posts_%s`` SET `num_files` = 1 WHERE `file` IS NOT NULL', $board['uri'])) or error(db_error());
587 query(sprintf('ALTER TABLE ``posts_%s`` DROP COLUMN `thumb`, DROP COLUMN `thumbwidth`, DROP COLUMN `thumbheight`, DROP COLUMN `file`, DROP COLUMN `fileheight`, DROP COLUMN `filesize`, DROP COLUMN `filewidth`, DROP COLUMN `filename`', $board['uri'])) or error(db_error());
588 query(sprintf('REPAIR TABLE ``posts_%s``', $board['uri']));
590 case '4.9.90':
591 case '4.9.91':
592 case '4.9.92':
593 foreach ($boards as &$board) {
594 query(sprintf('ALTER TABLE ``posts_%s`` ADD `slug` VARCHAR(255) DEFAULT NULL AFTER `embed`;', $board['uri'])) or error(db_error());
596 case '4.9.93':
597 query('ALTER TABLE ``mods`` CHANGE `password` `password` VARCHAR(255) NOT NULL;') or error(db_error());
598 query('ALTER TABLE ``mods`` CHANGE `salt` `salt` VARCHAR(64) NOT NULL;') or error(db_error());
599 case '5.0.0':
600 query('ALTER TABLE ``mods`` CHANGE `salt` `version` VARCHAR(64) NOT NULL;') or error(db_error());
601 case '5.0.1':
602 case '5.1.0':
603 query('CREATE TABLE IF NOT EXISTS ``pages`` (
604 `id` int(11) NOT NULL AUTO_INCREMENT,
605 `board` varchar(255) DEFAULT NULL,
606 `name` varchar(255) NOT NULL,
607 `title` varchar(255) DEFAULT NULL,
608 `type` varchar(255) DEFAULT NULL,
609 `content` text,
610 PRIMARY KEY (`id`),
611 UNIQUE KEY `u_pages` (`name`,`board`)
612 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;') or error(db_error());
613 case '5.1.1':
614 foreach ($boards as &$board) {
615 query(sprintf("ALTER TABLE ``posts_%s`` ADD `cycle` int(1) NOT NULL AFTER `locked`", $board['uri'])) or error(db_error());
617 case '5.1.2':
618 query('CREATE TABLE IF NOT EXISTS ``nntp_references`` (
619 `board` varchar(60) NOT NULL,
620 `id` int(11) unsigned NOT NULL,
621 `message_id` varchar(255) CHARACTER SET ascii NOT NULL,
622 `message_id_digest` varchar(40) CHARACTER SET ascii NOT NULL,
623 `own` tinyint(1) NOT NULL,
624 `headers` text,
625 PRIMARY KEY (`message_id_digest`),
626 UNIQUE KEY `message_id` (`message_id`),
627 UNIQUE KEY `u_board_id` (`board`, `id`)
628 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
629 ') or error(db_error());
630 case '5.1.3':
631 query('CREATE TABLE IF NOT EXISTS ``captchas`` (
632 `cookie` varchar(50),
633 `extra` varchar(200),
634 `text` varchar(255),
635 `created_at` int(11),
636 PRIMARY KEY (`cookie`,`extra`)
637 ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;') or error(db_error());
638 case false:
639 // TODO: enhance Tinyboard -> vichan upgrade path.
640 query("CREATE TABLE IF NOT EXISTS ``search_queries`` ( `ip` varchar(39) NOT NULL, `time` int(11) NOT NULL, `query` text NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8;") or error(db_error());
642 // Update version number
643 file_write($config['has_installed'], VERSION);
645 $page['title'] = 'Upgraded';
646 $page['body'] = '<p style="text-align:center">Successfully upgraded from ' . $version . ' to <strong>' . VERSION . '</strong>.</p>';
647 break;
648 default:
649 $page['title'] = 'Unknown version';
650 $page['body'] = '<p style="text-align:center">vichan was unable to determine what version is currently installed.</p>';
651 break;
652 case VERSION:
653 $page['title'] = 'Already installed';
654 $page['body'] = '<p style="text-align:center">It appears that vichan is already installed (' . $version . ') and there is nothing to upgrade! Delete <strong>' . $config['has_installed'] . '</strong> to reinstall.</p>';
655 break;
658 die(Element('page.html', $page));
661 function create_config_from_array(&$instance_config, &$array, $prefix = '') {
662 foreach ($array as $name => $value) {
663 if (is_array($value)) {
664 $instance_config .= "\n";
665 create_config_from_array($instance_config, $value, $prefix . '[\'' . addslashes($name) . '\']');
666 $instance_config .= "\n";
667 } else {
668 $instance_config .= ' $config' . $prefix . '[\'' . addslashes($name) . '\'] = ';
670 if (is_numeric($value))
671 $instance_config .= $value;
672 else
673 $instance_config .= "'" . addslashes($value) . "'";
675 $instance_config .= ";\n";
680 session_start();
682 if ($step == 0) {
683 // Agreeement
684 $page['body'] = '
685 <textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black" disabled>' . htmlentities(file_get_contents('LICENSE.md')) . '</textarea>
686 <p style="text-align:center">
687 <a href="?step=1">I have read and understood the agreement. Proceed to installation.</a>
688 </p>';
690 echo Element('page.html', $page);
691 } elseif ($step == 1) {
692 $page['title'] = 'Pre-installation test';
694 $can_exec = true;
695 if (!function_exists('shell_exec'))
696 $can_exec = false;
697 elseif (in_array('shell_exec', array_map('trim', explode(', ', ini_get('disable_functions')))))
698 $can_exec = false;
699 elseif (ini_get('safe_mode'))
700 $can_exec = false;
701 elseif (trim(shell_exec('echo "TEST"')) !== 'TEST')
702 $can_exec = false;
704 if (!defined('PHP_VERSION_ID')) {
705 $version = explode('.', PHP_VERSION);
706 define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
709 // Required extensions
710 $extensions = array(
711 'PDO' => array(
712 'installed' => extension_loaded('pdo'),
713 'required' => true
715 'GD' => array(
716 'installed' => extension_loaded('gd'),
717 'required' => true
719 'Imagick' => array(
720 'installed' => extension_loaded('imagick'),
721 'required' => false
723 'OpenSSL' => array(
724 'installed' => extension_loaded('openssl'),
725 'required' => false
729 $tests = array(
730 array(
731 'category' => 'PHP',
732 'name' => 'PHP &ge; 5.4',
733 'result' => PHP_VERSION_ID >= 50400,
734 'required' => true,
735 'message' => 'vichan requires PHP 5.4 or better.',
737 array(
738 'category' => 'PHP',
739 'name' => 'PHP &ge; 5.6',
740 'result' => PHP_VERSION_ID >= 50600,
741 'required' => false,
742 'message' => 'vichan works best on PHP 5.6 or better.',
744 array(
745 'category' => 'PHP',
746 'name' => 'mbstring extension installed',
747 'result' => extension_loaded('mbstring'),
748 'required' => true,
749 'message' => 'You must install the PHP <a href="http://www.php.net/manual/en/mbstring.installation.php">mbstring</a> extension.',
751 array(
752 'category' => 'PHP',
753 'name' => 'OpenSSL extension installed or PHP &ge; 7.0',
754 'result' => (extension_loaded('openssl') || (defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION >= 7)),
755 'required' => false,
756 'message' => 'It is highly recommended that you install the PHP <a href="http://www.php.net/manual/en/openssl.installation.php">OpenSSL</a> extension and/or use PHP version 7 or above. <strong>If you do not, it is possible that the IP addresses of users of your site could be compromised &mdash; see <a href="https://github.com/vichan-devel/vichan/issues/284">vichan issue #284.</a></strong> Installing the OpenSSL extension allows vichan to generate a secure salt automatically for you.',
758 array(
759 'category' => 'Database',
760 'name' => 'PDO extension installed',
761 'result' => extension_loaded('pdo'),
762 'required' => true,
763 'message' => 'You must install the PHP <a href="http://www.php.net/manual/en/intro.pdo.php">PDO</a> extension.',
765 array(
766 'category' => 'Database',
767 'name' => 'MySQL PDO driver installed',
768 'result' => extension_loaded('pdo') && in_array('mysql', PDO::getAvailableDrivers()),
769 'required' => true,
770 'message' => 'The required <a href="http://www.php.net/manual/en/ref.pdo-mysql.php">PDO MySQL driver</a> is not installed.',
772 array(
773 'category' => 'Image processing',
774 'name' => 'GD extension installed',
775 'result' => extension_loaded('gd'),
776 'required' => true,
777 'message' => 'You must install the PHP <a href="http://www.php.net/manual/en/intro.image.php">GD</a> extension. GD is a requirement even if you have chosen another image processor for thumbnailing.',
779 array(
780 'category' => 'Image processing',
781 'name' => 'GD: JPEG',
782 'result' => function_exists('imagecreatefromjpeg'),
783 'required' => true,
784 'message' => 'imagecreatefromjpeg() does not exist. This is a problem.',
786 array(
787 'category' => 'Image processing',
788 'name' => 'GD: PNG',
789 'result' => function_exists('imagecreatefrompng'),
790 'required' => true,
791 'message' => 'imagecreatefrompng() does not exist. This is a problem.',
793 array(
794 'category' => 'Image processing',
795 'name' => 'GD: GIF',
796 'result' => function_exists('imagecreatefromgif'),
797 'required' => true,
798 'message' => 'imagecreatefromgif() does not exist. This is a problem.',
800 array(
801 'category' => 'Image processing',
802 'name' => '`convert` (command-line ImageMagick)',
803 'result' => $can_exec && shell_exec('which convert'),
804 'required' => false,
805 'message' => '(Optional) `convert` was not found or executable; command-line ImageMagick image processing cannot be enabled.',
806 'effect' => function (&$config) { $config['thumb_method'] = 'convert'; },
808 array(
809 'category' => 'Image processing',
810 'name' => '`identify` (command-line ImageMagick)',
811 'result' => $can_exec && shell_exec('which identify'),
812 'required' => false,
813 'message' => '(Optional) `identify` was not found or executable; command-line ImageMagick image processing cannot be enabled.',
815 array(
816 'category' => 'Image processing',
817 'name' => '`gm` (command-line GraphicsMagick)',
818 'result' => $can_exec && shell_exec('which gm'),
819 'required' => false,
820 'message' => '(Optional) `gm` was not found or executable; command-line GraphicsMagick (faster than ImageMagick) cannot be enabled.',
821 'effect' => function (&$config) { $config['thumb_method'] = 'gm'; },
823 array(
824 'category' => 'Image processing',
825 'name' => '`gifsicle` (command-line animted GIF thumbnailing)',
826 'result' => $can_exec && shell_exec('which gifsicle'),
827 'required' => false,
828 'message' => '(Optional) `gifsicle` was not found or executable; you may not use `convert+gifsicle` for better animated GIF thumbnailing.',
829 'effect' => function (&$config) { if ($config['thumb_method'] == 'gm') $config['thumb_method'] = 'gm+gifsicle';
830 if ($config['thumb_method'] == 'convert') $config['thumb_method'] = 'convert+gifsicle'; },
832 array(
833 'category' => 'Image processing',
834 'name' => '`md5sum` (quick file hashing on GNU/Linux)',
835 'prereq' => '',
836 'result' => $can_exec && shell_exec('echo "vichan" | md5sum') == "141225c362da02b5c359c45b665168de -\n",
837 'required' => false,
838 'message' => '(Optional) `md5sum` was not found or executable; file hashing for multiple images will be slower. Ignore if not using Linux.',
839 'effect' => function (&$config) { $config['gnu_md5'] = true; },
841 array(
842 'category' => 'Image processing',
843 'name' => '`/sbin/md5` (quick file hashing on BSDs)',
844 'result' => $can_exec && shell_exec('echo "vichan" | /sbin/md5 -r') == "141225c362da02b5c359c45b665168de\n",
845 'required' => false,
846 'message' => '(Optional) `/sbin/md5` was not found or executable; file hashing for multiple images will be slower. Ignore if not using BSD.',
847 'effect' => function (&$config) { $config['bsd_md5'] = true; },
849 array(
850 'category' => 'File permissions',
851 'name' => getcwd(),
852 'result' => is_writable('.'),
853 'required' => true,
854 'message' => 'vichan does not have permission to create directories (boards) here. You will need to <code>chmod</code> (or operating system equivalent) appropriately.'
856 array(
857 'category' => 'File permissions',
858 'name' => getcwd() . '/templates/cache',
859 'result' => is_writable('templates') || (is_dir('templates/cache') && is_writable('templates/cache')),
860 'required' => true,
861 'message' => 'You must give vichan permission to create (and write to) the <code>templates/cache</code> directory or performance will be drastically reduced.'
863 array(
864 'category' => 'File permissions',
865 'name' => getcwd() . '/tmp/cache',
866 'result' => is_dir('tmp/cache') && is_writable('tmp/cache'),
867 'required' => true,
868 'message' => 'You must give vichan permission to write to the <code>tmp/cache</code> directory.'
870 array(
871 'category' => 'File permissions',
872 'name' => getcwd() . '/inc/instance-config.php',
873 'result' => is_writable('inc/instance-config.php'),
874 'required' => false,
875 'message' => 'vichan does not have permission to make changes to <code>inc/instance-config.php</code>. To complete the installation, you will be asked to manually copy and paste code into the file instead.'
877 array(
878 'category' => 'Misc',
879 'name' => 'Caching available (APC, XCache, Memcached or Redis)',
880 'result' => extension_loaded('apc') || extension_loaded('xcache')
881 || extension_loaded('memcached') || extension_loaded('redis'),
882 'required' => false,
883 'message' => 'You will not be able to enable the additional caching system, designed to minimize SQL queries and significantly improve performance. <a href="http://php.net/manual/en/book.apc.php">APC</a> is the recommended method of caching, but <a href="http://xcache.lighttpd.net/">XCache</a>, <a href="http://www.php.net/manual/en/intro.memcached.php">Memcached</a> and <a href="http://pecl.php.net/package/redis">Redis</a> are also supported.'
885 array(
886 'category' => 'Misc',
887 'name' => 'vichan installed using git',
888 'result' => is_dir('.git'),
889 'required' => false,
890 'message' => 'vichan is still beta software and it\'s not going to come out of beta any time soon. As there are often many months between releases yet changes and bug fixes are very frequent, it\'s recommended to use the git repository to maintain your vichan installation. Using git makes upgrading much easier.'
894 $config['font_awesome'] = true;
896 $additional_config = array();
897 foreach ($tests as $test) {
898 if ($test['result'] && isset($test['effect'])) {
899 $test['effect']($additional_config);
902 $more = '';
903 create_config_from_array($more, $additional_config);
904 $_SESSION['more'] = $more;
906 echo Element('page.html', array(
907 'body' => Element('installer/check-requirements.html', array(
908 'extensions' => $extensions,
909 'tests' => $tests,
910 'config' => $config,
912 'title' => 'Checking environment',
913 'config' => $config,
915 } elseif ($step == 2) {
917 // Basic config
918 $page['title'] = 'Configuration';
920 $sg = new SaltGen();
921 $config['cookies']['salt'] = $sg->generate();
922 $config['secure_trip_salt'] = $sg->generate();
924 echo Element('page.html', array(
925 'body' => Element('installer/config.html', array(
926 'config' => $config,
927 'more' => $_SESSION['more'],
929 'title' => 'Configuration',
930 'config' => $config
932 } elseif ($step == 3) {
933 $more = $_POST['more'];
934 unset($_POST['more']);
936 $instance_config =
937 '<'.'?php
940 * Instance Configuration
941 * ----------------------
942 * Edit this file and not config.php for imageboard configuration.
944 * You can copy values from config.php (defaults) and paste them here.
949 create_config_from_array($instance_config, $_POST);
951 $instance_config .= "\n";
952 $instance_config .= $more;
953 $instance_config .= "\n";
955 if (@file_put_contents('inc/instance-config.php', $instance_config)) {
956 // flushes opcache if php >= 5.5.0 or opcache is installed via PECL
957 if (function_exists('opcache_invalidate')) {
958 opcache_invalidate('inc/instance-config.php');
960 header('Location: ?step=4', true, $config['redirect_http']);
961 } else {
962 $page['title'] = 'Manual installation required';
963 $page['body'] = '
964 <p>I couldn\'t write to <strong>inc/instance-config.php</strong> with the new configuration, probably due to a permissions error.</p>
965 <p>Please complete the installation manually by copying and pasting the following code into the contents of <strong>inc/instance-config.php</strong>:</p>
966 <textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black">' . htmlentities($instance_config) . '</textarea>
967 <p style="text-align:center">
968 <a href="?step=4">Once complete, click here to complete installation.</a>
969 </p>
971 echo Element('page.html', $page);
973 } elseif ($step == 4) {
974 // SQL installation
976 buildJavascript();
978 $sql = @file_get_contents('install.sql') or error("Couldn't load install.sql.");
980 sql_open();
981 $mysql_version = mysql_version();
983 // This code is probably horrible, but what I'm trying
984 // to do is find all of the SQL queires and put them
985 // in an array.
986 preg_match_all("/(^|\n)((SET|CREATE|INSERT).+)\n\n/msU", $sql, $queries);
987 $queries = $queries[2];
989 $queries[] = Element('posts.sql', array('board' => 'b'));
990 $queries[] = Element('archive.sql', array('board' => 'b'));
991 $queries[] = Element('polling.sql', array());
992 $queries[] = Element('scoring.sql', array());
993 $queries[] = Element('captcha.sql', array());
994 $queries[] = Element('proxy.sql', array());
996 $sql_errors = '';
997 foreach ($queries as $query) {
998 if ($mysql_version < 50503)
999 $query = preg_replace('/(CHARSET=|CHARACTER SET )utf8mb4/', '$1utf8', $query);
1000 $query = preg_replace('/^([\w\s]*)`([0-9a-zA-Z$_\x{0080}-\x{FFFF}]+)`/u', '$1``$2``', $query);
1001 if (!query($query))
1002 $sql_errors .= '<li>' . db_error() . '</li>';
1005 $page['title'] = 'Installation complete';
1006 $page['body'] = '<p style="text-align:center">Thank you for using vichan. Please remember to report any bugs you discover. <a href="https://github.com/vichan-devel/vichan/wiki/Configuration-Basics">How do I edit the config files?</a></p>';
1008 if (!empty($sql_errors)) {
1009 $page['body'] .= '<div class="ban"><h2>SQL errors</h2><p>SQL errors were encountered when trying to install the database. This may be the result of using a database which is already occupied with a vichan installation; if so, you can probably ignore this.</p><p>The errors encountered were:</p><ul>' . $sql_errors . '</ul><p><a href="?step=5">Ignore errors and complete installation.</a></p></div>';
1010 } else {
1011 $boards = listBoards();
1012 foreach ($boards as &$_board) {
1013 setupBoard($_board);
1014 buildIndex();
1017 file_write($config['has_installed'], VERSION);
1018 /*if (!file_unlink(__FILE__)) {
1019 $page['body'] .= '<div class="ban"><h2>Delete install.php!</h2><p>I couldn\'t remove <strong>install.php</strong>. You will have to remove it manually.</p></div>';
1023 echo Element('page.html', $page);
1024 } elseif ($step == 5) {
1025 $page['title'] = 'Installation complete';
1026 $page['body'] = '<p style="text-align:center">Thank you for using vichan. Please remember to report any bugs you discover.</p>';
1028 $boards = listBoards();
1029 foreach ($boards as &$_board) {
1030 setupBoard($_board);
1031 buildIndex();
1034 file_write($config['has_installed'], VERSION);
1035 if (!file_unlink(__FILE__)) {
1036 $page['body'] .= '<div class="ban"><h2>Delete install.php!</h2><p>I couldn\'t remove <strong>install.php</strong>. You will have to remove it manually.</p></div>';
1039 echo Element('page.html', $page);