diff options
| -rw-r--r-- | inc/config.php | 3 | ||||
| -rw-r--r-- | inc/display.php | 6 | ||||
| -rw-r--r-- | inc/functions.php | 8 | ||||
| -rw-r--r-- | inc/mod/pages.php | 9 | ||||
| -rw-r--r-- | install.php | 23 | ||||
| -rw-r--r-- | install.sql | 22 | ||||
| -rw-r--r-- | mod.php | 33 | ||||
| -rw-r--r-- | post.php | 6 |
8 files changed, 63 insertions, 47 deletions
diff --git a/inc/config.php b/inc/config.php index 28a7a4db..36518028 100644 --- a/inc/config.php +++ b/inc/config.php @@ -1130,6 +1130,9 @@ // 'type' => 'scp' //); + // Regex for board URIs + $config['board_regex'] = '[0-9a-zA-Z$_\x{0080}-\x{FFFF}]{1,58}'; + // Complex regular expression to catch URLs $config['url_regex'] = '/' . '(https?|ftp):\/\/' . '(([\w\-]+\.)+[a-zA-Z]{2,6}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' . '(:\d+)?' . '(\/([\w\-~.#\/?=&;:+%!*\[\]@$\'()+,|\^]+)?)?' . '/'; diff --git a/inc/display.php b/inc/display.php index a7e4826e..0992166d 100644 --- a/inc/display.php +++ b/inc/display.php @@ -235,7 +235,7 @@ function bidi_cleanup($str){ function secure_link_confirm($text, $title, $confirm_message, $href) { global $config; - return '<a onclick="if (event.which==2) return true;if (confirm(\'' . htmlentities(addslashes($confirm_message)) . '\')) document.location=\'?/' . htmlentities(addslashes($href . '/' . make_secure_link_token($href))) . '\';return false;" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>'; + return '<a onclick="if (event.which==2) return true;if (confirm(\'' . htmlentities(addslashes($confirm_message)) . '\')) document.location=\'?/' . htmlspecialchars(addslashes($href . '/' . make_secure_link_token($href))) . '\';return false;" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>'; } function secure_link($href) { return $href . '/' . make_secure_link_token($href); @@ -299,7 +299,7 @@ class Post { // Fix internal links // Very complicated regex $this->body = preg_replace( - '/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), '\w+') . ')/', + '/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u', '<a $1href="?/$4', $this->body ); @@ -398,7 +398,7 @@ class Thread { // Fix internal links // Very complicated regex $this->body = preg_replace( - '/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), '\w+') . ')/', + '/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u', '<a $1href="?/$4', $this->body ); diff --git a/inc/functions.php b/inc/functions.php index d5692be5..6db21c54 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -98,18 +98,18 @@ function loadConfig() { 'https?:\/\/' . $_SERVER['HTTP_HOST']) . preg_quote($config['root'], '/') . '(' . - str_replace('%s', '\w+', preg_quote($config['board_path'], '/')) . + str_replace('%s', $config['board_regex'], preg_quote($config['board_path'], '/')) . '(' . preg_quote($config['file_index'], '/') . '|' . str_replace('%d', '\d+', preg_quote($config['file_page'])) . ')?' . '|' . - str_replace('%s', '\w+', preg_quote($config['board_path'], '/')) . + str_replace('%s', $config['board_regex'], preg_quote($config['board_path'], '/')) . preg_quote($config['dir']['res'], '/') . str_replace('%d', '\d+', preg_quote($config['file_page'], '/')) . '|' . preg_quote($config['file_mod'], '/') . '\?\/.+' . - ')([#?](.+)?)?$/i'; + ')([#?](.+)?)?$/ui'; } else { // CLI mode $config['referer_match'] = '//'; @@ -1468,7 +1468,7 @@ function markup(&$body, $track_cites = false) { } // Cross-board linking - if (preg_match_all('/(^|\s)>>>\/(\w+?)\/(\d+)?([\s,.)?]|$)/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { + if (preg_match_all('/(^|\s)>>>\/(' . $config['board_regex'] . 'f?)\/(\d+)?([\s,.)?]|$)/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycross']); } diff --git a/inc/mod/pages.php b/inc/mod/pages.php index fdf9d8e9..ab4cdaaf 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -443,7 +443,7 @@ function mod_new_board() { if ($_POST['title'] == '') error(sprintf($config['error']['required'], 'title')); - if (!preg_match('/^\w+$/', $_POST['uri'])) + if (!preg_match('/^' . $config['board_regex'] . '$/u', $_POST['uri'])) error(sprintf($config['error']['invalidfield'], 'URI')); if (openBoard($_POST['uri'])) { @@ -746,7 +746,6 @@ function mod_page_ip($ip) { openBoard($board['uri']); if (!hasPermission($config['mod']['show_ip'], $board['uri'])) continue; - $query = prepare(sprintf('SELECT * FROM `posts_%s` WHERE `ip` = :ip ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $board['uri'])); $query->bindValue(':ip', $ip); $query->bindValue(':limit', $config['mod']['ip_recentposts'], PDO::PARAM_INT); @@ -1420,7 +1419,7 @@ function mod_user($uid) { $boards = array(); foreach ($_POST as $name => $value) { - if (preg_match('/^board_(\w+)$/', $name, $matches) && in_array($matches[1], $_boards)) + if (preg_match('/^board_(' . $config['board_regex'] . ')$/u', $name, $matches) && in_array($matches[1], $_boards)) $boards[] = $matches[1]; } } @@ -1541,7 +1540,7 @@ function mod_user_new() { $boards = array(); foreach ($_POST as $name => $value) { - if (preg_match('/^board_(\w+)$/', $name, $matches) && in_array($matches[1], $_boards)) + if (preg_match('/^board_(' . $config['board_regex'] . ')$/u', $name, $matches) && in_array($matches[1], $_boards)) $boards[] = $matches[1]; } } @@ -2135,7 +2134,7 @@ function mod_debug_antispam() { $where .= ' AND `thread` = ' . $pdo->quote($_POST['thread']); if (isset($_POST['purge'])) { - $query = prepare('UPDATE `antispam` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE' . $where); + $query = prepare(', DATE `antispam` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE' . $where); $query->bindValue(':expires', $config['spam']['hidden_inputs_expire']); $query->execute() or error(db_error()); } diff --git a/install.php b/install.php index 1f148e92..847876ab 100644 --- a/install.php +++ b/install.php @@ -1,7 +1,7 @@ <?php // Installation/upgrade file -define('VERSION', 'v0.9.6-dev-10'); +define('VERSION', 'v0.9.6-dev-11'); require 'inc/functions.php'; @@ -300,10 +300,6 @@ if (file_exists($config['has_installed'])) { CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL , CHANGE `body` `body` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL , DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error()); - __query("ALTER TABLE `ip_notes` - CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL , - CHANGE `body` `body` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL , - DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error()); __query("ALTER TABLE `modlogs` CHANGE `ip` `ip` VARCHAR( 39 ) CHARACTER SET ASCII COLLATE ascii_general_ci NOT NULL , CHANGE `board` `board` VARCHAR( 120 ) CHARACTER SET ASCII COLLATE ascii_general_ci NULL DEFAULT NULL , @@ -343,6 +339,23 @@ if (file_exists($config['has_installed'])) { CHANGE `name` `name` VARCHAR( 40 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL , CHANGE `value` `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL , DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or eror(db_error()); + case 'v0.9.6-dev-10': + query("ALTER TABLE `antispam` + CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error()); + query("ALTER TABLE `bans` + CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;") or error(db_error()); + query("ALTER TABLE `boards` + CHANGE `uri` `uri` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error()); + query("ALTER TABLE `cites` + CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , + CHANGE `target_board` `target_board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , + DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;") or error(db_error()); + query("ALTER TABLE `modlogs` + CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;") or error(db_error()); + query("ALTER TABLE `mods` + CHANGE `boards` `boards` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error()); + query("ALTER TABLE `reports` + CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;") or error(db_error()); case false: // Update version number file_write($config['has_installed'], VERSION); diff --git a/install.sql b/install.sql index c4e82820..db89452b 100644 --- a/install.sql +++ b/install.sql @@ -22,7 +22,7 @@ SET time_zone = "+00:00"; -- CREATE TABLE IF NOT EXISTS `antispam` ( - `board` varchar(120) CHARACTER SET ascii NOT NULL, + `board` varchar(58) CHARACTER SET utf8 NOT NULL, `thread` int(11) DEFAULT NULL, `hash` char(40) COLLATE ascii_bin NOT NULL, `created` int(11) NOT NULL, @@ -45,7 +45,7 @@ CREATE TABLE IF NOT EXISTS `bans` ( `set` int(11) NOT NULL, `expires` int(11) DEFAULT NULL, `reason` text, - `board` varchar(120) CHARACTER SET ascii DEFAULT NULL, + `board` varchar(58) CHARACTER SET utf8 DEFAULT NULL, `seen` tinyint(1) NOT NULL, PRIMARY KEY (`id`), FULLTEXT KEY `ip` (`ip`) @@ -58,7 +58,7 @@ CREATE TABLE IF NOT EXISTS `bans` ( -- CREATE TABLE IF NOT EXISTS `boards` ( - `uri` varchar(120) CHARACTER SET ascii NOT NULL, + `uri` varchar(58) CHARACTER SET utf8 NOT NULL, `title` tinytext NOT NULL, `subtitle` tinytext, PRIMARY KEY (`uri`) @@ -78,13 +78,13 @@ INSERT INTO `boards` VALUES -- CREATE TABLE IF NOT EXISTS `cites` ( - `board` varchar(120) NOT NULL, + `board` varchar(58) NOT NULL, `post` int(11) NOT NULL, - `target_board` varchar(120) NOT NULL, + `target_board` varchar(58) NOT NULL, `target` int(11) NOT NULL, KEY `target` (`target_board`,`target`), KEY `post` (`board`,`post`) -) ENGINE=MyISAM DEFAULT CHARSET=ascii; +) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -------------------------------------------------------- @@ -111,7 +111,7 @@ CREATE TABLE IF NOT EXISTS `ip_notes` ( CREATE TABLE IF NOT EXISTS `modlogs` ( `mod` int(11) NOT NULL, `ip` varchar(39) CHARACTER SET ascii NOT NULL, - `board` varchar(120) CHARACTER SET ascii DEFAULT NULL, + `board` varchar(58) CHARACTER SET utf8 DEFAULT NULL, `time` int(11) NOT NULL, `text` text NOT NULL, KEY `time` (`time`) @@ -129,10 +129,10 @@ CREATE TABLE IF NOT EXISTS `mods` ( `password` char(64) CHARACTER SET ascii NOT NULL COMMENT 'SHA256', `salt` char(32) CHARACTER SET ascii NOT NULL, `type` smallint(1) NOT NULL COMMENT '0: janitor, 1: mod, 2: admin', - `boards` text CHARACTER SET ascii NOT NULL, + `boards` text CHARACTER SET utf8 NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`,`username`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=4 ; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=5 ; -- -- Dumping data for table `mods` @@ -210,11 +210,11 @@ CREATE TABLE IF NOT EXISTS `reports` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `time` int(11) NOT NULL, `ip` varchar(39) CHARACTER SET ascii NOT NULL, - `board` varchar(120) CHARACTER SET ascii DEFAULT NULL, + `board` varchar(58) CHARACTER SET utf8 DEFAULT NULL, `post` int(11) NOT NULL, `reason` text NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=3 ; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ; -- -------------------------------------------------------- @@ -18,7 +18,7 @@ if (get_magic_quotes_gpc()) { $_POST = strip_array($_POST); } -$query = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; +$query = isset($_SERVER['QUERY_STRING']) ? urldecode($_SERVER['QUERY_STRING']) : ''; $pages = array( '' => ':?/', // redirect to dashboard @@ -45,7 +45,7 @@ $pages = array( '/news/(\d+)' => 'news', // view news '/news/delete/(\d+)' => 'news_delete', // delete from news - '/edit/(\w+)' => 'edit_board', // edit board details + '/edit/(\%b)' => 'edit_board', // edit board details '/new-board' => 'new_board', // create a new board '/rebuild' => 'rebuild', // rebuild static files @@ -63,15 +63,15 @@ $pages = array( // CSRF-protected moderator actions '/ban' => 'secure_POST ban', // new ban - '/(\w+)/ban(&delete)?/(\d+)' => 'secure_POST ban_post', // ban poster - '/(\w+)/move/(\d+)' => 'secure_POST move', // move thread - '/(\w+)/edit(_raw)?/(\d+)' => 'secure_POST edit_post', // edit post - '/(\w+)/delete/(\d+)' => 'secure delete', // delete post - '/(\w+)/deletefile/(\d+)' => 'secure deletefile', // delete file from post - '/(\w+)/deletebyip/(\d+)(/global)?' => 'secure deletebyip', // delete all posts by IP address - '/(\w+)/(un)?lock/(\d+)' => 'secure lock', // lock thread - '/(\w+)/(un)?sticky/(\d+)' => 'secure sticky', // sticky thread - '/(\w+)/bump(un)?lock/(\d+)' => 'secure bumplock', // "bumplock" thread + '/(\%b)/ban(&delete)?/(\d+)' => 'secure_POST ban_post', // ban poster + '/(\%b)/move/(\d+)' => 'secure_POST move', // move thread + '/(\%b)/edit(_raw)?/(\d+)' => 'secure_POST edit_post', // edit post + '/(\%b)/delete/(\d+)' => 'secure delete', // delete post + '/(\%b)/deletefile/(\d+)' => 'secure deletefile', // delete file from post + '/(\%b)/deletebyip/(\d+)(/global)?' => 'secure deletebyip', // delete all posts by IP address + '/(\%b)/(un)?lock/(\d+)' => 'secure lock', // lock thread + '/(\%b)/(un)?sticky/(\d+)' => 'secure sticky', // sticky thread + '/(\%b)/bump(un)?lock/(\d+)' => 'secure bumplock', // "bumplock" thread '/themes' => 'themes_list', // manage themes '/themes/(\w+)' => 'theme_configure', // configure/reconfigure theme @@ -86,10 +86,10 @@ $pages = array( '/debug/sql' => 'secure_POST debug_sql', // This should always be at the end: - '/(\w+)/' => 'view_board', - '/(\w+)/' . preg_quote($config['file_index'], '!') => 'view_board', - '/(\w+)/' . str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_board', - '/(\w+)/' . preg_quote($config['dir']['res'], '!') . + '/(\%b)/' => 'view_board', + '/(\%b)/' . preg_quote($config['file_index'], '!') => 'view_board', + '/(\%b)/' . str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_board', + '/(\%b)/' . preg_quote($config['dir']['res'], '!') . str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_thread', ); @@ -109,7 +109,8 @@ $new_pages = array(); foreach ($pages as $key => $callback) { if (is_string($callback) && preg_match('/^secure /', $callback)) $key .= '(/(?P<token>[a-f0-9]{8}))?'; - $new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!'] = $callback; + $key = str_replace('\%b', $config['board_regex'], $key); + $new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!u'] = $callback; } $pages = $new_pages; @@ -170,7 +170,7 @@ if (isset($_POST['delete'])) { error($config['error']['bot']); // Check the referrer - if (!isset($_SERVER['HTTP_REFERER']) || !preg_match($config['referer_match'], $_SERVER['HTTP_REFERER'])) + if (!isset($_SERVER['HTTP_REFERER']) || !preg_match($config['referer_match'], urldecode($_SERVER['HTTP_REFERER']))) error($config['error']['referer']); checkDNSBL(); @@ -547,9 +547,9 @@ if (isset($_POST['delete'])) { // Remove board directories before inserting them into the database. if ($post['has_file']) { $post['file_path'] = $post['file']; - $post['file'] = substr_replace($post['file'], '', 0, mb_strlen($board['dir'] . $config['dir']['img'])); + $post['file'] = mb_substr($post['file'], mb_strlen($board['dir'] . $config['dir']['img'])); if ($is_an_image && $post['thumb'] != 'spoiler') - $post['thumb'] = substr_replace($post['thumb'], '', 0, mb_strlen($board['dir'] . $config['dir']['thumb'])); + $post['thumb'] = mb_substr($post['thumb'], mb_strlen($board['dir'] . $config['dir']['thumb'])); } $post = (object)$post; |
