3 // Installation/upgrade file
4 define('VERSION', '6.1.2');
5 require 'inc/functions.php';
10 public $salt_length = 128;
12 // Best function I could think of for non-SSL PHP 5
13 private function generate_install_salt() {
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));
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);
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();
45 return "INSECURE." . $this->generate_install_salt();
50 $step = isset($_GET['step']) ?
round($_GET['step']) : 0;
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']));
68 function __query($sql) {
71 if (mysql_version() >= 50503)
74 return query(str_replace('utf8mb4', 'utf8', $sql));
77 $boards = listBoards();
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());
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());
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());
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());
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
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());
127 query("ALTER TABLE `mods` ADD `boards` TEXT NOT NULL") or error(db_error());
128 query("UPDATE `mods` SET `boards` = '*'") or error(db_error());
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());
134 // Board-specifc bans
135 query("ALTER TABLE `bans` ADD `board` SMALLINT NULL AFTER `reason`") or error(db_error());
138 query("ALTER TABLE `bans` ADD `id` INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY ( `id` ), ADD UNIQUE (`id`)");
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());
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());
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());
161 foreach ($boards as &$board) {
162 query(sprintf("ALTER TABLE `posts_%s` ADD INDEX ( `thread` )", $board['uri'])) or error(db_error());
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':
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());
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());
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>
198 file_write($config['has_installed'], 'v0.9.4-dev-2');
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());
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());
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());
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());
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());
240 query("ALTER TABLE `boards`
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));
263 query("ALTER TABLE `antispam` CHANGE `hash` `hash` CHAR( 40 ) NOT NULL") or error(db_error());
265 query("ALTER TABLE `news` DROP INDEX `id`, ADD PRIMARY KEY ( `id` )") or error(db_error());
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());
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());
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());
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));
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``
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``
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,
462 KEY `posthash` (`posthash`),
463 KEY `filehash` (`filehash`),
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,
481 `seen` tinyint(1) NOT NULL,
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.
498 $query->bindValue(':ipstart', $range[0]);
499 if ($range[1] !== false && $range[1] != $range[0])
500 $query->bindValue(':ipend', $range[1]);
502 $query->bindValue(':ipend', null, PDO
::PARAM_NULL
);
504 $query->bindValue(':created', $ban['set']);
507 $query->bindValue(':expires', $ban['expires']);
509 $query->bindValue(':expires', null, PDO
::PARAM_NULL
);
512 $query->bindValue(':board', $ban['board']);
514 $query->bindValue(':board', null, PDO
::PARAM_NULL
);
516 $query->bindValue(':creator', $ban['mod']);
519 $query->bindValue(':reason', $ban['reason']);
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,
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>':
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>
559 file_write($config['has_installed'], '4.4.97');
564 if (!$twig) load_twig();
565 $twig->clearCacheFiles();
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>
577 file_write($config['has_installed'], '4.5.2');
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']));
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());
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());
600 query('ALTER TABLE ``mods`` CHANGE `salt` `version` VARCHAR(64) NOT NULL;') or error(db_error());
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,
611 UNIQUE KEY `u_pages` (`name`,`board`)
612 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;') or error(db_error());
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());
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,
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());
631 query('CREATE TABLE IF NOT EXISTS ``captchas`` (
632 `cookie` varchar(50),
633 `extra` varchar(200),
635 `created_at` int(11),
636 PRIMARY KEY (`cookie`,`extra`)
637 ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;') or error(db_error());
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>';
649 $page['title'] = 'Unknown version';
650 $page['body'] = '<p style="text-align:center">vichan was unable to determine what version is currently installed.</p>';
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>';
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";
668 $instance_config .= ' $config' . $prefix . '[\'' . addslashes($name) . '\'] = ';
670 if (is_numeric($value))
671 $instance_config .= $value;
673 $instance_config .= "'" . addslashes($value) . "'";
675 $instance_config .= ";\n";
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>
690 echo Element('page.html', $page);
691 } elseif ($step == 1) {
692 $page['title'] = 'Pre-installation test';
695 if (!function_exists('shell_exec'))
697 elseif (in_array('shell_exec', array_map('trim', explode(', ', ini_get('disable_functions')))))
699 elseif (ini_get('safe_mode'))
701 elseif (trim(shell_exec('echo "TEST"')) !== 'TEST')
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
712 'installed' => extension_loaded('pdo'),
716 'installed' => extension_loaded('gd'),
720 'installed' => extension_loaded('imagick'),
724 'installed' => extension_loaded('openssl'),
732 'name' => 'PHP ≥ 5.4',
733 'result' => PHP_VERSION_ID
>= 50400,
735 'message' => 'vichan requires PHP 5.4 or better.',
739 'name' => 'PHP ≥ 5.6',
740 'result' => PHP_VERSION_ID
>= 50600,
742 'message' => 'vichan works best on PHP 5.6 or better.',
746 'name' => 'mbstring extension installed',
747 'result' => extension_loaded('mbstring'),
749 'message' => 'You must install the PHP <a href="http://www.php.net/manual/en/mbstring.installation.php">mbstring</a> extension.',
753 'name' => 'OpenSSL extension installed or PHP ≥ 7.0',
754 'result' => (extension_loaded('openssl') ||
(defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION
>= 7)),
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 — 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.',
759 'category' => 'Database',
760 'name' => 'PDO extension installed',
761 'result' => extension_loaded('pdo'),
763 'message' => 'You must install the PHP <a href="http://www.php.net/manual/en/intro.pdo.php">PDO</a> extension.',
766 'category' => 'Database',
767 'name' => 'MySQL PDO driver installed',
768 'result' => extension_loaded('pdo') && in_array('mysql', PDO
::getAvailableDrivers()),
770 'message' => 'The required <a href="http://www.php.net/manual/en/ref.pdo-mysql.php">PDO MySQL driver</a> is not installed.',
773 'category' => 'Image processing',
774 'name' => 'GD extension installed',
775 'result' => extension_loaded('gd'),
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.',
780 'category' => 'Image processing',
781 'name' => 'GD: JPEG',
782 'result' => function_exists('imagecreatefromjpeg'),
784 'message' => 'imagecreatefromjpeg() does not exist. This is a problem.',
787 'category' => 'Image processing',
789 'result' => function_exists('imagecreatefrompng'),
791 'message' => 'imagecreatefrompng() does not exist. This is a problem.',
794 'category' => 'Image processing',
796 'result' => function_exists('imagecreatefromgif'),
798 'message' => 'imagecreatefromgif() does not exist. This is a problem.',
801 'category' => 'Image processing',
802 'name' => '`convert` (command-line ImageMagick)',
803 'result' => $can_exec && shell_exec('which convert'),
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'; },
809 'category' => 'Image processing',
810 'name' => '`identify` (command-line ImageMagick)',
811 'result' => $can_exec && shell_exec('which identify'),
813 'message' => '(Optional) `identify` was not found or executable; command-line ImageMagick image processing cannot be enabled.',
816 'category' => 'Image processing',
817 'name' => '`gm` (command-line GraphicsMagick)',
818 'result' => $can_exec && shell_exec('which gm'),
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'; },
824 'category' => 'Image processing',
825 'name' => '`gifsicle` (command-line animted GIF thumbnailing)',
826 'result' => $can_exec && shell_exec('which gifsicle'),
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'; },
833 'category' => 'Image processing',
834 'name' => '`md5sum` (quick file hashing on GNU/Linux)',
836 'result' => $can_exec && shell_exec('echo "vichan" | md5sum') == "141225c362da02b5c359c45b665168de -\n",
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; },
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",
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; },
850 'category' => 'File permissions',
852 'result' => is_writable('.'),
854 'message' => 'vichan does not have permission to create directories (boards) here. You will need to <code>chmod</code> (or operating system equivalent) appropriately.'
857 'category' => 'File permissions',
858 'name' => getcwd() . '/templates/cache',
859 'result' => is_writable('templates') ||
(is_dir('templates/cache') && is_writable('templates/cache')),
861 'message' => 'You must give vichan permission to create (and write to) the <code>templates/cache</code> directory or performance will be drastically reduced.'
864 'category' => 'File permissions',
865 'name' => getcwd() . '/tmp/cache',
866 'result' => is_dir('tmp/cache') && is_writable('tmp/cache'),
868 'message' => 'You must give vichan permission to write to the <code>tmp/cache</code> directory.'
871 'category' => 'File permissions',
872 'name' => getcwd() . '/inc/instance-config.php',
873 'result' => is_writable('inc/instance-config.php'),
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.'
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'),
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.'
886 'category' => 'Misc',
887 'name' => 'vichan installed using git',
888 'result' => is_dir('.git'),
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);
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,
912 'title' => 'Checking environment',
915 } elseif ($step == 2) {
918 $page['title'] = 'Configuration';
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(
927 'more' => $_SESSION['more'],
929 'title' => 'Configuration',
932 } elseif ($step == 3) {
933 $more = $_POST['more'];
934 unset($_POST['more']);
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']);
962 $page['title'] = 'Manual installation required';
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>
971 echo Element('page.html', $page);
973 } elseif ($step == 4) {
978 $sql = @file_get_contents
('install.sql') or error("Couldn't load install.sql.");
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
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());
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);
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>';
1011 $boards = listBoards();
1012 foreach ($boards as &$_board) {
1013 setupBoard($_board);
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);
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);