[tests] more strictness
This commit is contained in:
parent
b60c3fe362
commit
8b797a9a31
28 changed files with 143 additions and 115 deletions
|
@ -308,7 +308,7 @@ class BasePage
|
||||||
assert($this->file, "file should not be null with PageMode::FILE");
|
assert($this->file, "file should not be null with PageMode::FILE");
|
||||||
|
|
||||||
// https://gist.github.com/codler/3906826
|
// https://gist.github.com/codler/3906826
|
||||||
$size = filesize($this->file); // File size
|
$size = false_throws(filesize($this->file)); // File size
|
||||||
$length = $size; // Content length
|
$length = $size; // Content length
|
||||||
$start = 0; // Start byte
|
$start = 0; // Start byte
|
||||||
$end = $size - 1; // End byte
|
$end = $size - 1; // End byte
|
||||||
|
@ -420,7 +420,7 @@ class BasePage
|
||||||
if (!file_exists($css_cache_file)) {
|
if (!file_exists($css_cache_file)) {
|
||||||
$mcss = new \MicroBundler\MicroBundler();
|
$mcss = new \MicroBundler\MicroBundler();
|
||||||
foreach($css_files as $css) {
|
foreach($css_files as $css) {
|
||||||
$mcss->addSource($css, file_get_contents($css));
|
$mcss->addSource($css);
|
||||||
}
|
}
|
||||||
$mcss->save($css_cache_file);
|
$mcss->save($css_cache_file);
|
||||||
}
|
}
|
||||||
|
@ -443,7 +443,7 @@ class BasePage
|
||||||
if (!file_exists($js_cache_file)) {
|
if (!file_exists($js_cache_file)) {
|
||||||
$mcss = new \MicroBundler\MicroBundler();
|
$mcss = new \MicroBundler\MicroBundler();
|
||||||
foreach($js_files as $js) {
|
foreach($js_files as $js) {
|
||||||
$mcss->addSource($js, file_get_contents($js));
|
$mcss->addSource($js);
|
||||||
}
|
}
|
||||||
$mcss->save($js_cache_file);
|
$mcss->save($js_cache_file);
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,7 @@ class BasePage
|
||||||
if (!file_exists($js_cache_file)) {
|
if (!file_exists($js_cache_file)) {
|
||||||
$mcss = new \MicroBundler\MicroBundler();
|
$mcss = new \MicroBundler\MicroBundler();
|
||||||
foreach($js_files as $js) {
|
foreach($js_files as $js) {
|
||||||
$mcss->addSource($js, file_get_contents($js));
|
$mcss->addSource($js);
|
||||||
}
|
}
|
||||||
$mcss->save($js_cache_file);
|
$mcss->save($js_cache_file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ class EventTracingCache implements CacheInterface
|
||||||
/**
|
/**
|
||||||
* @param string[] $keys
|
* @param string[] $keys
|
||||||
* @param mixed $default
|
* @param mixed $default
|
||||||
* @return mixed[]
|
* @return iterable<mixed>
|
||||||
*/
|
*/
|
||||||
public function getMultiple($keys, $default = null)
|
public function getMultiple($keys, $default = null)
|
||||||
{
|
{
|
||||||
|
@ -126,10 +126,10 @@ function loadCache(?string $dsn): CacheInterface
|
||||||
} elseif ($url['scheme'] == "redis") {
|
} elseif ($url['scheme'] == "redis") {
|
||||||
$redis = new \Predis\Client([
|
$redis = new \Predis\Client([
|
||||||
'scheme' => 'tcp',
|
'scheme' => 'tcp',
|
||||||
'host' => $url['host'],
|
'host' => $url['host'] ?? "127.0.0.1",
|
||||||
'port' => $url['port'],
|
'port' => $url['port'] ?? 6379,
|
||||||
'username' => $url['user'],
|
'username' => $url['user'] ?? null,
|
||||||
'password' => $url['pass'],
|
'password' => $url['pass'] ?? null,
|
||||||
], ['prefix' => 'shm:']);
|
], ['prefix' => 'shm:']);
|
||||||
$c = new \Naroga\RedisCache\Redis($redis);
|
$c = new \Naroga\RedisCache\Redis($redis);
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,11 @@ class Database
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @param callable():T $callback
|
||||||
|
* @return T
|
||||||
|
*/
|
||||||
public function with_savepoint(callable $callback, string $name = "sp"): mixed
|
public function with_savepoint(callable $callback, string $name = "sp"): mixed
|
||||||
{
|
{
|
||||||
global $_tracer;
|
global $_tracer;
|
||||||
|
|
|
@ -72,7 +72,7 @@ class MySQL extends DBEngine
|
||||||
|
|
||||||
public function get_version(PDO $db): string
|
public function get_version(PDO $db): string
|
||||||
{
|
{
|
||||||
return $db->query('select version()')->fetch()[0];
|
return false_throws($db->query('select version()'))->fetch()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,14 +124,14 @@ class PostgreSQL extends DBEngine
|
||||||
|
|
||||||
public function get_version(PDO $db): string
|
public function get_version(PDO $db): string
|
||||||
{
|
{
|
||||||
return $db->query('select version()')->fetch()[0];
|
return false_throws($db->query('select version()'))->fetch()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shimmie functions for export to sqlite
|
// shimmie functions for export to sqlite
|
||||||
function _unix_timestamp(string $date): int
|
function _unix_timestamp(string $date): int
|
||||||
{
|
{
|
||||||
return strtotime($date);
|
return false_throws(strtotime($date));
|
||||||
}
|
}
|
||||||
function _now(): string
|
function _now(): string
|
||||||
{
|
{
|
||||||
|
@ -231,6 +231,6 @@ class SQLite extends DBEngine
|
||||||
|
|
||||||
public function get_version(PDO $db): string
|
public function get_version(PDO $db): string
|
||||||
{
|
{
|
||||||
return $db->query('select sqlite_version()')->fetch()[0];
|
return false_throws($db->query('select sqlite_version()'))->fetch()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,13 @@ abstract class Extension
|
||||||
$normal = "Shimmie2\\{$base}Theme";
|
$normal = "Shimmie2\\{$base}Theme";
|
||||||
|
|
||||||
if (class_exists($custom)) {
|
if (class_exists($custom)) {
|
||||||
return new $custom();
|
$c = new $custom();
|
||||||
|
assert(is_a($c, Themelet::class));
|
||||||
|
return $c;
|
||||||
} elseif (class_exists($normal)) {
|
} elseif (class_exists($normal)) {
|
||||||
return new $normal();
|
$n = new $normal();
|
||||||
|
assert(is_a($n, Themelet::class));
|
||||||
|
return $n;
|
||||||
} else {
|
} else {
|
||||||
return new Themelet();
|
return new Themelet();
|
||||||
}
|
}
|
||||||
|
@ -266,6 +270,7 @@ abstract class ExtensionInfo
|
||||||
{
|
{
|
||||||
foreach (get_subclasses_of(ExtensionInfo::class) as $class) {
|
foreach (get_subclasses_of(ExtensionInfo::class) as $class) {
|
||||||
$extension_info = new $class();
|
$extension_info = new $class();
|
||||||
|
assert(is_a($extension_info, ExtensionInfo::class));
|
||||||
if (array_key_exists($extension_info->key, self::$all_info_by_key)) {
|
if (array_key_exists($extension_info->key, self::$all_info_by_key)) {
|
||||||
throw new SCoreException("Extension Info $class with key $extension_info->key has already been loaded");
|
throw new SCoreException("Extension Info $class with key $extension_info->key has already been loaded");
|
||||||
}
|
}
|
||||||
|
@ -317,7 +322,7 @@ abstract class DataHandlerExtension extends Extension
|
||||||
throw new UploadException("Invalid or corrupted file");
|
throw new UploadException("Invalid or corrupted file");
|
||||||
}
|
}
|
||||||
|
|
||||||
$existing = Image::by_hash(md5_file($event->tmpname));
|
$existing = Image::by_hash(false_throws(md5_file($event->tmpname)));
|
||||||
if (!is_null($existing)) {
|
if (!is_null($existing)) {
|
||||||
if ($config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER) == ImageConfig::COLLISION_MERGE) {
|
if ($config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER) == ImageConfig::COLLISION_MERGE) {
|
||||||
// Right now tags are the only thing that get merged, so
|
// Right now tags are the only thing that get merged, so
|
||||||
|
@ -338,8 +343,8 @@ abstract class DataHandlerExtension extends Extension
|
||||||
assert(is_readable($filename));
|
assert(is_readable($filename));
|
||||||
$image = new Image();
|
$image = new Image();
|
||||||
$image->tmp_file = $filename;
|
$image->tmp_file = $filename;
|
||||||
$image->filesize = filesize($filename);
|
$image->filesize = false_throws(filesize($filename));
|
||||||
$image->hash = md5_file($filename);
|
$image->hash = false_throws(md5_file($filename));
|
||||||
$image->filename = (($pos = strpos($event->metadata['filename'], '?')) !== false) ? substr($event->metadata['filename'], 0, $pos) : $event->metadata['filename'];
|
$image->filename = (($pos = strpos($event->metadata['filename'], '?')) !== false) ? substr($event->metadata['filename'], 0, $pos) : $event->metadata['filename'];
|
||||||
$image->set_mime(MimeType::get_for_file($filename, get_file_ext($event->metadata["filename"]) ?? null));
|
$image->set_mime(MimeType::get_for_file($filename, get_file_ext($event->metadata["filename"]) ?? null));
|
||||||
if (empty($image->get_mime())) {
|
if (empty($image->get_mime())) {
|
||||||
|
@ -424,6 +429,7 @@ abstract class DataHandlerExtension extends Extension
|
||||||
$arr = [];
|
$arr = [];
|
||||||
foreach (get_subclasses_of(DataHandlerExtension::class) as $handler) {
|
foreach (get_subclasses_of(DataHandlerExtension::class) as $handler) {
|
||||||
$handler = (new $handler());
|
$handler = (new $handler());
|
||||||
|
assert(is_a($handler, DataHandlerExtension::class));
|
||||||
$arr = array_merge($arr, $handler->SUPPORTED_MIME);
|
$arr = array_merge($arr, $handler->SUPPORTED_MIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,9 +79,13 @@ function full_copy(string $source, string $target): void
|
||||||
if (is_dir($source)) {
|
if (is_dir($source)) {
|
||||||
@mkdir($target);
|
@mkdir($target);
|
||||||
|
|
||||||
$d = dir($source);
|
$d = false_throws(dir($source));
|
||||||
|
|
||||||
while (false !== ($entry = $d->read())) {
|
while (true) {
|
||||||
|
$entry = $d->read();
|
||||||
|
if ($entry === false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ($entry == '.' || $entry == '..') {
|
if ($entry == '.' || $entry == '..') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -155,12 +159,16 @@ function flush_output(): void
|
||||||
function stream_file(string $file, int $start, int $end): void
|
function stream_file(string $file, int $start, int $end): void
|
||||||
{
|
{
|
||||||
$fp = fopen($file, 'r');
|
$fp = fopen($file, 'r');
|
||||||
|
if(!$fp) {
|
||||||
|
throw new \Exception("Failed to open $file");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
fseek($fp, $start);
|
fseek($fp, $start);
|
||||||
$buffer = 1024 * 1024;
|
$buffer = 1024 * 1024;
|
||||||
while (!feof($fp) && ($p = ftell($fp)) <= $end) {
|
while (!feof($fp) && ($p = ftell($fp)) <= $end) {
|
||||||
if ($p + $buffer > $end) {
|
if ($p + $buffer > $end) {
|
||||||
$buffer = $end - $p + 1;
|
$buffer = $end - $p + 1;
|
||||||
|
assert($buffer >= 0);
|
||||||
}
|
}
|
||||||
echo fread($fp, $buffer);
|
echo fread($fp, $buffer);
|
||||||
flush_output();
|
flush_output();
|
||||||
|
@ -180,13 +188,13 @@ function stream_file(string $file, int $start, int $end): void
|
||||||
# http://www.php.net/manual/en/function.http-parse-headers.php#112917
|
# http://www.php.net/manual/en/function.http-parse-headers.php#112917
|
||||||
if (!function_exists('http_parse_headers')) {
|
if (!function_exists('http_parse_headers')) {
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return array<string, string|string[]>
|
||||||
*/
|
*/
|
||||||
function http_parse_headers(string $raw_headers): array
|
function http_parse_headers(string $raw_headers): array
|
||||||
{
|
{
|
||||||
$headers = []; // $headers = [];
|
$headers = [];
|
||||||
|
|
||||||
foreach (explode("\n", $raw_headers) as $i => $h) {
|
foreach (explode("\n", $raw_headers) as $h) {
|
||||||
$h = explode(':', $h, 2);
|
$h = explode(':', $h, 2);
|
||||||
|
|
||||||
if (isset($h[1])) {
|
if (isset($h[1])) {
|
||||||
|
@ -441,7 +449,7 @@ function page_number(string $input, ?int $max = null): int
|
||||||
} else {
|
} else {
|
||||||
$pageNumber = $input - 1;
|
$pageNumber = $input - 1;
|
||||||
}
|
}
|
||||||
return $pageNumber;
|
return (int)$pageNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_numberish(string $s): bool
|
function is_numberish(string $s): bool
|
||||||
|
@ -449,6 +457,14 @@ function is_numberish(string $s): bool
|
||||||
return is_numeric($s);
|
return is_numeric($s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because apparently phpstan thinks that if $i is an int, type(-$i) == int|float
|
||||||
|
*/
|
||||||
|
function negative_int(int $i): int
|
||||||
|
{
|
||||||
|
return -$i;
|
||||||
|
}
|
||||||
|
|
||||||
function clamp(int $val, ?int $min = null, ?int $max = null): int
|
function clamp(int $val, ?int $min = null, ?int $max = null): int
|
||||||
{
|
{
|
||||||
if (!is_null($min) && $val < $min) {
|
if (!is_null($min) && $val < $min) {
|
||||||
|
@ -611,11 +627,24 @@ function parse_to_milliseconds(string $input): int
|
||||||
*/
|
*/
|
||||||
function autodate(string $date, bool $html = true): string
|
function autodate(string $date, bool $html = true): string
|
||||||
{
|
{
|
||||||
$cpu = date('c', strtotime($date));
|
$cpu = date('c', false_throws(strtotime($date)));
|
||||||
$hum = date('F j, Y; H:i', strtotime($date));
|
$hum = date('F j, Y; H:i', false_throws(strtotime($date)));
|
||||||
return ($html ? "<time datetime='$cpu'>$hum</time>" : $hum);
|
return ($html ? "<time datetime='$cpu'>$hum</time>" : $hum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @param T|false $x
|
||||||
|
* @return T
|
||||||
|
*/
|
||||||
|
function false_throws(mixed $x): mixed
|
||||||
|
{
|
||||||
|
if($x === false) {
|
||||||
|
throw new \Exception("Unexpected false");
|
||||||
|
}
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a given string is a valid date-time. ( Format: yyyy-mm-dd hh:mm:ss )
|
* Check if a given string is a valid date-time. ( Format: yyyy-mm-dd hh:mm:ss )
|
||||||
*/
|
*/
|
||||||
|
@ -710,7 +739,7 @@ function validate_input(array $inputs): array
|
||||||
} elseif (in_array('bool', $flags)) {
|
} elseif (in_array('bool', $flags)) {
|
||||||
$outputs[$key] = bool_escape($value);
|
$outputs[$key] = bool_escape($value);
|
||||||
} elseif (in_array('date', $flags)) {
|
} elseif (in_array('date', $flags)) {
|
||||||
$outputs[$key] = date("Y-m-d H:i:s", strtotime(trim($value)));
|
$outputs[$key] = date("Y-m-d H:i:s", false_throws(strtotime(trim($value))));
|
||||||
} elseif (in_array('string', $flags)) {
|
} elseif (in_array('string', $flags)) {
|
||||||
if (in_array('trim', $flags)) {
|
if (in_array('trim', $flags)) {
|
||||||
$value = trim($value);
|
$value = trim($value);
|
||||||
|
|
|
@ -84,6 +84,7 @@ function modify_current_url(array $changes): string
|
||||||
*/
|
*/
|
||||||
function modify_url(string $url, array $changes): string
|
function modify_url(string $url, array $changes): string
|
||||||
{
|
{
|
||||||
|
/** @var array<string, mixed> */
|
||||||
$parts = parse_url($url);
|
$parts = parse_url($url);
|
||||||
|
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
|
@ -89,6 +89,7 @@ class UserClass
|
||||||
|
|
||||||
$_all_false = [];
|
$_all_false = [];
|
||||||
foreach ((new \ReflectionClass(Permissions::class))->getConstants() as $k => $v) {
|
foreach ((new \ReflectionClass(Permissions::class))->getConstants() as $k => $v) {
|
||||||
|
assert(is_string($v));
|
||||||
$_all_false[$v] = false;
|
$_all_false[$v] = false;
|
||||||
}
|
}
|
||||||
new UserClass("base", null, $_all_false);
|
new UserClass("base", null, $_all_false);
|
||||||
|
|
|
@ -194,7 +194,7 @@ function get_session_ip(Config $config): string
|
||||||
{
|
{
|
||||||
$mask = $config->get_string("session_hash_mask", "255.255.0.0");
|
$mask = $config->get_string("session_hash_mask", "255.255.0.0");
|
||||||
$addr = get_real_ip();
|
$addr = get_real_ip();
|
||||||
$addr = inet_ntop(inet_pton($addr) & inet_pton($mask));
|
$addr = false_throws(inet_ntop(false_throws(inet_pton($addr)) & false_throws(inet_pton($mask))));
|
||||||
return $addr;
|
return $addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,17 +285,21 @@ function load_balance_url(string $tmpl, string $hash, int $n = 0): string
|
||||||
return $tmpl;
|
return $tmpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FetchException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return null|array<string, mixed>
|
* @return array<string, string|string[]>
|
||||||
*/
|
*/
|
||||||
function fetch_url(string $url, string $mfile): ?array
|
function fetch_url(string $url, string $mfile): array
|
||||||
{
|
{
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) {
|
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) {
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
assert($ch !== false);
|
assert($ch !== false);
|
||||||
$fp = fopen($mfile, "w");
|
$fp = false_throws(fopen($mfile, "w"));
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, 1);
|
curl_setopt($ch, CURLOPT_VERBOSE, 1);
|
||||||
|
@ -306,37 +310,37 @@ function fetch_url(string $url, string $mfile): ?array
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
if ($response === false) {
|
if ($response === false) {
|
||||||
return null;
|
throw new FetchException("cURL failed: ".curl_error($ch));
|
||||||
|
}
|
||||||
|
if ($response === true) { // we use CURLOPT_RETURNTRANSFER, so this should never happen
|
||||||
|
throw new FetchException("cURL failed successfully??");
|
||||||
}
|
}
|
||||||
|
|
||||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||||
$headers = http_parse_headers(implode("\n", preg_split('/\R/', rtrim(substr($response, 0, $header_size)))));
|
$header_text = trim(substr($response, 0, $header_size));
|
||||||
|
$headers = http_parse_headers(implode("\n", false_throws(preg_split('/\R/', $header_text))));
|
||||||
$body = substr($response, $header_size);
|
$body = substr($response, $header_size);
|
||||||
|
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
fwrite($fp, $body);
|
fwrite($fp, $body);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
|
} elseif ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "wget") {
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "wget") {
|
|
||||||
$s_url = escapeshellarg($url);
|
$s_url = escapeshellarg($url);
|
||||||
$s_mfile = escapeshellarg($mfile);
|
$s_mfile = escapeshellarg($mfile);
|
||||||
system("wget --no-check-certificate $s_url --output-document=$s_mfile");
|
system("wget --no-check-certificate $s_url --output-document=$s_mfile");
|
||||||
|
if(!file_exists($mfile)) {
|
||||||
return file_exists($mfile) ? ["ok" => "true"] : null;
|
throw new FetchException("wget failed");
|
||||||
}
|
}
|
||||||
|
$headers = [];
|
||||||
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "fopen") {
|
} elseif ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "fopen") {
|
||||||
$fp_in = @fopen($url, "r");
|
$fp_in = @fopen($url, "r");
|
||||||
$fp_out = fopen($mfile, "w");
|
$fp_out = fopen($mfile, "w");
|
||||||
if (!$fp_in || !$fp_out) {
|
if (!$fp_in || !$fp_out) {
|
||||||
return null;
|
throw new FetchException("fopen failed");
|
||||||
}
|
}
|
||||||
$length = 0;
|
$length = 0;
|
||||||
while (!feof($fp_in) && $length <= $config->get_int(UploadConfig::SIZE)) {
|
while (!feof($fp_in) && $length <= $config->get_int(UploadConfig::SIZE)) {
|
||||||
$data = fread($fp_in, 8192);
|
$data = false_throws(fread($fp_in, 8192));
|
||||||
$length += strlen($data);
|
$length += strlen($data);
|
||||||
fwrite($fp_out, $data);
|
fwrite($fp_out, $data);
|
||||||
}
|
}
|
||||||
|
@ -344,11 +348,16 @@ function fetch_url(string $url, string $mfile): ?array
|
||||||
fclose($fp_out);
|
fclose($fp_out);
|
||||||
|
|
||||||
$headers = http_parse_headers(implode("\n", $http_response_header));
|
$headers = http_parse_headers(implode("\n", $http_response_header));
|
||||||
|
} else {
|
||||||
return $headers;
|
throw new FetchException("No transload engine configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
if (filesize($mfile) == 0) {
|
||||||
|
@unlink($mfile);
|
||||||
|
throw new FetchException("No data found in $url -- perhaps the site has hotlink protection?");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -412,29 +421,17 @@ function get_dir_contents(string $dir): array
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return array_diff(
|
return array_diff(
|
||||||
scandir(
|
false_throws(scandir($dir)),
|
||||||
$dir
|
|
||||||
),
|
|
||||||
['..', '.']
|
['..', '.']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove_empty_dirs(string $dir): bool
|
function remove_empty_dirs(string $dir): bool
|
||||||
{
|
{
|
||||||
assert(!empty($dir));
|
|
||||||
|
|
||||||
$result = true;
|
$result = true;
|
||||||
|
|
||||||
if (!is_dir($dir)) {
|
$items = get_dir_contents($dir);
|
||||||
return false;
|
;
|
||||||
}
|
|
||||||
|
|
||||||
$items = array_diff(
|
|
||||||
scandir(
|
|
||||||
$dir
|
|
||||||
),
|
|
||||||
['..', '.']
|
|
||||||
);
|
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
$path = join_path($dir, $item);
|
$path = join_path($dir, $item);
|
||||||
if (is_dir($path)) {
|
if (is_dir($path)) {
|
||||||
|
@ -454,22 +451,10 @@ function remove_empty_dirs(string $dir): bool
|
||||||
*/
|
*/
|
||||||
function get_files_recursively(string $dir): array
|
function get_files_recursively(string $dir): array
|
||||||
{
|
{
|
||||||
assert(!empty($dir));
|
$things = get_dir_contents($dir);
|
||||||
|
|
||||||
if (!is_dir($dir)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$things = array_diff(
|
|
||||||
scandir(
|
|
||||||
$dir
|
|
||||||
),
|
|
||||||
['..', '.']
|
|
||||||
);
|
|
||||||
|
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
|
|
||||||
foreach ($things as $thing) {
|
foreach ($things as $thing) {
|
||||||
$path = join_path($dir, $thing);
|
$path = join_path($dir, $thing);
|
||||||
if (is_file($path)) {
|
if (is_file($path)) {
|
||||||
|
@ -659,8 +644,10 @@ function _fatal_error(\Exception $e): void
|
||||||
foreach ($t as $n => $f) {
|
foreach ($t as $n => $f) {
|
||||||
$c = $f['class'] ?? '';
|
$c = $f['class'] ?? '';
|
||||||
$t = $f['type'] ?? '';
|
$t = $f['type'] ?? '';
|
||||||
|
$i = $f['file'] ?? 'unknown file';
|
||||||
|
$l = $f['line'] ?? -1;
|
||||||
$a = implode(", ", array_map("Shimmie2\stringer", $f['args'] ?? []));
|
$a = implode(", ", array_map("Shimmie2\stringer", $f['args'] ?? []));
|
||||||
print("$n: {$f['file']}({$f['line']}): {$c}{$t}{$f['function']}({$a})\n");
|
print("$n: {$i}({$l}): {$c}{$t}{$f['function']}({$a})\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Message: $message\n");
|
print("Message: $message\n");
|
||||||
|
|
|
@ -105,7 +105,7 @@ class AliasEditor extends Extension
|
||||||
if ($user->can(Permissions::MANAGE_ALIAS_LIST)) {
|
if ($user->can(Permissions::MANAGE_ALIAS_LIST)) {
|
||||||
if (count($_FILES) > 0) {
|
if (count($_FILES) > 0) {
|
||||||
$tmp = $_FILES['alias_file']['tmp_name'];
|
$tmp = $_FILES['alias_file']['tmp_name'];
|
||||||
$contents = file_get_contents($tmp);
|
$contents = false_throws(file_get_contents($tmp));
|
||||||
$this->add_alias_csv($contents);
|
$this->add_alias_csv($contents);
|
||||||
log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many?
|
log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many?
|
||||||
$page->set_mode(PageMode::REDIRECT);
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
|
|
@ -111,7 +111,7 @@ class AutoTagger extends Extension
|
||||||
if ($user->can(Permissions::MANAGE_AUTO_TAG)) {
|
if ($user->can(Permissions::MANAGE_AUTO_TAG)) {
|
||||||
if (count($_FILES) > 0) {
|
if (count($_FILES) > 0) {
|
||||||
$tmp = $_FILES['auto_tag_file']['tmp_name'];
|
$tmp = $_FILES['auto_tag_file']['tmp_name'];
|
||||||
$contents = file_get_contents($tmp);
|
$contents = false_throws(file_get_contents($tmp));
|
||||||
$count = $this->add_auto_tag_csv($contents);
|
$count = $this->add_auto_tag_csv($contents);
|
||||||
log_info(AutoTaggerInfo::KEY, "Imported $count auto-tag definitions from file from file", "Imported $count auto-tag definitions");
|
log_info(AutoTaggerInfo::KEY, "Imported $count auto-tag definitions from file from file", "Imported $count auto-tag definitions");
|
||||||
$page->set_mode(PageMode::REDIRECT);
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
|
|
@ -28,7 +28,7 @@ class BrowserSearch extends Extension
|
||||||
$search_title = $config->get_string(SetupConfig::TITLE);
|
$search_title = $config->get_string(SetupConfig::TITLE);
|
||||||
$search_form_url = search_link(['{searchTerms}']);
|
$search_form_url = search_link(['{searchTerms}']);
|
||||||
$suggenton_url = make_link('browser_search/')."{searchTerms}";
|
$suggenton_url = make_link('browser_search/')."{searchTerms}";
|
||||||
$icon_b64 = base64_encode(file_get_contents("ext/static_files/static/favicon.ico"));
|
$icon_b64 = base64_encode(false_throws(file_get_contents("ext/static_files/static/favicon.ico")));
|
||||||
|
|
||||||
// Now for the XML
|
// Now for the XML
|
||||||
$xml = "
|
$xml = "
|
||||||
|
|
|
@ -48,7 +48,7 @@ class BulkDownload extends Extension
|
||||||
if ($user->can(Permissions::BULK_DOWNLOAD) &&
|
if ($user->can(Permissions::BULK_DOWNLOAD) &&
|
||||||
($event->action == BulkDownload::DOWNLOAD_ACTION_NAME)) {
|
($event->action == BulkDownload::DOWNLOAD_ACTION_NAME)) {
|
||||||
$download_filename = $user->name . '-' . date('YmdHis') . '.zip';
|
$download_filename = $user->name . '-' . date('YmdHis') . '.zip';
|
||||||
$zip_filename = tempnam(sys_get_temp_dir(), "shimmie_bulk_download");
|
$zip_filename = false_throws(tempnam(sys_get_temp_dir(), "shimmie_bulk_download"));
|
||||||
$zip = new \ZipArchive();
|
$zip = new \ZipArchive();
|
||||||
$size_total = 0;
|
$size_total = 0;
|
||||||
$max_size = $config->get_int(BulkDownloadConfig::SIZE_LIMIT);
|
$max_size = $config->get_int(BulkDownloadConfig::SIZE_LIMIT);
|
||||||
|
@ -61,7 +61,6 @@ class BulkDownload extends Extension
|
||||||
throw new BulkDownloadException("Bulk download limited to ".human_filesize($max_size));
|
throw new BulkDownloadException("Bulk download limited to ".human_filesize($max_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$filename = urldecode($image->get_nice_image_name());
|
$filename = urldecode($image->get_nice_image_name());
|
||||||
$filename = str_replace(":", ";", $filename);
|
$filename = str_replace(":", ";", $filename);
|
||||||
$zip->addFile($img_loc, $filename);
|
$zip->addFile($img_loc, $filename);
|
||||||
|
|
|
@ -313,10 +313,11 @@ class DanbooruApi extends Extension
|
||||||
$source = isset($_REQUEST['source']) ? $_REQUEST['source'] : $_REQUEST['post']['source'];
|
$source = isset($_REQUEST['source']) ? $_REQUEST['source'] : $_REQUEST['post']['source'];
|
||||||
$file = tempnam(sys_get_temp_dir(), "shimmie_transload");
|
$file = tempnam(sys_get_temp_dir(), "shimmie_transload");
|
||||||
assert($file !== false);
|
assert($file !== false);
|
||||||
$ok = fetch_url($source, $file);
|
try {
|
||||||
if (!$ok) {
|
fetch_url($source, $file);
|
||||||
|
} catch(FetchException $e) {
|
||||||
$page->set_code(409);
|
$page->set_code(409);
|
||||||
$page->add_http_header("X-Danbooru-Errors: fopen read error");
|
$page->add_http_header("X-Danbooru-Errors: $e");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$filename = basename($source);
|
$filename = basename($source);
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Home extends Extension
|
||||||
$counters = [];
|
$counters = [];
|
||||||
$counters["None"] = "none";
|
$counters["None"] = "none";
|
||||||
$counters["Text-only"] = "text-only";
|
$counters["Text-only"] = "text-only";
|
||||||
foreach (glob("ext/home/counters/*") as $counter_dirname) {
|
foreach (false_throws(glob("ext/home/counters/*")) as $counter_dirname) {
|
||||||
$name = str_replace("ext/home/counters/", "", $counter_dirname);
|
$name = str_replace("ext/home/counters/", "", $counter_dirname);
|
||||||
$counters[ucfirst($name)] = $name;
|
$counters[ucfirst($name)] = $name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,8 +352,10 @@ class OuroborosAPI extends Extension
|
||||||
// Transload from source
|
// Transload from source
|
||||||
$meta['file'] = tempnam(sys_get_temp_dir(), 'shimmie_transload_' . $config->get_string(UploadConfig::TRANSLOAD_ENGINE));
|
$meta['file'] = tempnam(sys_get_temp_dir(), 'shimmie_transload_' . $config->get_string(UploadConfig::TRANSLOAD_ENGINE));
|
||||||
$meta['filename'] = basename($post->file_url);
|
$meta['filename'] = basename($post->file_url);
|
||||||
if (!fetch_url($post->file_url, $meta['file'])) {
|
try {
|
||||||
$this->sendResponse(500, 'Transloading failed');
|
fetch_url($post->file_url, $meta['file']);
|
||||||
|
} catch (FetchException $e) {
|
||||||
|
$this->sendResponse(500, "Transloading failed: $e");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$meta['hash'] = md5_file($meta['file']);
|
$meta['hash'] = md5_file($meta['file']);
|
||||||
|
|
|
@ -109,7 +109,7 @@ class RSSImages extends Extension
|
||||||
$tags = html_escape($image->get_tag_list());
|
$tags = html_escape($image->get_tag_list());
|
||||||
$thumb_url = $image->get_thumb_link();
|
$thumb_url = $image->get_thumb_link();
|
||||||
$image_url = $image->get_image_link();
|
$image_url = $image->get_image_link();
|
||||||
$posted = date(DATE_RSS, strtotime($image->posted));
|
$posted = date(DATE_RSS, false_throws(strtotime($image->posted)));
|
||||||
$content = html_escape(
|
$content = html_escape(
|
||||||
"<div>" .
|
"<div>" .
|
||||||
"<p>" . $this->theme->build_thumb_html($image) . "</p>" .
|
"<p>" . $this->theme->build_thumb_html($image) . "</p>" .
|
||||||
|
|
|
@ -348,7 +348,7 @@ class Setup extends Extension
|
||||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||||
{
|
{
|
||||||
$themes = [];
|
$themes = [];
|
||||||
foreach (glob("themes/*") as $theme_dirname) {
|
foreach (false_throws(glob("themes/*")) as $theme_dirname) {
|
||||||
$name = str_replace("themes/", "", $theme_dirname);
|
$name = str_replace("themes/", "", $theme_dirname);
|
||||||
$human = str_replace("_", " ", $name);
|
$human = str_replace("_", " ", $name);
|
||||||
$human = ucwords($human);
|
$human = ucwords($human);
|
||||||
|
|
|
@ -211,7 +211,7 @@ class TranscodeVideo extends Extension
|
||||||
}
|
}
|
||||||
|
|
||||||
$original_file = warehouse_path(Image::IMAGE_DIR, $image->hash);
|
$original_file = warehouse_path(Image::IMAGE_DIR, $image->hash);
|
||||||
$tmp_filename = tempnam(sys_get_temp_dir(), "shimmie_transcode_video");
|
$tmp_filename = false_throws(tempnam(sys_get_temp_dir(), "shimmie_transcode_video"));
|
||||||
$tmp_filename = $this->transcode_video($original_file, $image->video_codec, $target_mime, $tmp_filename);
|
$tmp_filename = $this->transcode_video($original_file, $image->video_codec, $target_mime, $tmp_filename);
|
||||||
send_event(new ImageReplaceEvent($image, $tmp_filename));
|
send_event(new ImageReplaceEvent($image, $tmp_filename));
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -69,18 +69,14 @@ class Update extends Extension
|
||||||
$filename = "./data/update_{$commitSHA}.zip";
|
$filename = "./data/update_{$commitSHA}.zip";
|
||||||
|
|
||||||
log_info("update", "Attempting to download Shimmie commit: ".$commitSHA);
|
log_info("update", "Attempting to download Shimmie commit: ".$commitSHA);
|
||||||
if ($headers = fetch_url($url, $filename)) {
|
$headers = fetch_url($url, $filename);
|
||||||
if (($headers['Content-Type'] !== MimeType::ZIP) || ((int) $headers['Content-Length'] !== filesize($filename))) {
|
if (($headers['Content-Type'] !== MimeType::ZIP) || ((int) $headers['Content-Length'] !== filesize($filename))) {
|
||||||
unlink("./data/update_{$commitSHA}.zip");
|
unlink("./data/update_{$commitSHA}.zip");
|
||||||
log_warning("update", "Download failed: not zip / not same size as remote file.");
|
log_warning("update", "Download failed: not zip / not same size as remote file.");
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_warning("update", "Download failed to download.");
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function update_shimmie(): bool
|
private function update_shimmie(): bool
|
||||||
|
|
|
@ -385,13 +385,10 @@ class Upload extends Extension
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch file
|
// Fetch file
|
||||||
$headers = fetch_url($url, $tmp_filename);
|
try {
|
||||||
if (is_null($headers)) {
|
$headers = fetch_url($url, $tmp_filename);
|
||||||
log_warning("core-util", "Failed to fetch $url");
|
} catch (FetchException $e) {
|
||||||
throw new UploadException("Error reading from $url");
|
throw new UploadException("Error reading from $url: $e");
|
||||||
}
|
|
||||||
if (filesize($tmp_filename) == 0) {
|
|
||||||
throw new UploadException("No data found in $url -- perhaps the site has hotlink protection?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse metadata
|
// Parse metadata
|
||||||
|
|
|
@ -8,7 +8,7 @@ use MicroHTML\HTMLElement;
|
||||||
|
|
||||||
class UserBlockBuildingEvent extends Event
|
class UserBlockBuildingEvent extends Event
|
||||||
{
|
{
|
||||||
/** @var array<int, array{name: string, link: string}> */
|
/** @var array<int, array{name: string|HTMLElement, link: string}> */
|
||||||
public array $parts = [];
|
public array $parts = [];
|
||||||
|
|
||||||
public function add_link(string|HTMLElement $name, string $link, int $position = 50): void
|
public function add_link(string|HTMLElement $name, string $link, int $position = 50): void
|
||||||
|
|
|
@ -45,7 +45,7 @@ class UserPageTheme extends Themelet
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<int, array{name: string, link: string}> $parts
|
* @param array<int, array{name: string|HTMLElement, link: string}> $parts
|
||||||
*/
|
*/
|
||||||
public function display_user_links(Page $page, User $user, array $parts): void
|
public function display_user_links(Page $page, User $user, array $parts): void
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,7 @@ class UserPageTheme extends Themelet
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<array{link: string, name: string}> $parts
|
* @param array<array{link: string, name: string|HTMLElement}> $parts
|
||||||
*/
|
*/
|
||||||
public function display_user_block(Page $page, User $user, array $parts): void
|
public function display_user_block(Page $page, User $user, array $parts): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,9 @@ declare(strict_types=1);
|
||||||
namespace Shimmie2;
|
namespace Shimmie2;
|
||||||
|
|
||||||
define("UNITTEST", true);
|
define("UNITTEST", true);
|
||||||
define("EXTRA_EXTS", str_replace("ext/", "", implode(',', glob('ext/*'))));
|
$_all_exts = glob('ext/*');
|
||||||
|
assert($_all_exts !== false);
|
||||||
|
define("EXTRA_EXTS", str_replace("ext/", "", implode(',', $_all_exts)));
|
||||||
|
|
||||||
define("DATABASE_DSN", null);
|
define("DATABASE_DSN", null);
|
||||||
define("DATABASE_TIMEOUT", 10000);
|
define("DATABASE_TIMEOUT", 10000);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
parameters:
|
parameters:
|
||||||
errorFormat: raw
|
errorFormat: raw
|
||||||
level: 5
|
level: 6
|
||||||
paths:
|
paths:
|
||||||
- ../core
|
- ../core
|
||||||
- ../ext
|
- ../ext
|
||||||
|
|
|
@ -59,7 +59,8 @@ class CustomCommentListTheme extends CommentListTheme
|
||||||
if ($comment_limit > 0 && $comment_count > $comment_limit) {
|
if ($comment_limit > 0 && $comment_count > $comment_limit) {
|
||||||
//$hidden = $comment_count - $comment_limit;
|
//$hidden = $comment_count - $comment_limit;
|
||||||
$comment_html .= "<p>showing $comment_limit of $comment_count comments</p>";
|
$comment_html .= "<p>showing $comment_limit of $comment_count comments</p>";
|
||||||
$comments = array_slice($comments, -$comment_limit);
|
|
||||||
|
$comments = array_slice($comments, negative_int($comment_limit));
|
||||||
}
|
}
|
||||||
foreach ($comments as $comment) {
|
foreach ($comments as $comment) {
|
||||||
$comment_html .= $this->comment_to_html($comment);
|
$comment_html .= $this->comment_to_html($comment);
|
||||||
|
|
|
@ -59,7 +59,7 @@ class CustomCommentListTheme extends CommentListTheme
|
||||||
if ($comment_limit > 0 && $comment_count > $comment_limit) {
|
if ($comment_limit > 0 && $comment_count > $comment_limit) {
|
||||||
//$hidden = $comment_count - $comment_limit;
|
//$hidden = $comment_count - $comment_limit;
|
||||||
$comment_html .= "<p>showing $comment_limit of $comment_count comments</p>";
|
$comment_html .= "<p>showing $comment_limit of $comment_count comments</p>";
|
||||||
$comments = array_slice($comments, -$comment_limit);
|
$comments = array_slice($comments, negative_int($comment_limit));
|
||||||
}
|
}
|
||||||
foreach ($comments as $comment) {
|
foreach ($comments as $comment) {
|
||||||
$comment_html .= $this->comment_to_html($comment);
|
$comment_html .= $this->comment_to_html($comment);
|
||||||
|
|
|
@ -88,6 +88,7 @@ EOD;
|
||||||
$footer_html = $this->footer_html();
|
$footer_html = $this->footer_html();
|
||||||
|
|
||||||
$header_inc = file_get_contents("themes/rule34v2/header.inc");
|
$header_inc = file_get_contents("themes/rule34v2/header.inc");
|
||||||
|
assert($header_inc !== false);
|
||||||
$header_inc = str_replace('$QUERY', $query, $header_inc);
|
$header_inc = str_replace('$QUERY', $query, $header_inc);
|
||||||
return <<<EOD
|
return <<<EOD
|
||||||
<table id="header" width="100%">
|
<table id="header" width="100%">
|
||||||
|
|
Reference in a new issue