diff --git a/core/database.class.php b/core/database.class.php index 0d19c9e0..f0480699 100644 --- a/core/database.class.php +++ b/core/database.class.php @@ -20,7 +20,7 @@ class Querylet { * @param \Querylet $querylet */ public function append($querylet) { - assert(!is_null($querylet)); + assert('!is_null($querylet)'); $this->sql .= $querylet->sql; $this->variables = array_merge($this->variables, $querylet->variables); } @@ -295,7 +295,7 @@ class MemcacheCache implements CacheEngine { * @return array|bool|string */ public function get($key) { - assert(!is_null($key)); + assert('!is_null($key)'); $val = $this->memcache->get($key); if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { $hit = $val === false ? "miss" : "hit"; @@ -317,7 +317,7 @@ class MemcacheCache implements CacheEngine { * @param int $time */ public function set($key, $val, $time=0) { - assert(!is_null($key)); + assert('!is_null($key)'); $this->memcache->set($key, $val, false, $time); if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { file_put_contents("data/cache.log", "Cache set: $key ($time)\n", FILE_APPEND); @@ -328,7 +328,7 @@ class MemcacheCache implements CacheEngine { * @param string $key */ public function delete($key) { - assert(!is_null($key)); + assert('!is_null($key)'); $this->memcache->delete($key); if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { file_put_contents("data/cache.log", "Cache delete: $key\n", FILE_APPEND); @@ -354,7 +354,7 @@ class APCCache implements CacheEngine { } public function get($key) { - assert(!is_null($key)); + assert('!is_null($key)'); $val = apc_fetch($key); if($val) { $this->hits++; @@ -367,12 +367,12 @@ class APCCache implements CacheEngine { } public function set($key, $val, $time=0) { - assert(!is_null($key)); + assert('!is_null($key)'); apc_store($key, $val, $time); } public function delete($key) { - assert(!is_null($key)); + assert('!is_null($key)'); apc_delete($key); } diff --git a/core/exceptions.class.php b/core/exceptions.class.php index 14765760..d2400893 100644 --- a/core/exceptions.class.php +++ b/core/exceptions.class.php @@ -22,3 +22,8 @@ class PermissionDeniedException extends SCoreException {} * Example: Image::by_id(-1) returns null */ class ImageDoesNotExist extends SCoreException {} + +/* + * For validate_input() + */ +class InvalidInput extends SCoreException {} diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index ad5de8d2..2c914536 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -97,7 +97,7 @@ class Image { * @return Image */ public static function by_id(/*int*/ $id) { - assert(is_numeric($id)); + assert('is_numeric($id)'); global $database; $row = $database->get_row("SELECT * FROM images WHERE images.id=:id", array("id"=>$id)); return ($row ? new Image($row) : null); @@ -110,7 +110,7 @@ class Image { * @return Image */ public static function by_hash(/*string*/ $hash) { - assert(is_string($hash)); + assert('is_string($hash)'); global $database; $row = $database->get_row("SELECT images.* FROM images WHERE hash=:hash", array("hash"=>$hash)); return ($row ? new Image($row) : null); @@ -123,7 +123,7 @@ class Image { * @return Image */ public static function by_random($tags=array()) { - assert(is_array($tags)); + assert('is_array($tags)'); $max = Image::count_images($tags); if ($max < 1) return null; // From Issue #22 - opened by HungryFeline on May 30, 2011. $rand = mt_rand(0, $max-1); @@ -142,9 +142,9 @@ class Image { * @return Image[] */ public static function find_images(/*int*/ $start, /*int*/ $limit, $tags=array()) { - assert(is_numeric($start)); - assert(is_numeric($limit)); - assert(is_array($tags)); + assert('is_numeric($start)'); + assert('is_numeric($limit)'); + assert('is_array($tags)'); global $database, $user, $config, $order_sql; $images = array(); @@ -246,7 +246,7 @@ class Image { * @return mixed */ public static function count_images($tags=array()) { - assert(is_array($tags)); + assert('is_array($tags)'); global $database; $tag_count = count($tags); @@ -278,7 +278,7 @@ class Image { * @return float */ public static function count_pages($tags=array()) { - assert(is_array($tags)); + assert('is_array($tags)'); global $config; return ceil(Image::count_images($tags) / $config->get_int('index_images')); } @@ -299,8 +299,8 @@ class Image { * @return Image */ public function get_next($tags=array(), $next=true) { - assert(is_array($tags)); - assert(is_bool($next)); + assert('is_array($tags)'); + assert('is_bool($next)'); global $database; if($next) { @@ -562,18 +562,17 @@ class Image { * @param string[] $tags */ public function set_tags($tags) { + assert('is_array($tags) && count($tags) > 0', var_export($tags, true)); global $database; - assert(is_array($tags)); - $tags = array_map(array('Tag', 'sanitise'), $tags); $tags = Tag::resolve_aliases($tags); - assert(is_array($tags)); - assert(count($tags) > 0); - $new_tags = implode(" ", $tags); + if(count($tags) <= 0) { + throw new SCoreException('Tried to set zero tags'); + } - if($new_tags != $this->get_tag_list()) { + if(implode(" ", $tags) != $this->get_tag_list()) { // delete old $this->delete_tags_from_image(); // insert each new tags @@ -726,7 +725,7 @@ class Image { * @return \Querylet */ private static function build_search_querylet($terms) { - assert(is_array($terms)); + assert('is_array($terms)'); global $database; if($database->get_driver_name() === "mysql") return Image::build_ugly_search_querylet($terms); @@ -1104,7 +1103,7 @@ class Tag { * @return mixed */ public static function sanitise($tag) { - assert(is_string($tag)); + assert('is_string($tag)'); $tag = preg_replace("/[\s?*]/", "", $tag); # whitespace $tag = preg_replace('/\x20(\x0e|\x0f)/', '', $tag); # unicode RTL $tag = preg_replace("/\.+/", ".", $tag); # strings of dots? @@ -1120,7 +1119,7 @@ class Tag { * @return array */ public static function explode($tags, $tagme=true) { - assert(is_string($tags) || is_array($tags)); + assert('is_string($tags) || is_array($tags)'); if(is_string($tags)) { $tags = explode(' ', trim($tags)); @@ -1151,7 +1150,7 @@ class Tag { * @return string */ public static function implode($tags) { - assert(is_string($tags) || is_array($tags)); + assert('is_string($tags) || is_array($tags)'); if(is_array($tags)) { sort($tags); @@ -1169,7 +1168,7 @@ class Tag { * @return string */ public static function resolve_alias($tag) { - assert(is_string($tag)); + assert('is_string($tag)'); $negative = false; if(!empty($tag) && ($tag[0] == '-')) { @@ -1224,7 +1223,7 @@ class Tag { * @return array */ public static function resolve_aliases($tags) { - assert(is_array($tags)); + assert('is_array($tags)'); $new = array(); diff --git a/core/user.class.php b/core/user.class.php index 679e0fa6..34d111aa 100644 --- a/core/user.class.php +++ b/core/user.class.php @@ -94,7 +94,7 @@ class User { * @return null|User */ public static function by_id(/*int*/ $id) { - assert(is_numeric($id)); + assert('is_numeric($id)', var_export($id, true)); global $database; if($id === 1) { $cached = $database->cache->get('user-id:'.$id); @@ -111,7 +111,7 @@ class User { * @return null|User */ public static function by_name(/*string*/ $name) { - assert(is_string($name)); + assert('is_string($name)', var_export($name, true)); global $database; $row = $database->get_row($database->scoreql_to_sql("SELECT * FROM users WHERE SCORE_STRNORM(name) = SCORE_STRNORM(:name)"), array("name"=>$name)); return is_null($row) ? null : new User($row); @@ -124,8 +124,8 @@ class User { * @return null|User */ public static function by_name_and_pass(/*string*/ $name, /*string*/ $pass) { - assert(is_string($name)); - assert(is_string($pass)); + assert('is_string($name)', var_export($name, true)); + assert('is_string($pass)', var_export($pass, true)); $user = User::by_name($name); if($user) { if($user->passhash == md5(strtolower($name) . $pass)) { @@ -143,8 +143,8 @@ class User { * @return array */ public static function by_list(/*int*/ $offset, /*int*/ $limit=50) { - assert(is_numeric($offset)); - assert(is_numeric($limit)); + assert('is_numeric($offset)', var_export($offset, true)); + assert('is_numeric($limit)', var_export($limit, true)); global $database; $rows = $database->get_all("SELECT * FROM users WHERE id >= :start AND id < :end", array("start"=>$offset, "end"=>$offset+$limit)); return array_map("_new_user", $rows); @@ -196,7 +196,7 @@ class User { * @param string $class */ public function set_class(/*string*/ $class) { - assert(is_string($class)); + assert('is_string($class)', var_export($class, true)); global $database; $database->Execute("UPDATE users SET class=:class WHERE id=:id", array("class"=>$class, "id"=>$this->id)); log_info("core-user", 'Set class for '.$this->name.' to '.$class); diff --git a/core/util.inc.php b/core/util.inc.php index 603facf4..95eb318b 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -263,6 +263,64 @@ function isValidDate($date) { return false; } +function validate_input($inputs) { + $outputs = array(); + + foreach($inputs as $key => $validations) { + $flags = explode(',', $validations); + if(in_array('optional', $flags)) { + if(!isset($_POST[$key])) { + continue; + } + } + + if(!isset($_POST[$key])) { + throw new InvalidInput("Input '$key' not set"); + } + + $value = $_POST[$key]; + + if(in_array('user_id', $flags)) { + $id = int_escape($value); + if(in_array('exists', $flags)) { + if(is_null(User::by_id($id))) { + throw new InvalidInput("User #$id does not exist"); + } + } + $outputs[$key] = $id; + } + else if(in_array('user_name', $flags)) { + if(strlen($value) < 1) { + throw new InvalidInput("Username must be at least 1 character"); + } + else if(!preg_match('/^[a-zA-Z0-9-_]+$/', $value)) { + throw new InvalidInput( + "Username contains invalid characters. Allowed characters are ". + "letters, numbers, dash, and underscore"); + } + $outputs[$key] = $value; + } + else if(in_array('user_class', $flags)) { + global $_user_classes; + if(!array_key_exists($value, $_user_classes)) { + throw new InvalidInput("Invalid user class: ".html_escape($class)); + } + $outputs[$key] = $value; + } + else if(in_array('email', $flags)) { + $outputs[$key] = $value; + } + else if(in_array('password', $flags)) { + $outputs[$key] = $value; + } + else { + throw new InvalidInput("Unknown validation '$validations'"); + } + } + + return $outputs; +} + /** * Give a HTML string which shows an IP (if the user is allowed to see IPs), * and a link to ban that IP (if the user is allowed to ban IPs) @@ -1439,6 +1497,19 @@ function get_debug_info() { return $debug; } +function score_assert_handler($file, $line, $code, $desc = null) { + $file = basename($file); + print("Assertion failed at $file:$line: $code ($desc)"); + /* + print("
");
+	debug_print_backtrace();
+	print("
"); + */ +} +//assert_options(ASSERT_ACTIVE, 1); +assert_options(ASSERT_WARNING, 0); +assert_options(ASSERT_QUIET_EVAL, 1); +assert_options(ASSERT_CALLBACK, 'score_assert_handler'); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Request initialisation stuff * diff --git a/ext/user/main.php b/ext/user/main.php index e5791f4d..a0d87426 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -174,7 +174,7 @@ class UserPage extends Extension { log_info("user", "Logged out"); $page->set_mode("redirect"); - // Try forwarding to same page on logout unless user comes from registration page + // Try forwarding to same page on logout unless user comes from registration page if ($config->get_int("user_loginshowprofile",0) == 0 && isset($_SERVER['HTTP_REFERER']) && strstr($_SERVER['HTTP_REFERER'], "post/")) @@ -190,49 +190,37 @@ class UserPage extends Extension { } else if($event->get_arg(0) == "change_name") { - if(isset($_POST['id']) && isset($_POST['name'])) { - $duser = User::by_id($_POST['id']); - if ( ! $duser instanceof User) { - throw new NullUserException("Error: the user id does not exist!"); - } - $name = $_POST['name']; - $this->change_name_wrapper($duser, $name); - } + $input = validate_input(array( + 'id' => 'user_id,exists', + 'name' => 'user_name', + )); + $duser = User::by_id($input['id']); + $this->change_name_wrapper($duser, $input['name']); } else if($event->get_arg(0) == "change_pass") { - if(isset($_POST['id']) && isset($_POST['pass1']) && isset($_POST['pass2'])) { - $duser = User::by_id($_POST['id']); - if ( ! $duser instanceof User) { - throw new NullUserException("Error: the user id does not exist!"); - } - $pass1 = $_POST['pass1']; - $pass2 = $_POST['pass2']; - $this->change_password_wrapper($duser, $pass1, $pass2); - } + $input = validate_input(array( + 'id' => 'user_id,exists', + 'pass1' => 'password', + 'pass2' => 'password', + )); + $duser = User::by_id($input['id']); + $this->change_password_wrapper($duser, $input['pass1'], $input['pass2']); } else if($event->get_arg(0) == "change_email") { - if(isset($_POST['id']) && isset($_POST['address'])) { - $duser = User::by_id($_POST['id']); - if ( ! $duser instanceof User) { - throw new NullUserException("Error: the user id does not exist!"); - } - $address = $_POST['address']; - $this->change_email_wrapper($duser, $address); - } + $input = validate_input(array( + 'id' => 'user_id,exists', + 'address' => 'email', + )); + $duser = User::by_id($input['id']); + $this->change_email_wrapper($duser, $input['address']); } else if($event->get_arg(0) == "change_class") { - global $_user_classes; - if(isset($_POST['id']) && isset($_POST['class'])) { - $duser = User::by_id($_POST['id']); - if ( ! $duser instanceof User) { - throw new NullUserException("Error: the user id does not exist!"); - } - $class = $_POST['class']; - if(!array_key_exists($class, $_user_classes)) { - throw Exception("Invalid user class: ".html_escape($class)); - } - $this->change_class_wrapper($duser, $class); - } + $input = validate_input(array( + 'id' => 'user_id,exists', + 'class' => 'user_class', + )); + $duser = User::by_id($input['id']); + $this->change_class_wrapper($duser, $input['class']); } else if($event->get_arg(0) == "delete_user") { $this->delete_user($page, isset($_POST["with_images"]), isset($_POST["with_comments"])); @@ -459,7 +447,7 @@ class UserPage extends Extension { "Username contains invalid characters. Allowed characters are ". "letters, numbers, dash, and underscore"); } - else if($database->get_row($database->scoreql_to_sql("SELECT * FROM users WHERE SCORE_STRNORM(name) = SCORE_STRNORM(:name)"), array("name"=>$name))) { + else if(User::by_name($name)) { throw new UserCreationException("That username is already taken"); } } @@ -601,12 +589,7 @@ class UserPage extends Extension { global $user; if($user->class->name == "admin") { - $duser = User::by_id($_POST['id']); - if ( ! $duser instanceof User) { - throw new NullUserException("Error: the user id does not exist!"); - } $duser->set_class($class); - flash_message("Class changed"); $this->redirect_to_user($duser); }