Ran PHPStan over everything and attempted some fixes.

This commit is contained in:
flash 2022-02-19 19:03:00 +00:00
parent 3a118fef15
commit d55585372e
49 changed files with 115 additions and 195 deletions

View file

@ -1,104 +0,0 @@
Misuzu.UserRelations = {};
Misuzu.UserRelations.Type = DefineEnum({ none: 0, follow: 1, });
Misuzu.UserRelations.init = function() {
var buttons = document.getElementsByClassName('js-user-relation-action');
for(var i = 0; i < buttons.length; ++i) {
switch(buttons[i].tagName.toLowerCase()) {
case 'a':
buttons[i].removeAttribute('href');
buttons[i].removeAttribute('target');
buttons[i].removeAttribute('rel');
break;
}
buttons[i].addEventListener('click', Misuzu.UserRelations.setRelationHandler);
}
};
Misuzu.UserRelations.setRelation = function(user, type, onSuccess, onFailure) {
var xhr = new XMLHttpRequest;
xhr.addEventListener('readystatechange', function() {
if(xhr.readyState !== 4)
return;
Misuzu.CSRF.setToken(xhr.getResponseHeader('X-Misuzu-CSRF'));
var json = JSON.parse(xhr.responseText),
message = json.error || json.message;
if(message && onFailure)
onFailure(message);
else if(!message && onSuccess)
onSuccess(json);
});
xhr.open('GET', Misuzu.Urls.format('user-relation-create', [Misuzu.Urls.v('user', user), Misuzu.Urls.v('type', type)]));
xhr.setRequestHeader('X-Misuzu-XHR', 'user_relation');
xhr.setRequestHeader('X-Misuzu-CSRF', Misuzu.CSRF.getToken());
xhr.send();
};
Misuzu.UserRelations.ICO_ADD = 'fas fa-user-plus';
Misuzu.UserRelations.ICO_REM = 'fas fa-user-minus';
Misuzu.UserRelations.ICO_BUS = 'fas fa-spinner fa-pulse';
Misuzu.UserRelations.BTN_BUS = 'input__button--busy';
Misuzu.UserRelations.setRelationHandler = function(ev) {
var target = this,
userId = parseInt(target.dataset.relationUser),
relationType = parseInt(target.dataset.relationType),
isButton = target.classList.contains('input__button'),
icon = target.querySelector('[class^="fa"]');
if(isButton) {
if(target.classList.contains(Misuzu.UserRelations.BTN_BUS))
return;
target.classList.add(Misuzu.UserRelations.BTN_BUS);
}
if(icon)
icon.className = Misuzu.UserRelations.ICO_BUS;
Misuzu.UserRelations.setRelation(
userId,
relationType,
function(info) {
target.classList.remove(Misuzu.UserRelations.BTN_BUS);
switch(info.relation_type) {
case Misuzu.UserRelations.Type.none:
if(isButton) {
if(target.classList.contains('input__button--destroy'))
target.classList.remove('input__button--destroy');
target.textContent = 'Follow';
}
if(icon) {
icon.className = Misuzu.UserRelations.ICO_ADD;
target.title = 'Follow';
}
target.dataset.relationType = Misuzu.UserRelations.Type.follow.toString();
break;
case Misuzu.UserRelations.Type.follow:
if(isButton) {
if(!target.classList.contains('input__button--destroy'))
target.classList.add('input__button--destroy');
target.textContent = 'Unfollow';
}
if(icon) {
icon.className = Misuzu.UserRelations.ICO_REM;
target.title = 'Unfollow';
}
target.dataset.relationType = Misuzu.UserRelations.Type.none.toString();
break;
}
},
function(msg) {
target.classList.remove(Misuzu.UserRelations.BTN_BUS);
Misuzu.showMessageBox(msg);
}
);
};

View file

@ -242,7 +242,7 @@ if(parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) !== '/index.php')
if(!empty($userInfo))
Template::set('current_user', $userInfo);
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
$inManageMode = str_starts_with($_SERVER['REQUEST_URI'], '/manage');
$hasManageAccess = User::hasCurrent()
&& !User::getCurrent()->hasActiveWarning()
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);

6
phpstan.neon Normal file
View file

@ -0,0 +1,6 @@
parameters:
level: 5
paths:
- src
bootstrapFiles:
- misuzu.php

View file

@ -149,7 +149,7 @@ class AuditLog {
public static function create(string $action, array $params = [], ?User $user = null, ?string $remoteAddr = null): void {
$user = $user ?? User::getCurrent();
$remoteAddr = $ipAddress ?? IPAddress::remote();
$remoteAddr = $remoteAddr ?? IPAddress::remote();
$createLog = DB::prepare(
'INSERT INTO `' . DB::PREFIX . self::TABLE . '` (`log_action`, `user_id`, `log_params`, `log_ip`, `log_country`)'
. ' VALUES (:action, :user, :params, INET6_ATON(:ip), :country)'
@ -162,7 +162,7 @@ class AuditLog {
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countAll(?User $user = null): int {
$getCount = DB::prepare(

View file

@ -65,7 +65,7 @@ class AuthToken {
}
public static function unpack(string $data, bool $base64 = true): self {
$obj = new static;
$obj = new AuthToken;
if(empty($data))
return $obj;
@ -83,7 +83,7 @@ class AuthToken {
}
public static function create(User $user, UserSession $session): self {
return (new static)
return (new AuthToken)
->setUser($user)
->setSession($session);
}

View file

@ -183,7 +183,7 @@ class ChangelogChange implements JsonSerializable {
return [
'id' => $this->getId(),
'user' => $this->getUserId(),
'action' => $this->getActionId(),
'action' => $this->getAction(),
'header' => $this->getHeader(),
'body' => $this->getBody(),
'comments' => $this->getCommentsCategoryName(),

View file

@ -78,7 +78,7 @@ class ChangelogChangeTag implements JsonSerializable {
private static function byQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf(self::SELECT, self::TABLE));
}
public static function byExact(ChangelogChange $change, ChangelogTag $tag): array {
public static function byExact(ChangelogChange $change, ChangelogTag $tag): self {
$tag = DB::prepare(self::byQueryBase() . ' WHERE `tag_id` = :tag')
->bind('change', $change->getId())
->bind('tag', $tag->getId())

View file

@ -18,14 +18,14 @@ class Colour {
}
public static function none(): self {
return new static(self::FLAG_INHERIT);
return new Colour(self::FLAG_INHERIT);
}
public static function fromRgb(int $red, int $green, int $blue): self {
return (new static)->setRed($red)->setGreen($green)->setBlue($blue);
return (new Colour)->setRed($red)->setGreen($green)->setBlue($blue);
}
public static function fromHex(string $hex): self {
return (new static)->setHex($hex);
return (new Colour)->setHex($hex);
}
public function getRaw(): int {
@ -99,7 +99,7 @@ class Colour {
return $this;
}
public function getLuminance(): int {
public function getLuminance(): float {
return self::LUMINANCE_WEIGHT_RED * $this->getRed()
+ self::LUMINANCE_WEIGHT_GREEN * $this->getGreen()
+ self::LUMINANCE_WEIGHT_BLUE * $this->getBlue();

View file

@ -128,7 +128,7 @@ class CommentsVote implements JsonSerializable {
}
private static function fake(CommentsPost $post, User $user, int $vote): CommentsVote {
$fake = new static;
$fake = new CommentsVote;
$fake->comment_id = $post->getId();
$fake->comment = $post;
$fake->user_id = $user->getId();

View file

@ -4,6 +4,14 @@ namespace Misuzu;
use PDO;
use Misuzu\Database\Database;
/**
* @method static PDO getPDO()
* @method static int queries()
* @method static int exec(string $stmt)
* @method static \Misuzu\Database\DatabaseStatement prepare(string $stmt, array $options = [])
* @method static \Misuzu\Database\DatabaseStatement query(string $stmt, ?int $fetchMode = null, ...$args)
* @method static int lastId()
*/
final class DB {
private static $instance;

View file

@ -1,7 +1,14 @@
<?php
namespace Misuzu;
use InvalidArgumentException;
final class Emoticon {
private int $emote_id;
private int $emote_order;
private int $emote_hierarchy;
private string $emote_url;
public const ALL = PHP_INT_MAX;
public function __construct() {
@ -132,7 +139,7 @@ final class Emoticon {
public static function byId(int $emoteId): self {
if($emoteId < 1)
return [];
throw new InvalidArgumentException('$emoteId is not a valid emoticon id.');
$getEmote = DB::prepare('
SELECT `emote_id`, `emote_order`, `emote_hierarchy`, `emote_url`

View file

@ -70,8 +70,6 @@ class Feed {
return count($this->feedItems) > 0;
}
public function addItem(FeedItem $item): self {
if($item === null)
throw new InvalidArgumentException('item may not be null');
$this->feedItems[] = $item;
return $this;
}

View file

@ -238,9 +238,8 @@ function forum_get_child_ids(int $forumId): array {
}
function forum_topics_unread(int $forumId, int $userId): int {
if($userId < 1 || $forumId < 1) {
return false;
}
if($userId < 1 || $forumId < 1)
return 0;
static $memoized = [];
$memoId = "{$forumId}-{$userId}";

View file

@ -308,7 +308,7 @@ function forum_post_can_delete($postId, ?int $userId = null): int {
return MSZ_E_FORUM_POST_DELETE_OWNER;
}
if(strtotime($post['post_created']) <= time() - MSZ_FORUM_POST_DELETE_LIMIT) {
if(strtotime($post['post_created']) <= (time() - MSZ_FORUM_POST_DELETE_LIMIT)) {
return MSZ_E_FORUM_POST_DELETE_OLD;
}
}

View file

@ -575,7 +575,7 @@ function forum_topic_can_delete($topicId, ?int $userId = null): int {
return MSZ_E_FORUM_TOPIC_DELETE_OWNER;
}
if(strtotime($topic['topic_created']) <= time() - MSZ_FORUM_TOPIC_DELETE_TIME_LIMIT) {
if(strtotime($topic['topic_created']) <= (time() - MSZ_FORUM_TOPIC_DELETE_TIME_LIMIT)) {
return MSZ_E_FORUM_TOPIC_DELETE_OLD;
}

View file

@ -26,7 +26,7 @@ class ChangelogHandler extends Handler {
if($filterDate !== null)
try {
$dateParts = explode('-', $filterDate, 3);
$filterDate = gmmktime(12, 0, 0, $dateParts[1], $dateParts[2], $dateParts[0]);
$filterDate = gmmktime(12, 0, 0, intval($dateParts[1]), intval($dateParts[2]), intval($dateParts[0]));
} catch(ErrorException $ex) {
return 404;
}

View file

@ -11,7 +11,7 @@ final class ForumHandler extends Handler {
$forumId = (int)$request->getQueryParam('forum', FILTER_SANITIZE_NUMBER_INT);
$response->setTemplate('confirm', [
'title' => 'Mark forum as read',
'message' => 'Are you sure you want to mark ' . ($forumId === null ? 'the entire' : 'this') . ' forum as read?',
'message' => 'Are you sure you want to mark ' . ($forumId === 0 ? 'the entire' : 'this') . ' forum as read?',
'return' => url($forumId ? 'forum-category' : 'forum-index', ['forum' => $forumId]),
'params' => [
'forum' => $forumId,

View file

@ -20,7 +20,7 @@ final class InfoHandler extends Handler {
'title' => '',
];
$isMisuzuDoc = $name === 'misuzu' || starts_with($name, 'misuzu/');
$isMisuzuDoc = $name === 'misuzu' || str_starts_with($name, 'misuzu/');
if($isMisuzuDoc) {
$filename = substr($name, 7);
@ -41,8 +41,8 @@ final class InfoHandler extends Handler {
if(empty($document['content']))
return 404;
if(empty($document['title'])) {
if(starts_with($document['content'], '# ')) {
if($document['title'] === '') {
if(str_starts_with($document['content'], '# ')) {
$titleOffset = strpos($document['content'], "\n");
$document['title'] = trim(substr($document['content'], 2, $titleOffset - 1));
$document['content'] = substr($document['content'], $titleOffset);

View file

@ -13,7 +13,7 @@ use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\News\NewsCategory;
use Misuzu\News\NewsPost;
use Misuzu\News\NewsCategoryNotFoundException;
use Misuzu\News\NewsPostNotException;
use Misuzu\News\NewsPostNotFoundException;
use Misuzu\Parsers\Parser;
use Misuzu\Users\User;

View file

@ -67,12 +67,14 @@ final class SockChatHandler extends Handler {
$body = $request->getParsedBody();
if(isset($body['bump'], $body['hash']) && is_string($body['bump']) && is_string($body['hash']))
return $this->bump(
if(isset($body['bump'], $body['hash']) && is_string($body['bump']) && is_string($body['hash'])) {
$this->bump(
$response,
$request->setHeader('X-SharpChat-Signature', $body['hash'])
->setBody(Stream::create($body['bump']))
);
return;
}
$source = isset($body['user_id']) ? $body : $query;
@ -381,9 +383,10 @@ final class SockChatHandler extends Handler {
$userInfo = User::byUsername($param);
break;
}
} catch(UserNotFoundException $ex) {
} catch(UserNotFoundException $ex) {}
if(!isset($userInfo))
return [];
}
return [
'user_id' => $userInfo->getId(),

View file

@ -16,7 +16,7 @@ class AcceptHttpHeaderChild implements HasQualityInterface {
if(isset($parts[1])) {
$split = explode('=', $parts[1], 2);
if($split[0] === 'q' && isset($split[1]))
$this->quality = max(min(round(filter_var($split[1], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) ?? 1, 2), 1), 0);
$this->quality = max(min(round((float)filter_var($split[1], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION), 2), 1), 0);
}
}

View file

@ -52,7 +52,7 @@ class HttpHeader {
case 'TE':
return new AcceptHttpHeader($name, $line);
default:
return new static($name, $line);
return new HttpHeader($name, $line);
}
}
}

View file

@ -190,7 +190,7 @@ class HttpRequestMessage extends HttpMessage {
}
}
if(!isset($headers['Authorization'])) {
if(empty($headers['Authorization'])) {
if(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
$headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
} elseif(isset($_SERVER['PHP_AUTH_USER'])) {

View file

@ -131,7 +131,6 @@ class HttpResponseMessage extends HttpMessage {
414 => 'URI Too Long',
416 => 'Range Not Satisfiable',
417 => 'Expectation Failed',
417 => 'Expectation Failed',
418 => 'I\'m a teapot',
421 => 'Misdirected Request',
422 => 'Unprocessable Entity',

View file

@ -23,7 +23,7 @@ class Route {
}
public static function create(array $methods, string $path, ?string $method = null, ?string $class = null): self {
return new static($methods, $path, $method, $class);
return new Route($methods, $path, $method, $class);
}
public static function get(string $path, ?string $method = null, ?string $class = null): self {
return self::create(['GET'], $path, $method, $class);

View file

@ -21,7 +21,7 @@ class Router {
if($name[0] === '_')
return null;
if(self::$instance === null)
(new static)->setInstance();
(new Router)->setInstance();
return self::$instance->{'_' . $name}(...$args);
}
@ -92,7 +92,7 @@ class Router {
$handlerMethod = $route->getHandlerMethod();
if(is_callable($handlerMethod)) {
$result = call_user_func_array($handlerMethod, $args);
$result = call_user_func_array($handlerMethod, $matches);
} elseif($handlerMethod[0] === '/') {
$response->redirect($handlerMethod);
} else {

View file

@ -38,7 +38,7 @@ class UploadedFile {
$this->stream = $fileNameOrStream;
if($size === null && $this->stream !== null)
$this->size = $stream->getSize();
$this->size = $this->stream->getSize();
}
}
@ -47,7 +47,7 @@ class UploadedFile {
throw new RuntimeException('Can\'t open stream because of an upload error.');
if($this->hasMoved)
throw new RuntimeException('Can\'t open stream because file has already been moved.');
if($this->steam === null)
if($this->stream === null)
$this->stream = Stream::createFromFile($this->fileName);
return $this->stream;
@ -97,7 +97,7 @@ class UploadedFile {
}
public static function createFromFILE(array $file): self {
return new static(
return new UploadedFile(
$file['tmp_name'] ?? '',
$file['error'] ?? UPLOAD_ERR_NO_FILE,
$file['size'] ?? null,

View file

@ -26,7 +26,7 @@ final class GdImage extends Image {
];
public function __construct($pathOrWidth, int $height = -1) {
parent::__construct($pathOrWidth, $height);
parent::__construct($pathOrWidth);
if(is_int($pathOrWidth)) {
$this->gd = imagecreatetruecolor($pathOrWidth, $height < 1 ? $pathOrWidth : $height);

View file

@ -5,7 +5,7 @@ use InvalidArgumentException;
use UnexpectedValueException;
abstract class Image {
public function __construct($pathOrWidth, int $height = -1) {
public function __construct($pathOrWidth) {
if(!is_int($pathOrWidth) && !is_string($pathOrWidth))
throw new InvalidArgumentException('The first argument must be or type string to open an image file, or int to set a width for a new image.');
}

View file

@ -8,12 +8,12 @@ final class ImagickImage extends Image {
private ?Imagick $imagick = null;
public function __construct($pathOrWidth, int $height = -1) {
parent::__construct($pathOrWidth, $height);
parent::__construct($pathOrWidth);
if(is_int($pathOrWidth)) {
$this->imagick = new Imagick();
$this->newImage($pathOrWidth, $height < 1 ? $pathOrWidth : $height, 'none');
$this->setImageFormat('png');
$this->imagick->newImage($pathOrWidth, $height < 1 ? $pathOrWidth : $height, 'none');
$this->imagick->setImageFormat('png');
} elseif(is_string($pathOrWidth)) {
$imagick = new Imagick($pathOrWidth);
$imagick->setImageFormat($imagick->getNumberImages() > 1 ? 'gif' : 'png');

View file

@ -14,6 +14,9 @@ final class Mailer {
private static $dsn = 'null://null';
private static $transport = null;
private static string $senderName = 'Flashii';
private static string $senderAddr = 'sys@flashii.net';
public static function init(string $method, array $config): void {
if($method !== 'smtp') {
self::$dsn = 'null://null';
@ -42,6 +45,12 @@ final class Mailer {
$dsn .= $config['port'] ?? 25;
self::$dsn = $dsn;
if(!empty($config['sender_name']))
self::$senderName = $config['sender_name'];
if(!empty($config['sender_addr']))
self::$senderAddr = $config['sender_addr'];
}
public static function getTransport() {
@ -59,8 +68,8 @@ final class Mailer {
$message = new SymfonyMessage;
$message->from(new SymfonyAddress(
$config['sender_addr'] ?? 'sys@flashii.net',
$config['sender_name'] ?? 'Flashii'
self::$senderAddr,
self::$senderName
));
if($bcc)

View file

@ -68,7 +68,7 @@ class MediaType implements HasQualityInterface {
}
public function matchPattern(string $pattern): bool {
try {
$mediaType = new static($pattern);
$mediaType = new MediaType($pattern);
} catch(InvalidArgumentException $ex) {
return false;
}

View file

@ -27,7 +27,7 @@ final class Pagination {
}
public function getPages(): int {
return ceil($this->getCount() / $this->getRange());
return (int)ceil($this->getCount() / $this->getRange());
}
public function hasValidOffset(): bool {
@ -50,7 +50,7 @@ final class Pagination {
if($this->getOffset() < 1)
return self::START_PAGE;
return floor($this->getOffset() / $this->getRange()) + self::START_PAGE;
return (int)floor($this->getOffset() / $this->getRange()) + self::START_PAGE;
}
public function setPage(int $page, bool $zeroBased = false): self {
@ -70,7 +70,7 @@ final class Pagination {
$source ??= $_GET;
if(isset($source[$name]) && is_string($source[$name]) && ctype_digit($source[$name]))
return $source[$name];
return intval($source[$name]);
return $default;
}

View file

@ -47,7 +47,7 @@ class Stream {
if($contents instanceof Stream)
return $contents;
return new static($contents);
return new Stream($contents);
}
public static function createFromFile(string $filename, string $mode = 'rb'): Stream {
if(!in_array($mode[0], ['r', 'w', 'a', 'x', 'c']))
@ -79,9 +79,9 @@ class Stream {
return $this->readable;
}
public function read($length): int {
public function read($length): string {
if(!$this->isReadable())
throw RuntimeException('Can\'t read from this stream.');
throw new RuntimeException('Can\'t read from this stream.');
return fread($this->stream, $length);
}

View file

@ -32,6 +32,6 @@ class TOTP {
$bin |= (ord($hash[$offset + 3]) & 0xFF);
$otp = $bin % pow(10, self::DIGITS);
return str_pad($otp, self::DIGITS, STR_PAD_LEFT);
return str_pad(strval($otp), self::DIGITS, '0', STR_PAD_LEFT);
}
}

View file

@ -34,7 +34,7 @@ final class Template {
define('MSZ_TPL_RENDER', microtime(true));
}
if(!ends_with($file, self::FILE_EXT)) {
if(!str_ends_with($file, self::FILE_EXT)) {
$file = str_replace('.', DIRECTORY_SEPARATOR, $file) . self::FILE_EXT;
}

View file

@ -57,7 +57,7 @@ class UserAvatarAsset extends UserImageAsset implements UserAssetScalableInterfa
}
public function getScaledFileExtension(int $dims): string {
$imageSize = getimagesize($this->getScaledPath($dims));
if($imageSize === null)
if($imageSize === false)
return 'img';
return self::TYPES_EXT[$imageSize[2]] ?? 'img';
}

View file

@ -94,7 +94,7 @@ class UserBackgroundAsset extends UserImageAsset {
return $this;
}
public function isBlend(): bool {
return $this->getAttributes() & self::ATTRIB_BLEND;
return ($this->getAttributes() & self::ATTRIB_BLEND) > 0;
}
public function setBlend(bool $blend): self {
$this->getUser()->setBackgroundSettings(
@ -105,7 +105,7 @@ class UserBackgroundAsset extends UserImageAsset {
return $this;
}
public function isSlide(): bool {
return $this->getAttributes() & self::ATTRIB_SLIDE;
return ($this->getAttributes() & self::ATTRIB_SLIDE) > 0;
}
public function setSlide(bool $slide): self {
$this->getUser()->setBackgroundSettings(

View file

@ -120,7 +120,7 @@ abstract class UserImageAsset implements JsonSerializable, UserImageAssetInterfa
public function setFromData(string $data): void {
$file = tempnam(sys_get_temp_dir(), 'msz');
if($file === null || !is_file($file))
if($file === false || !is_file($file))
throw new UserImageAssetFileCreationFailedException;
chmod($file, 0664);
file_put_contents($file, $data);

View file

@ -790,7 +790,7 @@ class User implements HasRankInterface, JsonSerializable {
************/
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countAll(bool $showDeleted = false): int {
return (int)DB::prepare(

View file

@ -93,7 +93,7 @@ class UserLoginAttempt {
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countAll(?User $user = null): int {
$getCount = DB::prepare(

View file

@ -83,7 +83,7 @@ class UserRole implements ArrayAccess, HasRankInterface {
public function getCanLeave(): bool {
return boolval($this->role_can_leave);
}
public function setCanLeave(bool $canLeave): bool {
public function setCanLeave(bool $canLeave): self {
$this->role_can_leave = $canLeave ? 1 : 0;
return $this;
}
@ -159,7 +159,7 @@ class UserRole implements ArrayAccess, HasRankInterface {
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countAll(bool $showHidden = false): int {
return (int)DB::prepare(

View file

@ -60,7 +60,7 @@ class UserRoleRelation {
->execute();
// data is predictable, just create a "fake"
$object = new static;
$object = new UserRoleRelation;
$object->user = $user;
$object->user_id = $user->getId();
$object->role = $role;
@ -69,7 +69,7 @@ class UserRoleRelation {
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countUsers(UserRole $role): int {
return (int)DB::prepare(self::countQueryBase() . ' WHERE `role_id` = :role')

View file

@ -199,7 +199,7 @@ class UserSession {
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countAll(?User $user = null): int {
$getCount = DB::prepare(

View file

@ -197,7 +197,7 @@ class UserWarning {
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
return sprintf(self::QUERY_SELECT, 'COUNT(*)');
}
public static function countByRemoteAddress(?string $address = null, bool $withDuration = true): int {
$address = $address ?? IPAddress::remote();

View file

@ -86,6 +86,7 @@ final class Zalgo {
continue;
$str .= $char;
$num_up = $num_mid = $num_down = 0;
switch($mode) {
case self::MODE_MINI:

View file

@ -74,17 +74,15 @@ function perms_get_key(string $prefix, string $suffix): string {
function perms_get_select(array $modes = MSZ_PERM_MODES, string $allow = MSZ_PERMS_ALLOW, string $deny = MSZ_PERMS_DENY): string {
$select = '';
if(empty($select)) {
foreach($modes as $mode) {
$select .= sprintf(
'(BIT_OR(`%1$s_perms_%2$s`) &~ BIT_OR(`%1$s_perms_%3$s`)) AS `%1$s`,',
$mode, $allow, $deny
);
}
$select = substr($select, 0, -1);
foreach($modes as $mode) {
$select .= sprintf(
'(BIT_OR(`%1$s_perms_%2$s`) &~ BIT_OR(`%1$s_perms_%3$s`)) AS `%1$s`,',
$mode, $allow, $deny
);
}
$select = substr($select, 0, -1);
return $select;
}

View file

@ -132,7 +132,7 @@ function url(string $name, array $variables = []): string {
$info = MSZ_URLS[$name];
if(!is_string($info[0] ?? null)) {
if(!isset($info[0]) || !is_string($info[0])) {
return '';
}
@ -175,13 +175,13 @@ function url_redirect(string $name, array $variables = []): void {
}
function url_variable(string $value, array $variables): string {
if(starts_with($value, '<') && ends_with($value, '>'))
if(str_starts_with($value, '<') && str_ends_with($value, '>'))
return $variables[trim($value, '<>')] ?? '';
if(starts_with($value, '[') && ends_with($value, ']'))
if(str_starts_with($value, '[') && str_ends_with($value, ']'))
return constant(trim($value, '[]'));
if(starts_with($value, '{') && ends_with($value, '}'))
if(str_starts_with($value, '{') && str_ends_with($value, '}'))
return \Misuzu\CSRF::token();
// Hack that allows variables with file extensions
@ -201,7 +201,7 @@ function url_list(): array {
$collection = [];
foreach(MSZ_URLS as $name => $urlInfo) {
if(empty($hasManageAccess) && starts_with($name, 'manage-'))
if(empty($hasManageAccess) && str_starts_with($name, 'manage-'))
continue;
$item = [
@ -271,5 +271,5 @@ function is_local_url(string $url): bool {
if($url[0] === '/' && ($length > 1 ? $url[1] !== '/' : true))
return true;
return starts_with($url, url_prefix());
return str_starts_with($url, url_prefix());
}

View file

@ -33,16 +33,12 @@ function clamp($num, int $min, int $max): int {
return max($min, min($max, intval($num)));
}
function starts_with(string $string, string $text, bool $multibyte = true): bool {
$strlen = $multibyte ? 'mb_strlen' : 'strlen';
$substr = $multibyte ? 'mb_substr' : 'substr';
return $substr($string, 0, $strlen($text)) === $text;
function starts_with(string $string, string $text): bool {
return str_starts_with($string, $text);
}
function ends_with(string $string, string $text, bool $multibyte = true): bool {
$strlen = $multibyte ? 'mb_strlen' : 'strlen';
$substr = $multibyte ? 'mb_substr' : 'substr';
return $substr($string, 0 - $strlen($text)) === $text;
function ends_with(string $string, string $text): bool {
return str_ends_with($string, $text);
}
function first_paragraph(string $text, string $delimiter = "\n"): string {