From 58ea368c4526b95f2a2c8cffe66566cbaa192289 Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Tue, 18 Jul 2017 22:32:51 -0700 Subject: [PATCH 01/13] Move to utf8mb4 and add php7 mysql compat shim fixes #10, #35, #36 (hopefully) --- lib/mysql.php | 8 +- lib/mysql_compat.php | 834 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 841 insertions(+), 1 deletion(-) create mode 100644 lib/mysql_compat.php diff --git a/lib/mysql.php b/lib/mysql.php index 181df03..7301710 100644 --- a/lib/mysql.php +++ b/lib/mysql.php @@ -1,4 +1,10 @@ 1 connection @@ -22,7 +28,7 @@ $this->connection = (($persist) ? mysql_pconnect($host,$user,$pass) : mysql_connect($host,$user,$pass)); $t = microtime(true)-$start; $this->id = ++self::$connection_count; - $this->set_character_encoding("utf8"); + $this->set_character_encoding("utf8mb4"); if (self::$debug_on) { $b = self::getbacktrace(); diff --git a/lib/mysql_compat.php b/lib/mysql_compat.php new file mode 100644 index 0000000..5461e98 --- /dev/null +++ b/lib/mysql_compat.php @@ -0,0 +1,834 @@ + + * @copyright Copyright (c) 2017 Davey Shafik + * @license MIT License + * @link https://github.com/dshafik/php7-mysql-shim + */ + +/** + * A drop-in replacement for ext/mysql in PHP 7+ using ext/mysqli instead + * + * This library is meant to be a _stop-gap_. It will be slower than using + * the native functions directly. + * + * You should switch to ext/pdo_mysql or ext/mysqli, and migrate to prepared + * queries (@see http://php.net/manual/en/pdo.prepared-statements.php) to + * ensure you are securely interacting with your database. + */ +namespace { + + if (!extension_loaded('mysql')) { + if (!extension_loaded('mysqli')) { + trigger_error('php7-mysql-shim: ext/mysqli is required', E_USER_ERROR); + } + + define('MYSQL_ASSOC', 1); + define('MYSQL_NUM', 2); + define('MYSQL_BOTH', 3); + define('MYSQL_CLIENT_COMPRESS', 32); + define('MYSQL_CLIENT_SSL', 2048); + define('MYSQL_CLIENT_INTERACTIVE', 1024); + define('MYSQL_CLIENT_IGNORE_SPACE', 256); + + function mysql_connect( + $hostname = null, + $username = null, + $password = null, + $new = false, + $flags = 0 + ) { + if ($new !== false) { + trigger_error('Argument $new is no longer supported in PHP > 7', E_USER_WARNING); + } + if (null === $hostname) { + $hostname = ini_get('mysqli.default_host') ?: null; + } + if (null === $username) { + $username = ini_get('mysqli.default_user') ?: null; + } + if (null === $password) { + $password = ini_get('mysqli.default_pw') ?: null; + } + + $hash = sha1($hostname . $username . $flags); + /* persistent connections start with p: */ + if ($hostname{1} !== ':' && isset(\Dshafik\MySQL::$connections[$hash])) { + \Dshafik\MySQL::$last_connection = \Dshafik\MySQL::$connections[$hash]['conn']; + \Dshafik\MySQL::$connections[$hash]['refcount'] += 1; + return \Dshafik\MySQL::$connections[$hash]['conn']; + } + + /* No flags, means we can use mysqli_connect() */ + if ($flags === 0) { + $conn = mysqli_connect($hostname, $username, $password); + if (!$conn instanceof mysqli) { + return false; + } + \Dshafik\MySQL::$last_connection = $conn; + $conn->hash = $hash; + \Dshafik\MySQL::$connections[$hash] = array('refcount' => 1, 'conn' => $conn); + + return $conn; + } + + /* Flags means we need to use mysqli_real_connect() instead, and handle exceptions */ + try { + \Dshafik\MySQL::$last_connection = $conn = mysqli_init(); + + mysqli_real_connect( + $conn, + $hostname, + $username, + $password, + '', + null, + '', + $flags + ); + + // @codeCoverageIgnoreStart + // PHPUnit turns the warning from mysqli_real_connect into an exception, so this never runs + if ($conn === false) { + return false; + } + // @codeCoverageIgnoreEnd + + $conn->hash = $hash; + \Dshafik\MySQL::$connections[$hash] = array('refcount' => 1, 'conn' => $conn); + + return $conn; + } catch (\Throwable $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + // @codeCoverageIgnoreStart + // PHPUnit turns the warning into an exception, so this never runs + return false; + // @codeCoverageIgnoreEnd + } + } + + function mysql_pconnect( + $hostname = null, + $username = null, + $password = null, + $flags = 0 + ) { + $hostname = 'p:' . $hostname; + return mysql_connect($hostname, $username, $password, false, $flags); + } + + function mysql_close(\mysqli $link = null) + { + $isDefault = ($link === null); + + $link = \Dshafik\MySQL::getConnection($link, __FUNCTION__); + if ($link === null) { + // @codeCoverageIgnoreStart + // PHPUnit Warning -> Exception + return false; + // @codeCoverageIgnoreEnd + } + + if (isset(\Dshafik\MySQL::$connections[$link->hash])) { + \Dshafik\MySQL::$connections[$link->hash]['refcount'] -= 1; + } + + $return = true; + if (\Dshafik\MySQL::$connections[$link->hash]['refcount'] === 0) { + $return = mysqli_close($link); + unset(\Dshafik\MySQL::$connections[$link->hash]); + } + + if ($isDefault) { + Dshafik\MySQL::$last_connection = null; + } + + return $return; + } + + function mysql_select_db($databaseName, \mysqli $link = null) + { + $link = \Dshafik\MySQL::getConnection($link); + + return mysqli_query( + $link, + 'USE `' . mysqli_real_escape_string($link, $databaseName) . '`' + ) !== false; + } + + function mysql_query($query, \mysqli $link = null) + { + return mysqli_query(\Dshafik\MySQL::getConnection($link), $query); + } + + function mysql_unbuffered_query($query, \mysqli $link = null) + { + $link = \Dshafik\MySQL::getConnection($link); + if (mysqli_real_query($link, $query)) { + return mysqli_use_result($link); + } + + return false; + } + + function mysql_db_query($databaseName, $query, \mysqli $link = null) + { + if (mysql_select_db($databaseName, $link)) { + return mysql_query($query, $link); + } + return false; + } + + function mysql_list_dbs(\mysqli $link = null) + { + return mysql_query('SHOW DATABASES', $link); + } + + function mysql_list_tables($databaseName, \mysqli $link = null) + { + $link = \Dshafik\MySQL::getConnection($link); + $query = sprintf( + 'SHOW TABLES FROM `%s`', + mysql_real_escape_string($databaseName, $link) + ); + return mysql_query($query, $link); + } + + function mysql_list_fields($databaseName, $tableName, \mysqli $link = null) + { + $link = \Dshafik\MySQL::getConnection($link); + + $query = sprintf( + 'SHOW COLUMNS FROM `%s`.`%s`', + mysqli_real_escape_string($link, $databaseName), + mysqli_real_escape_string($link, $tableName) + ); + + $result = mysql_query($query, $link); + + if ($result instanceof \mysqli_result) { + $result->table = $tableName; + return $result; + } + + trigger_error('mysql_list_fields(): Unable to save MySQL query result', E_USER_WARNING); + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + function mysql_list_processes(\mysqli $link = null) + { + return mysql_query('SHOW PROCESSLIST', $link); + } + + function mysql_error(\mysqli $link = null) + { + return mysqli_error(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_errno(\mysqli $link = null) + { + return mysqli_errno(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_affected_rows(\mysqli $link = null) + { + return mysqli_affected_rows(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_insert_id($link = null) /*|*/ + { + return mysqli_insert_id(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_result($result, $row, $field = 0) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + if (!mysqli_data_seek($result, $row)) { + trigger_error( + sprintf( + 'mysql_result(): Unable to jump to row %d on MySQL result index %s', + $row, + spl_object_hash($result) + ), + E_USER_WARNING + ); + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + $found = true; + if (strpos($field, '.') !== false) { + list($table, $name) = explode('.', $field); + $i = 0; + $found = false; + mysqli_field_seek($result, 0); + while ($column = mysqli_fetch_field($result)) { + if ($column->table === $table && $column->name === $name) { + $field = $i; + $found = true; + break; + } + $i++; + } + } + + $row = mysql_fetch_array($result); + if ($found && array_key_exists($field, $row)) { + return $row[$field]; + } + + trigger_error( + sprintf( + '%s(): %s not found in MySQL result index %s', + __FUNCTION__, + $field, + spl_object_hash($result) + ), + E_USER_WARNING + ); + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + function mysql_num_rows($result) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + $previous = error_reporting(0); + $rows = mysqli_num_rows($result); + error_reporting($previous); + + return $rows; + } + + function mysql_num_fields($result) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_num_fields($result); + } + + function mysql_fetch_row($result) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_fetch_row($result) ?: false; + } + + function mysql_fetch_array($result, $resultType = MYSQL_BOTH) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_fetch_array($result, $resultType) ?: false; + } + + function mysql_fetch_assoc($result) /* : array|null */ + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + return mysqli_fetch_assoc($result) ?: false; + } + + function mysql_fetch_object($result, $class = null, array $params = array()) /* : object|null */ + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + if ($class === null) { + $object = mysqli_fetch_object($result); + } else { + $object = mysqli_fetch_object($result, $class, $params); + } + + return $object ?: false; + } + + function mysql_data_seek($result, $offset) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_data_seek($result, $offset); + } + + function mysql_fetch_lengths($result) /* : array|*/ + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_fetch_lengths($result); + } + + function mysql_fetch_field($result) /* : object|*/ + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_fetch_field($result); + } + + function mysql_field_seek($result, $field) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_field_seek($result, $field); + } + + function mysql_free_result($result) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return mysqli_free_result($result); + } + + function mysql_field_name($result, $field) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'name'); + } + + function mysql_field_table($result, $field) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'table'); + } + + function mysql_field_len($result, $field) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'length'); + } + + function mysql_field_type($result, $field) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'type'); + } + + function mysql_field_flags($result, $field) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'flags'); + } + + function mysql_escape_string($unescapedString) + { + if (\Dshafik\MySQL::$last_connection === null) { + trigger_error( + sprintf( + '%s() is insecure; use mysql_real_escape_string() instead!', + __FUNCTION__ + ), + E_USER_NOTICE + ); + + return \Dshafik\MySQL::escapeString($unescapedString); + } + return mysql_real_escape_string($unescapedString, null); + } + + function mysql_real_escape_string($unescapedString, \mysqli $link = null) + { + return mysqli_escape_string(\Dshafik\MySQL::getConnection($link), $unescapedString); + } + + function mysql_stat(\mysqli $link = null) + { + return mysqli_stat(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_thread_id(\mysqli $link = null) + { + return mysqli_thread_id(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_client_encoding(\mysqli $link = null) + { + return mysqli_character_set_name(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_ping(\mysqli $link = null) + { + return mysqli_ping(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_get_client_info(\mysqli $link = null) + { + return mysqli_get_client_info(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_get_host_info(\mysqli $link = null) + { + return mysqli_get_host_info(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_get_proto_info(\mysqli $link = null) + { + return mysqli_get_proto_info(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_get_server_info(\mysqli $link = null) + { + return mysqli_get_server_info(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_info(\mysqli $link = null) + { + return mysqli_info(\Dshafik\MySQL::getConnection($link)); + } + + function mysql_set_charset($charset, \mysqli $link = null) + { + return mysqli_set_charset(\Dshafik\MySQL::getConnection($link), $charset); + } + + function mysql_db_name($result, $row, $field = 0) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + // Alias as per https://github.com/php/php-src/blob/PHP-5.6/ext/mysql/php_mysql.c#L319 + return mysql_result($result, $row, $field); + } + + function mysql_tablename($result, $row) + { + if (!\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + // Alias as per http://lxr.php.net/xref/PHP_5_6/ext/mysql/php_mysql.c#321 + return mysql_result($result, $row, 'Table'); + } + + /* Aliases */ + + function mysql_fieldname($result, $field) + { + return mysql_field_name($result, $field); + } + + function mysql_fieldtable($result, $field) + { + return mysql_field_table($result, $field); + } + + function mysql_fieldlen($result, $field) + { + return mysql_field_len($result, $field); + } + + function mysql_fieldtype($result, $field) + { + return mysql_field_type($result, $field); + } + + function mysql_fieldflags($result, $field) + { + return mysql_field_flags($result, $field); + } + + function mysql_selectdb($databaseName, $link = null) + { + return mysql_select_db($databaseName, $link); + } + + function mysql_freeresult($result) + { + return mysql_free_result($result); + } + + function mysql_numfields($result) + { + return mysql_num_fields($result); + } + + function mysql_numrows($result) + { + return mysql_num_rows($result); + } + + function mysql_listdbs($link) + { + return mysql_list_dbs($link); + } + + function mysql_listtables($databaseName, $link = null) + { + return mysql_list_tables($databaseName, $link); + } + + function mysql_listfields($databaseName, $tableName, $link = null) + { + return mysql_list_fields($databaseName, $tableName, $link); + } + + function mysql_dbname($result, $row, $field = 0) + { + return mysql_db_name($result, $row, $field); + } + + function mysql_table_name($result, $row) + { + return mysql_tablename($result, $row); + } + } +} + +namespace Dshafik { + + class MySQL + { + public static $last_connection = null; + public static $connections = array(); + + public static function getConnection($link = null, $func = null) + { + if ($link !== null) { + return $link; + } + + if (static::$last_connection === null) { + $err = 'A link to the server could not be established'; + if ($func !== null) { + $err = $func . '(): no MySQL-Link resource supplied'; + } + trigger_error($err, E_USER_WARNING); + return false; + } + + return static::$last_connection; + } + + public static function mysqlFieldInfo(\mysqli_result $result, $field, $what) + { + try { + $field = mysqli_fetch_field_direct($result, $field); + } catch (\Exception $e) { + trigger_error( + sprintf( + 'mysql_field_%s(): Field %d is invalid for MySQL result index %s', + ($what !== 'length') ? $what : 'len', + $field, + spl_object_hash($result) + ), + E_USER_WARNING + ); + // @codeCoverageIgnoreStart + // PHPUnit turns the warning into an exception, so this never runs + return false; + // @codeCoverageIgnoreEnd + } + + if ($what === 'type') { + return static::getFieldType($field->type); + } + + if ($what === 'flags') { + return static::getFieldFlags($field->flags); + } + + if (isset($field->{$what})) { + return $field->{$what}; + } + + return false; + } + + public static function checkValidResult($result, $function) + { + if (!($result instanceof \mysqli_result)) { + if ($function !== 'mysql_fetch_object') { + trigger_error( + $function . '() expects parameter 1 to be resource, ' . strtolower(gettype($result)) . ' given', + E_USER_WARNING + ); + } + + if ($function === 'mysql_fetch_object') { + trigger_error( + $function . '(): supplied argument is not a valid MySQL result resource', + E_USER_WARNING + ); + } + return false; + } + + return true; + } + + public static function escapeString($unescapedString) + { + $escapedString = ''; + for ($i = 0, $max = strlen($unescapedString); $i < $max; $i++) { + $escapedString .= self::escapeChar($unescapedString{$i}); + } + + return $escapedString; + } + + protected static function getFieldFlags($what) + { + // Order of flags taken from http://lxr.php.net/xref/PHP_5_6/ext/mysql/php_mysql.c#2507 + $flags = array( + MYSQLI_NOT_NULL_FLAG => 'not_null', + MYSQLI_PRI_KEY_FLAG => 'primary_key', + MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', + MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', + MYSQLI_BLOB_FLAG => 'blob', + MYSQLI_UNSIGNED_FLAG => 'unsigned', + MYSQLI_ZEROFILL_FLAG => 'zerofill', + MYSQLI_BINARY_FLAG => 'binary', + MYSQLI_ENUM_FLAG => 'enum', + MYSQLI_SET_FLAG => 'set', + MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', + MYSQLI_TIMESTAMP_FLAG => 'timestamp', + ); + + $fieldFlags = array(); + foreach ($flags as $flag => $value) { + if ($what & $flag) { + $fieldFlags[] = $value; + } + } + + return implode(' ', $fieldFlags); + } + + protected static function getFieldType($what) + { + $types = array( + MYSQLI_TYPE_STRING => 'string', + MYSQLI_TYPE_VAR_STRING => 'string', + MYSQLI_TYPE_ENUM => 'string', + MYSQLI_TYPE_SET => 'string', + + MYSQLI_TYPE_LONG => 'int', + MYSQLI_TYPE_TINY => 'int', + MYSQLI_TYPE_SHORT => 'int', + MYSQLI_TYPE_INT24 => 'int', + MYSQLI_TYPE_CHAR => 'int', + MYSQLI_TYPE_LONGLONG => 'int', + + MYSQLI_TYPE_DECIMAL => 'real', + MYSQLI_TYPE_FLOAT => 'real', + MYSQLI_TYPE_DOUBLE => 'real', + MYSQLI_TYPE_NEWDECIMAL => 'real', + + MYSQLI_TYPE_TINY_BLOB => 'blob', + MYSQLI_TYPE_MEDIUM_BLOB => 'blob', + MYSQLI_TYPE_LONG_BLOB => 'blob', + MYSQLI_TYPE_BLOB => 'blob', + + MYSQLI_TYPE_NEWDATE => 'date', + MYSQLI_TYPE_DATE => 'date', + MYSQLI_TYPE_TIME => 'time', + MYSQLI_TYPE_YEAR => 'year', + MYSQLI_TYPE_DATETIME => 'datetime', + MYSQLI_TYPE_TIMESTAMP => 'timestamp', + + MYSQLI_TYPE_NULL => 'null', + + MYSQLI_TYPE_GEOMETRY => 'geometry', + ); + + return isset($types[$what]) ? $types[$what] : 'unknown'; + } + + protected static function escapeChar($char) + { + switch ($char) { + case "\0": + $esc = "\\0"; + break; + case "\n": + $esc = "\\n"; + break; + case "\r": + $esc = "\\r"; + break; + case '\\': + case '\'': + case '"': + $esc = "\\{$char}"; + break; + case "\032": + $esc = "\\Z"; + break; + default: + $esc = $char; + break; + } + + return $esc; + } + } +} From f50d45104ceb014ee887dec680f25ccaafd7b5f6 Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Tue, 18 Jul 2017 23:11:39 -0700 Subject: [PATCH 02/13] Remove dead code --- lib/layout_mobile.php | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 lib/layout_mobile.php diff --git a/lib/layout_mobile.php b/lib/layout_mobile.php deleted file mode 100644 index cc9a8ef..0000000 --- a/lib/layout_mobile.php +++ /dev/null @@ -1,5 +0,0 @@ - From 4fdd16cf5780f27127049dee216171a514199b37 Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Wed, 19 Jul 2017 00:20:25 -0700 Subject: [PATCH 03/13] Fix and add thread meta tags --- lib/layout.php | 36 ++++++++++++++++-------------------- thread.php | 19 +++++++++++-------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/lib/layout.php b/lib/layout.php index d038615..154b3bb 100644 --- a/lib/layout.php +++ b/lib/layout.php @@ -10,7 +10,7 @@ header('Pragma: no-cache'); $userip = $_SERVER['REMOTE_ADDR']; - + if (!($clientip = filter_var(getenv("HTTP_CLIENT_IP"), FILTER_VALIDATE_IP))) $clientip = "XXXXXXXXXXXXXXXXX"; if (!($forwardedip = filter_var(getenv("HTTP_X_FORWARDED_FOR"), FILTER_VALIDATE_IP))) $forwardedip = "XXXXXXXXXXXXXXXXX"; // $clientip=(getenv("HTTP_CLIENT_IP") == "" ? "XXXXXXXXXXXXXXXXX" : getenv("HTTP_CLIENT_IP")); @@ -285,17 +285,17 @@ } $views=$sql->resultq('SELECT views FROM misc')+1; - + if (!$ipbanned && !$torbanned && (!defined("IS_AJAX_REQUEST") || !IS_AJAX_REQUEST)) { // Don't increment the view counter for bots // Todo: Actually check for bots and disable it because hdurfs $sql->query("UPDATE misc SET views=$views"); - + if($views%10000000>9999000 or $views%10000000<1000) { $u=($loguserid?$loguserid:0); $sql->query("INSERT INTO hits VALUES ($views,$u,'$userip',".ctime().')'); } - + // Print out a message to IRC whenever a 10-million-view milestone is hit if ($views%10000000>9999994 || ($views % 10000000 >= 9991000 && $views % 1000 == 0) || ($views % 10000000 >= 9999900 && $views % 10 == 0) || ($views > 5 && $views % 10000000 < 5)) { xk_ircsend("0|View ". xk(11) . str_pad(number_format($views), 10, " ", STR_PAD_LEFT) . xk() ." by ". ($loguser['id'] ? xk(11) . str_pad($loguser['name'], 25, " ") : xk(12) . str_pad($_SERVER['REMOTE_ADDR'], 25, " ")) . xk() . ($views % 1000000 > 500000 ? " (". xk(12) . str_pad(number_format(1000000 - ($views % 1000000)), 5, " ", STR_PAD_LEFT) . xk(2) ." to go" . xk() .")" : "")); @@ -359,7 +359,7 @@ $yyy .= ""; } }*/ - + $dispviews = $views; // if (($views % 1000000 >= 999000) && ($views % 1000000 < 999990)) // $dispviews = substr((string)$views, 0, -3) . "???"; @@ -376,15 +376,14 @@ if (filter_bool($meta['noindex'])) $metatag .= ""; - if (filter_bool($meta['description'])) + if (isset($meta['description'])) $metatag .= ""; - if (filter_bool($x_hacks['smallbrowse']) and false) { - $css = ""; - $css = ""; + if (isset($meta['canonical'])) { + $metatag .= "$windowtitle $metatag $css @@ -400,7 +399,7 @@ Views: $dispviews
$headlinks2 -
". date($dateformat,ctime()+$tzoff) ."
" +
". date($dateformat,ctime()+$tzoff) ."
" : "
$dispviews views, ". date($dateformat,ctime()+$tzoff) ." $headlinks2") ." @@ -422,16 +421,16 @@ $ref=filter_string($_SERVER['HTTP_REFERER']); $url=getenv('SCRIPT_URL'); - + if(!$url) $url=str_replace('/etc/board','',getenv('SCRIPT_NAME')); $q=getenv('QUERY_STRING'); - + if($q) $url.="?$q"; - + if($ref && substr($ref,7,7)!="jul.rus") $sql->query("INSERT INTO referer (time,url,ref,ip) VALUES (". ctime() .", '".addslashes($url)."', '".addslashes($ref)."', '". $_SERVER['REMOTE_ADDR'] ."')"); $sql->query("DELETE FROM guests WHERE ip='$userip' OR date<".(ctime()-300)); - + if($log) { /* $ulastip=mysql_result(mysql_query("SELECT lastip FROM users WHERE id=$loguserid"),0,0); @@ -467,7 +466,7 @@ } else { $sql->query("INSERT INTO guests (ip,date,useragent,lasturl) VALUES ('$userip',".ctime().",'".addslashes($_SERVER['HTTP_USER_AGENT']) ."','". addslashes($url) ."')"); } - + @@ -494,7 +493,7 @@ {$smallfont} Acmlmboard - ". (file_exists('version.txt') ? file_get_contents("version.txt") : shell_exec("git log --format='commit %h [%ad]' --date='short' -n 1")) ." -
©2000-". date("Y") ." Acmlm, Xkeeper, Inuyasha, et al. +
©2000-". date("Y") ." Acmlm, Xkeeper, Inuyasha, et al. @@ -540,6 +539,3 @@ piwikTracker.enableLinkTracking();

E-mail: xkeeper@gmail.com $tblend$footer"); - - - diff --git a/thread.php b/thread.php index b504814..24d3f13 100644 --- a/thread.php +++ b/thread.php @@ -20,7 +20,7 @@ if ($id && (filter_int($_GET['addvote']) || filter_int($_GET['delvote']))) { $option = (($_GET['addvote']) ? 'addvote' : 'delvote'); $choice = filter_int($_GET[$option]); - + $pollid = $sql->resultq("SELECT poll FROM threads WHERE id='{$id}'"); if (!$pollid) return header("Location: ?id={$id}#{$id}"); @@ -56,6 +56,9 @@ } $numposts = $sql->resultq("SELECT COUNT(*) FROM `posts` WHERE `thread` = '{$id}' AND `id` < '{$pid}'"); $page = floor($numposts / $ppp); + + // Canonical page w/o ppp link (for bots) + $meta['canonical'] = "thread.php?id=$id&page=$page"; } define('E_BADPOSTS', -1); @@ -90,7 +93,7 @@ } $thread['title'] = str_replace("<", "<", $thread['title']); - + $forumid = intval($thread['forum']); $forum = $sql->fetchq("SELECT * FROM forums WHERE id=$forumid"); @@ -175,7 +178,7 @@ $meta['noindex'] = true; // prevent search engines from indexing what they can't access require_once 'lib/layout.php'; errorpage("No thread specified.",'the index page',"index.php"); - } + } //temporary if ($windowtitle) $windowtitle = "$boardname -- $windowtitle"; @@ -186,7 +189,7 @@ $fonline = fonlineusers($forumid); if (mysql_num_rows($sql->query("SELECT user FROM forummods WHERE forum='$forumid' and user='$loguserid'"))) $ismod = true; - } + } $modfeats = ''; if ($id && $ismod) { $trashid = 27; @@ -354,7 +357,7 @@ $page = max(0, filter_int($page)); $min = $ppp * $page; - + if ($user) $searchon = "user={$user}"; else $searchon = "thread={$id}"; @@ -392,7 +395,7 @@ $pthread = $sql->fetchq("SELECT id,title,forum FROM threads WHERE id=$post[thread]", MYSQL_BOTH, true); $pforum = $sql->fetchq("SELECT minpower FROM forums WHERE id=".intval($pthread[forum]), MYSQL_BOTH, true); } - + $post['act'] = filter_int($act[$post['user']]); if (!$pforum || $pforum['minpower'] <= $power) @@ -430,7 +433,7 @@ $pagelinks .= " ..."; } } - + if ($i == $page) $pagelinks .= " ".($i + 1); else @@ -455,4 +458,4 @@ function notAuthorizedError() { $redir = (($log) ? 'index.php' : 'login.php'); $rtext = (($log) ? 'the index page' : 'log in (then try again)'); errorpage("Couldn't enter the forum. You don't have access to this restricted forum.", $rtext, $redir); -} \ No newline at end of file +} From 9318ec258d2e68f94a98b23969b4f2b9bd6713d1 Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Wed, 19 Jul 2017 00:21:19 -0700 Subject: [PATCH 04/13] Add photobucket replacement image --- images/photobucket.png | Bin 0 -> 2420 bytes lib/function.php | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 images/photobucket.png diff --git a/images/photobucket.png b/images/photobucket.png new file mode 100644 index 0000000000000000000000000000000000000000..b761da7efdb7d2d171b4e2d7c5eb0199ecb3000e GIT binary patch literal 2420 zcmV-)35)iLP)hKY%Zu&}U{l$4^PqOGm1rlzKunVFrP zouHtgtE;Q8udk1fk7j0OpP!$Sl9G#yi+_KAq@<*6ZEdKisCamIm6es2mX>L0X@`f0 zj*gCee0*_naf5?{s&QbJ000QLNkl1%`;PzPrx9cw`nx!0fi_MoKhprqi4m!#xS2{@u9X*tyWRWUfCB#-L2S(upP z?yfzkBha^m9O2&aL&A>0cM@`h`^OInJHlT}!?B=;4|xk~Nf#g55$qsi zBeshjSH$KH#|t8M@Tc4X$imA;URqhk{^Dld2T}TeBWwGTL6dvghpQg5_YH`h?v12qetKOzlP|du0+Hx2=Sw@ z2|~gSCBu*$5r2FMQ8ys)jELL6hR7f!>;Un1kX+4k3u1}7)-XiMLPMUUtZzYVQP?qp zT(SLP8#l5R8d6nnVaU-#n$Z?1M2omN4;6|m+jfOs-5}*UF7%MyRu{FRFpWLo(e!~< zF8L8phaVROBgm_1Tc_A!}hx7oo*qf3~mi5iNP+H$! zn7_{LiDEy7=sutF{GGPGAcr~LV3}oRp@*5sT0}e^4*L%kgiu~#fNTrD*LS9*w##C2 z)S4F>NZEn=)t)RQ_mEF}O>%lu3eMTpwRPPL4$%JB!hyg<_!>fxH}ombFhGs~9b`+};VP(4^gVc4Lnq^Fj-u zGjcwMd?4a0IS6tcK6YJ8wA&E%B}4$ljoSet{XP$pAbxFLNDx(h1^J1HFAAm*IzDa@ zu|%CxjK6YN43U0iXZn`?36gyUQR>6={ACI`AmRmPkh1mHtC>@^y8>2)_`Yq19s4|m z%nLn4DfNknm8pF{g}^9#b69CgGn72!*a2k?$j+7wyTQh-5M*BHAxf!VhrOu188mAjGV_hQku z%>aR`-A%gT*je|8eH4T$hsN#z&q!%zka?lRQQj}+N{*7NOKGHHua{d>5pB>`FYF1i zMbmaXr10aWoE%!7UwCS+ zvh9wzO^a7BnHLt-MOAs8|FiJ<{qt}*m)E2GT>iR6(iUwSYBOWh* z2VuDn7hi1v!tCIOgdGeJHU~c>>|lVfI`|=B2R|g}A3=lR4 zKP2p6fUr6EAz=ptgu%fKiFfcrid|;27edytj(Eu8HhUcBiQBOpvYkM(2nREyX~&Rj zgo77C_vXHxh3MiO{E&^m->y?#A{@*RL_}Y8ZXO4I~)GbJ^lp*wALgaAKdG?UD0{}LN`VvwZ z2slFH<`5V{OAtHeq=o2HV-y6UAj(0ifAThk9NbZ~oWs zVFoNgdN;}AY$x}1O^chtU+lI|!!(DcFAZbcMI5sN$VK;ku83DR_x}tgh5P4*1e-=S z?r`iMui~NrGGejbe@K;$Kt6qF0)>efz%z8)E$)69TX-9|C?0!9qGTL zC;hi3rT-o)ehF8z>A&kO{kQL>|2{;13jez{860W9#r5C!>L&E2o&MXv(|w7-a$#7K}p_0NuEJTos0fsOz5}^QV(nnCzS5TN0 m{1$l7Fd(=skWl{5-TyCyV-@jC&cQ", '-->', $p); } + $p=preg_replace("'(https?://.*\.?photobucket.com/)'si",'images/photobucket.png#\\1',$p); + + $p=str_replace("http://insectduel.proboards82.com","http://jul.rustedlogic.net/idiotredir.php?",$p); // $p=str_replace("http://imageshack.us", "imageshit", $p); $p=preg_replace("'http://.{0,3}\.?tinypic\.com'si",'tinyshit',$p); @@ -1614,5 +1617,3 @@ function ircerrors($type, $msg, $file, $line, $context) { " $typetext: ".xk()."($errorlocation) $msg"); return true; } - - From 0449b82b42865bb8028ad25d5f05d50d8b34a8ad Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Wed, 19 Jul 2017 00:21:49 -0700 Subject: [PATCH 05/13] Shrink downtime window from 5 minutes to 1 minute --- lib/function.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/function.php b/lib/function.php index dced7a0..49b4419 100644 --- a/lib/function.php +++ b/lib/function.php @@ -14,7 +14,7 @@ $id = 0; // Wait for the midnight backup to finish... - if ((int)date("Gi") < 5) { + if ((int)date("Gi") < 1) { require "lib/downtime.php"; } From 877647b409daf90a042f9586dac8fb422403af9f Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Wed, 19 Jul 2017 00:22:20 -0700 Subject: [PATCH 06/13] Add years to readable durations --- lib/function.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/function.php b/lib/function.php index 49b4419..610cd10 100644 --- a/lib/function.php +++ b/lib/function.php @@ -323,12 +323,13 @@ function readpostread($userid){ } function timeunits($sec){ - if($sec<60) return "$sec sec."; - if($sec<3600) return floor($sec/60).' min.'; - if($sec<7200) return '1 hour'; - if($sec<86400) return floor($sec/3600).' hours'; - if($sec<172800) return '1 day'; - return floor($sec/86400).' days'; + if($sec<60) return "$sec sec."; + if($sec<3600) return floor($sec/60).' min.'; + if($sec<7200) return '1 hour'; + if($sec<86400) return floor($sec/3600).' hours'; + if($sec<172800) return '1 day'; + if($sec<31556926) return floor($sec/86400).' days'; + return sprintf("%.1f years", floor($sec/31556926)); } function timeunits2($sec){ From 14f8190906d0bcfcae874d80b9ee2c9df7603409 Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Wed, 19 Jul 2017 00:22:37 -0700 Subject: [PATCH 07/13] Remove old filter tracking code --- lib/function.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/function.php b/lib/function.php index 610cd10..15c1bb2 100644 --- a/lib/function.php +++ b/lib/function.php @@ -1178,14 +1178,6 @@ function adminlinkbar($sel = 'admin.php') { return $r; } -function nuke_js($before, $after) { - - global $sql, $loguser; - $page = addslashes($_SERVER['REQUEST_URI']); - $time = ctime(); - $sql -> query("INSERT INTO `jstrap` SET `loguser` = '". $loguser['id'] ."', `ip` = '". $_SERVER['REMOTE_ADDR'] ."', `text` = '". addslashes($before) ."', `url` = '$page', `time` = '$time', `filtered` = '". addslashes($after) ."'"); - -} function include_js($fn, $as_tag = false) { // HANDY JAVASCRIPT INCLUSION FUNCTION if ($as_tag) { @@ -1207,9 +1199,6 @@ function dofilters($p){ $p=preg_replace("''si",'',$p); $p=preg_replace("'oad',$p); @@ -1228,10 +1217,6 @@ function dofilters($p){ $p=preg_replace("'onmouseout'si",'onmouseout',$p); $p=preg_replace("'onmouseover'si",'onmouseover',$p); $p=preg_replace("'onmouseup'si",'onmouseup',$p); - - if ($temp != $p) { - nuke_js($temp, $p); - } } //$p=preg_replace("''si","",$p); From b8caeda4086ccfa0286a0b7ff7d18802bce528db Mon Sep 17 00:00:00 2001 From: Xkeeper Date: Wed, 19 Jul 2017 00:23:19 -0700 Subject: [PATCH 08/13] Update and enhance mobile view --- css/base.css | 77 ++++++++++++++++++++++++++++---------------- css/basics.css | 33 +++++++++++++++++++ lib/layout.php | 46 ++++---------------------- lib/threadpost.php | 12 +++---- mobile.css | 4 --- tlayouts/compact.php | 14 +++++--- 6 files changed, 104 insertions(+), 82 deletions(-) create mode 100644 css/basics.css delete mode 100644 mobile.css diff --git a/css/base.css b/css/base.css index 4688976..0d7adc7 100644 --- a/css/base.css +++ b/css/base.css @@ -1,33 +1,56 @@ -textarea,input,select { - border: 1px solid #000; - background: #000; - color: #EEE; - font: 10pt monospace; -} -input[type=radio] { - border: none; -} -input[type=submit] { - border: #000 solid 2px; - font: 10pt 'verdana', sans-serif; -} -body, table, thead, tbody, span, td, tr, th, a, img, br { padding: 0; margin: 0; border: 0; font-size: 100%; } -center { text-align: center; } -.tdbgh, .tbl, .tdbgc, .tdbg1, .tdbg2 { line-height: 1; padding: 1px;} -table { border-spacing: 0; border-collapse: collapse; } -a:link,a:visited,a:active,a:hover { text-decoration:none; font-weight: bold; } -table { padding: 0.5em; } -span.lastpost { font-size: 90%; padding: 0; margin: 0; } -div.lastpost { font-size: 90%; text-align: right !important; } +/* Global CSS styles across every theme */ -.table { width: 100%; empty-cells: show;} -.sparkline { display: none; } -.center, center { text-align: center; } -.right { text-align: right; } +/* Make images upscale crispy */ +* { + image-rendering: -moz-crisp-edges; + image-rendering: -o-crisp-edges; + image-rendering: -webkit-optimize-contrast; + image-rendering: crisp-edges; + image-rendering: pixelated; + -ms-interpolation-mode:nearest-neighbor; + } -code { overflow: auto; width: 100%; white-space: pre; display: block; } -code br { display: none; } +/* Make all links bold and not underlined by default */ +a:link,a:visited,a:active,a:hover{text-decoration:none;font-weight:bold;} +/* Mostly legacy thing from when IE had a blue border around link images */ +img { border:none; } +.center {text-align:center} +.right {text-align:right} + +/* Make code blocks scroll instead of stretching the page */ +code { + overflow: auto; + width: 100%; + white-space: pre; + display: block; +} + +/* "Fix" for auto-generated
tags in and
 blocks */
+code br, pre br { display: none; }
+
+/* Make radio buttons look not terrible */
+input[type=radio] { color: black; background: white; }
+
+/* Spoiler tag code */
 .pstspl1 {opacity:0;}
 .pstspl1:hover {opacity:1;}
 .pstspl2 {background:#000;color:#FFF;display:block;}
+
+/* Stop avatars from being huge */
+.avatar	{
+	max-width:	200px;
+	}
+
+/* On mobile, make avatars smaller */
+.mobile-avatar {
+	float:	left;
+	height:	50px;
+	width:	50px;
+	padding: 2px;
+	text-align:	center;
+}
+.mobile-avatar > .avatar {
+	max-height:	100%;
+	max-width:	100%;
+}
diff --git a/css/basics.css b/css/basics.css
new file mode 100644
index 0000000..4688976
--- /dev/null
+++ b/css/basics.css
@@ -0,0 +1,33 @@
+textarea,input,select {
+	border: 1px solid #000;
+	background: #000;
+	color: #EEE;
+	font: 10pt monospace;
+}
+input[type=radio] {
+	border: none;
+}
+input[type=submit] {
+	border: #000 solid 2px;
+	font: 10pt 'verdana', sans-serif;
+}
+body, table, thead, tbody, span, td, tr, th, a, img, br { padding: 0; margin: 0; border: 0; font-size: 100%; }
+center { text-align: center; }
+.tdbgh, .tbl, .tdbgc, .tdbg1, .tdbg2 { line-height: 1; padding: 1px;}
+table { border-spacing: 0; border-collapse: collapse; }
+a:link,a:visited,a:active,a:hover { text-decoration:none; font-weight: bold; }
+table { padding: 0.5em; }
+span.lastpost { font-size: 90%; padding: 0; margin: 0; }
+div.lastpost { font-size: 90%; text-align: right !important; }
+
+.table { width: 100%; empty-cells: show;}
+.sparkline { display: none; }
+.center, center { text-align: center; }
+.right { text-align: right; }
+
+code { overflow: auto; width: 100%; white-space: pre; display: block; }
+code br { display: none; }
+
+.pstspl1 {opacity:0;}
+.pstspl1:hover {opacity:1;}
+.pstspl2 {background:#000;color:#FFF;display:block;}
diff --git a/lib/layout.php b/lib/layout.php
index 154b3bb..2c23100 100644
--- a/lib/layout.php
+++ b/lib/layout.php
@@ -73,43 +73,25 @@
 		// special "null" scheme.
 		$css = "";
 	} elseif (isset($schemetype) && $schemetype == 1) {
-		$css = "";
+		$css = "";
 		// possibly causes issue #19 - not sure why this was here
 		// likely irrelevant after addition of custom date formats
 		// (remove this later)
 		//$dateformat = "m/d/y h:i";
 		//$dateshort  = "m/d/y";
-		
+
 		// backwards compat
 		global $bgcolor, $linkcolor;
 		$bgcolor = "000";
 		$linkcolor = "FFF";
 	} else {
 		$css="
+