and also au revoir to all object trashy wrappings
This commit is contained in:
parent
5db6d59a49
commit
f12ac03629
14 changed files with 92 additions and 362 deletions
|
@ -71,7 +71,7 @@ function deleteAllFilesInDir(string $dir, string $pattern): void
|
|||
$files = globDir($dir, $pattern);
|
||||
|
||||
foreach ($files as $file) {
|
||||
unlink($file);
|
||||
safe_delete($file);
|
||||
misuzu_log("Deleted '{$file}'");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,9 +211,7 @@ MIG;
|
|||
// we're running this again because ob_clean breaks gzip otherwise
|
||||
ob_start();
|
||||
|
||||
$storage_dir = $app->getStoragePath();
|
||||
if (!$storage_dir->isReadable()
|
||||
|| !$storage_dir->isWritable()) {
|
||||
if (!$app->canAccessStorage()) {
|
||||
echo 'Cannot access storage directory.';
|
||||
exit;
|
||||
}
|
||||
|
|
|
@ -11,18 +11,22 @@ switch ($mode) {
|
|||
case 'avatar':
|
||||
$avatar_filename = $app->getDefaultAvatar();
|
||||
$user_avatar = "{$user_id}.msz";
|
||||
$cropped_avatar = $app->getStore('avatars/200x200')->filename($user_avatar);
|
||||
$cropped_avatar = build_path(
|
||||
create_directory(build_path($app->getStoragePath(), 'avatars/200x200')),
|
||||
$user_avatar
|
||||
);
|
||||
|
||||
if (File::exists($cropped_avatar)) {
|
||||
if (is_file($cropped_avatar)) {
|
||||
$avatar_filename = $cropped_avatar;
|
||||
} else {
|
||||
$original_avatar = $app->getStore('avatars/original')->filename($user_avatar);
|
||||
$original_avatar = build_path($app->getStoragePath(), 'avatars/original', $user_avatar);
|
||||
|
||||
if (File::exists($original_avatar)) {
|
||||
if (is_file($original_avatar)) {
|
||||
try {
|
||||
File::writeAll(
|
||||
file_put_contents(
|
||||
$cropped_avatar,
|
||||
crop_image_centred_path($original_avatar, 200, 200)->getImagesBlob()
|
||||
crop_image_centred_path($original_avatar, 200, 200)->getImagesBlob(),
|
||||
LOCK_EX
|
||||
);
|
||||
|
||||
$avatar_filename = $cropped_avatar;
|
||||
|
@ -32,7 +36,7 @@ switch ($mode) {
|
|||
}
|
||||
|
||||
header('Content-Type: ' . mime_content_type($avatar_filename));
|
||||
echo File::readToEnd($avatar_filename);
|
||||
echo file_get_contents($avatar_filename);
|
||||
break;
|
||||
|
||||
case 'view':
|
||||
|
|
|
@ -303,7 +303,7 @@ switch ($settingsMode) {
|
|||
');
|
||||
$getMail->bindValue('user_id', $app->getUserId());
|
||||
$currentEmail = $getMail->execute() ? $getMail->fetchColumn() : 'Failed to fetch e-mail address.';
|
||||
$userHasAvatar = File::exists($app->getStore('avatars/original')->filename($avatarFileName));
|
||||
$userHasAvatar = is_file(build_path($app->getStoragePath(), 'avatars/original', $avatarFileName));
|
||||
|
||||
tpl_vars([
|
||||
'avatar_user_id' => $app->getUserId(),
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
namespace Misuzu;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Misuzu\IO\Directory;
|
||||
use Misuzu\IO\DirectoryDoesNotExistException;
|
||||
use Misuzu\Users\Session;
|
||||
use UnexpectedValueException;
|
||||
use InvalidArgumentException;
|
||||
|
@ -121,51 +119,22 @@ final class Application
|
|||
$path = __DIR__ . '/../' . $path;
|
||||
}
|
||||
|
||||
return Directory::fixSlashes(rtrim($path, '/'));
|
||||
return fix_path_separator(rtrim($path, '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data storage path, with config storage path prefix.
|
||||
* @param string $append
|
||||
* @return Directory
|
||||
* @throws DirectoryDoesNotExistException
|
||||
* @throws IO\DirectoryExistsException
|
||||
* Gets a data storage path.
|
||||
* @return string
|
||||
*/
|
||||
public function getStoragePath(string $append = ''): Directory
|
||||
public function getStoragePath(): string
|
||||
{
|
||||
if (starts_with($append, '/')) {
|
||||
$path = $append;
|
||||
} else {
|
||||
$path = $this->config['Storage']['path'] ?? __DIR__ . '/../store';
|
||||
|
||||
if (!empty($append)) {
|
||||
$path .= '/' . $append;
|
||||
}
|
||||
}
|
||||
|
||||
return Directory::createOrOpen($this->getPath($path));
|
||||
return create_directory($this->config['Storage']['path'] ?? __DIR__ . '/../store');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data store, with config overrides!
|
||||
* @param string $purpose
|
||||
* @return Directory
|
||||
* @throws DirectoryDoesNotExistException
|
||||
* @throws IO\DirectoryExistsException
|
||||
*/
|
||||
public function getStore(string $purpose): Directory
|
||||
public function canAccessStorage(): bool
|
||||
{
|
||||
$override_key = 'override_' . str_replace('/', '_', $purpose);
|
||||
|
||||
if (array_key_exists('Storage', $this->config)) {
|
||||
try {
|
||||
return new Directory($this->config['Storage'][$override_key] ?? '');
|
||||
} catch (DirectoryDoesNotExistException $ex) {
|
||||
// fall through and just get the default path.
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getStoragePath($purpose);
|
||||
$path = $this->getStoragePath();
|
||||
return is_readable($path) && is_writable($path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Directory container.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class Directory
|
||||
{
|
||||
/**
|
||||
* Path to this directory.
|
||||
* @var string
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* Directory separator used on this system, usually either \ for Windows or / for basically everything else.
|
||||
*/
|
||||
public const SEPARATOR = DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Get the path of this directory.
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isReadable(): bool
|
||||
{
|
||||
return is_readable($this->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isWritable(): bool
|
||||
{
|
||||
return is_writable($this->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the path, sets proper slashes and checks if the directory exists.
|
||||
* @param string $path
|
||||
* @throws DirectoryDoesNotExistException
|
||||
*/
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$path = static::fixSlashes(rtrim($path, '/\\'));
|
||||
|
||||
if (!static::exists($path)) {
|
||||
throw new DirectoryDoesNotExistException;
|
||||
}
|
||||
|
||||
$this->path = realpath($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets contents of this directory, subdirs get their own instance.
|
||||
* @param string $pattern
|
||||
* @return array
|
||||
*/
|
||||
public function files(string $pattern = '*'): array
|
||||
{
|
||||
return array_map(function ($path) {
|
||||
if (static::exists($path)) {
|
||||
return new static($path);
|
||||
}
|
||||
|
||||
return realpath($path);
|
||||
}, glob($this->path . self::SEPARATOR . $pattern));
|
||||
}
|
||||
|
||||
public function filename(string $filename): string
|
||||
{
|
||||
return $this->getPath() . self::SEPARATOR . $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory if it doesn't already exist.
|
||||
* @param string $path
|
||||
* @return Directory
|
||||
* @throws DirectoryDoesNotExistException
|
||||
* @throws DirectoryExistsException
|
||||
*/
|
||||
public static function create(string $path): Directory
|
||||
{
|
||||
if (static::exists($path)) {
|
||||
throw new DirectoryExistsException;
|
||||
}
|
||||
|
||||
$on_windows = running_on_windows();
|
||||
$path = Directory::fixSlashes($path);
|
||||
$split_path = explode(self::SEPARATOR, $path);
|
||||
$existing_path = $on_windows ? '' : self::SEPARATOR;
|
||||
|
||||
foreach ($split_path as $path_part) {
|
||||
$existing_path .= $path_part . self::SEPARATOR;
|
||||
|
||||
if ($on_windows && mb_substr($path_part, 1, 2) === ':\\') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Directory::exists($existing_path)) {
|
||||
mkdir($existing_path);
|
||||
}
|
||||
}
|
||||
|
||||
return new static($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return Directory
|
||||
* @throws DirectoryDoesNotExistException
|
||||
* @throws DirectoryExistsException
|
||||
*/
|
||||
public static function createOrOpen(string $path): Directory
|
||||
{
|
||||
if (static::exists($path)) {
|
||||
return new Directory($path);
|
||||
} else {
|
||||
return Directory::create($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a directory, recursively if requested. Use $purge with care!
|
||||
* @param string $path
|
||||
* @param bool $purge
|
||||
* @throws DirectoryDoesNotExistException
|
||||
* @throws FileDoesNotExistException
|
||||
*/
|
||||
public static function delete(string $path, bool $purge = false): void
|
||||
{
|
||||
$path = static::fixSlashes($path);
|
||||
|
||||
if (!static::exists($path)) {
|
||||
throw new DirectoryDoesNotExistException;
|
||||
}
|
||||
|
||||
if ($purge) {
|
||||
$dir = new static($path);
|
||||
|
||||
foreach ($dir->files() as $file) {
|
||||
if ($file instanceof self) {
|
||||
static::delete($file->path, true);
|
||||
} else {
|
||||
File::delete($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rmdir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a directory exists.
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists(string $path): bool
|
||||
{
|
||||
$path = static::fixSlashes($path);
|
||||
return file_exists($path) && is_dir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes operating system specific slashing.
|
||||
* @param string $path
|
||||
* @param string $separator
|
||||
* @return string
|
||||
*/
|
||||
public static function fixSlashes(string $path, string $separator = self::SEPARATOR): string
|
||||
{
|
||||
return str_replace(['/', '\\'], $separator, $path);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a directory doesn't exist.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class DirectoryDoesNotExistException extends IOException
|
||||
{
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a folder already exists.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class DirectoryExistsException extends IOException
|
||||
{
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Static file meta functions.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class File
|
||||
{
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param bool $lock
|
||||
* @return string
|
||||
*/
|
||||
public static function readToEnd(string $filename, bool $lock = false): string
|
||||
{
|
||||
$lock = file_get_contents($filename); // reusing $lock bc otherwise sublime yells about unused vars
|
||||
return $lock === false ? $lock : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $data
|
||||
* @throws FileDoesNotExistException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function writeAll(string $filename, string $data): void
|
||||
{
|
||||
file_put_contents($filename, $data, LOCK_EX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file exists.
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists(string $path): bool
|
||||
{
|
||||
$path = realpath(Directory::fixSlashes($path));
|
||||
return file_exists($path) && is_file($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file permanently, use with care!
|
||||
* @param string $path
|
||||
* @throws FileDoesNotExistException
|
||||
*/
|
||||
public static function delete(string $path): void
|
||||
{
|
||||
$path = realpath(Directory::fixSlashes($path));
|
||||
|
||||
if (!is_string($path) || !static::exists($path)) {
|
||||
throw new FileDoesNotExistException;
|
||||
}
|
||||
|
||||
unlink($path);
|
||||
}
|
||||
|
||||
public static function safeDelete(string $path): void
|
||||
{
|
||||
if (self::exists($path)) {
|
||||
self::delete($path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a file doesn't exist.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class FileDoesNotExistException extends IOException
|
||||
{
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a file already exists.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class FileExistsException extends IOException
|
||||
{
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Holds the base I/O exception.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class IOException extends \Exception
|
||||
{
|
||||
}
|
|
@ -61,14 +61,15 @@ function user_avatar_delete(int $userId): void
|
|||
{
|
||||
$app = Application::getInstance();
|
||||
$avatarFileName = sprintf(MSZ_USER_AVATAR_FORMAT, $userId);
|
||||
$storePath = $app->getStoragePath();
|
||||
|
||||
$deleteThis = [
|
||||
$app->getStore('avatars/original')->filename($avatarFileName),
|
||||
$app->getStore('avatars/200x200')->filename($avatarFileName),
|
||||
build_path($storePath, 'avatars/original', $avatarFileName),
|
||||
build_path($storePath, 'avatars/200x200', $avatarFileName),
|
||||
];
|
||||
|
||||
foreach ($deleteThis as $deleteAvatar) {
|
||||
File::safeDelete($deleteAvatar);
|
||||
safe_delete($deleteAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +136,10 @@ function user_avatar_set_from_path(int $userId, string $path, array $options = [
|
|||
user_avatar_delete($userId);
|
||||
|
||||
$fileName = sprintf(MSZ_USER_AVATAR_FORMAT, $userId);
|
||||
$avatarPath = Application::getInstance()->getStore('avatars/original')->filename($fileName);
|
||||
$avatarPath = build_path(
|
||||
create_directory(build_path(Application::getInstance()->getStoragePath(), 'avatars/original')),
|
||||
$fileName
|
||||
);
|
||||
|
||||
if (!copy($path, $avatarPath)) {
|
||||
return MSZ_USER_AVATAR_ERROR_STORE_FAILED;
|
||||
|
@ -155,7 +159,7 @@ function user_avatar_set_from_data(int $userId, string $data, array $options = [
|
|||
chmod($tmp, 644);
|
||||
file_put_contents($tmp, $data);
|
||||
$result = user_avatar_set_from_path($userId, $tmp, $options);
|
||||
unlink($tmp);
|
||||
safe_delete($tmp);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
|
61
utility.php
61
utility.php
|
@ -38,6 +38,67 @@ function password_entropy(string $password): int
|
|||
return count(count_chars(utf8_decode($password), 1)) * 8;
|
||||
}
|
||||
|
||||
function fix_path_separator(string $path, string $separator = DIRECTORY_SEPARATOR, array $separators = ['/', '\\']): string
|
||||
{
|
||||
return str_replace($separators, $separator, rtrim($path, implode($separators)));
|
||||
}
|
||||
|
||||
function safe_delete(string $path): void
|
||||
{
|
||||
$path = realpath($path);
|
||||
|
||||
if (empty($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
rmdir($path);
|
||||
return;
|
||||
}
|
||||
|
||||
unlink($path);
|
||||
}
|
||||
|
||||
// mkdir + recursion
|
||||
function create_directory(string $path): string
|
||||
{
|
||||
if (is_file($path)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
return realpath($path);
|
||||
}
|
||||
|
||||
$on_windows = running_on_windows();
|
||||
$path = fix_path_separator($path);
|
||||
$split_path = explode(DIRECTORY_SEPARATOR, $path);
|
||||
$existing_path = $on_windows ? '' : DIRECTORY_SEPARATOR;
|
||||
|
||||
foreach ($split_path as $path_part) {
|
||||
$existing_path .= $path_part . DIRECTORY_SEPARATOR;
|
||||
|
||||
if ($on_windows && mb_substr($path_part, 1, 2) === ':\\') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!file_exists($existing_path)) {
|
||||
mkdir($existing_path);
|
||||
}
|
||||
}
|
||||
|
||||
return ($path = realpath($path)) === false ? '' : $path;
|
||||
}
|
||||
|
||||
function build_path(string ...$path): string
|
||||
{
|
||||
for ($i = 0; $i < count($path); $i++) {
|
||||
$path[$i] = fix_path_separator($path[$i]);
|
||||
}
|
||||
|
||||
return implode(DIRECTORY_SEPARATOR, $path);
|
||||
}
|
||||
|
||||
function check_mx_record(string $email): bool
|
||||
{
|
||||
$domain = mb_substr(mb_strstr($email, '@'), 1);
|
||||
|
|
Loading…
Reference in a new issue