config = $config; } public function validate(\Szurubooru\IValidatable $validatable) { $validatable->validate($this); } public function validateNumber($subject) { if (!preg_match('/^-?[0-9]+$/', $subject)) throw new \DomainException($subject . ' does not look like a number.'); } public function validateNonEmpty($subject, $subjectName = 'Object') { if (!$subject) throw new \DomainException($subjectName . ' cannot be empty.'); } public function validateLength($subject, $minLength, $maxLength, $subjectName = 'Object') { $this->validateMinLength($subject, $minLength, $subjectName); $this->validateMaxLength($subject, $maxLength, $subjectName); } public function validateMinLength($subject, $minLength, $subjectName = 'Object') { if (strlen($subject) < $minLength) throw new \DomainException($subjectName . ' must have at least ' . $minLength . ' character(s).'); } public function validateMaxLength($subject, $maxLength, $subjectName = 'Object') { if (strlen($subject) > $maxLength) throw new \DomainException($subjectName . ' must have at most ' . $maxLength . ' character(s).'); } public function validateUserName($userName) { $minUserNameLength = intval($this->config->users->minUserNameLength); $maxUserNameLength = intval($this->config->users->maxUserNameLength); $this->validateNonEmpty($userName, 'User name'); $this->validateLength($userName, $minUserNameLength, $maxUserNameLength, 'User name'); if (preg_match('/[^a-zA-Z0-9_-]/', $userName)) { throw new \DomainException('User name may contain only characters, numbers, underscore (_) and dash (-).'); } } public function validateEmail($email) { if (!$email) return; if (!preg_match('/^[^@]+@[^@]+\.\w+$/', $email)) throw new \DomainException('Specified e-mail appears to be invalid.'); } public function validatePassword($password) { $minPasswordLength = intval($this->config->security->minPasswordLength); $this->validateNonEmpty($password, 'Password'); $this->validateMinLength($password, $minPasswordLength, 'Password'); if (preg_match('/[^\x20-\x7f]/', $password)) { throw new \DomainException( 'Password may contain only characters from ASCII range to avoid potential problems with encoding.'); } } public function validatePostTags($tags) { if (empty($tags)) throw new \DomainException('Tags cannot be empty.'); //<> causes HTML injection and problems with Markdown. //\/ causes problems with URLs. //; causes problems with search argument parsing in JS frontend. //whitespace causes problems with search. $illegalCharacters = str_split("<>;\\/\r\n\t " . chr(160)); foreach ($tags as $tag) { if (empty($tag)) throw new \DomainException('Tags cannot be empty.'); //: causes problems with complex search (e.g. id:5). if (strpos($tag, ':') > 0) throw new \DomainException('Colon in tag may appear only at the beginning.'); $this->validateMaxLength($tag, 64, 'Tag'); foreach ($illegalCharacters as $char) { if (strpos($tag, $char) !== false) { throw new \DomainException( sprintf('Tags cannot contain any of following characters: %s.', implode(', ', array_map(function($char) { if ($char === "\n") return "new line"; if ($char === "\r") return "carriage return"; if ($char === "\t") return "tab"; if ($char === " ") return "space"; if ($char === chr(160)) return "hard space"; return $char; }, $illegalCharacters)))); } } } } public function validatePostSource($source) { $this->validateMaxLength($source, 200, 'Source'); } public function validateToken($token) { $this->validateNonEmpty($token, 'Token'); } }