Intial commit
This commit is contained in:
commit
ea0e8ddad8
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
session_start();
|
||||
|
||||
// Global variables
|
||||
|
||||
$_dr = $_SERVER['DOCUMENT_ROOT'];
|
||||
// TODO: Make configurable in .ini
|
||||
$GLOBALS['path_media'] = '/srv/http/boorein/media';
|
||||
$GLOBALS['base_media'] = 'media';
|
||||
$GLOBALS['base_uri'] =
|
||||
$_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
(match ([$_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD']]) {
|
||||
['/item', 'POST'] => post_item(),
|
||||
//['/item', 'GET'] => get_item(),
|
||||
//['/search', 'GET'] => get_search(),
|
||||
default => Json::error('Not implemented')
|
||||
})->die();
|
||||
|
||||
function post_item()
|
||||
{
|
||||
// The checks are performed internally
|
||||
$item = Item::upload($_FILES['file']);
|
||||
|
||||
return Json::new([
|
||||
'type' => 'success',
|
||||
'id' => $item->getHash(),
|
||||
'link' => $item->getUri(),
|
||||
]);
|
||||
};
|
||||
|
||||
class Item
|
||||
{
|
||||
private string $hash;
|
||||
private string $extension;
|
||||
|
||||
// ::upload() requires the PHP file upload ARRAY from $_FILES
|
||||
public static function upload(array $php_file): Item
|
||||
{
|
||||
$from_path = $php_file['tmp_name'] ?? null;
|
||||
|
||||
// --- CHECKS ---
|
||||
if (!is_string($from_path))
|
||||
Json::error('Passed invalid upload structure')->die();
|
||||
if (!is_uploaded_file($from_path))
|
||||
Json::error('Trying to upload illegal or non-existent file')->die();
|
||||
|
||||
// --- INITIALIZE ---
|
||||
$ret = new Item();
|
||||
$ret->hash = hash_file('sha256', $from_path);
|
||||
$ret->calculateExtension($php_file);
|
||||
|
||||
// --- ACTUALLY GRAB FILE ---
|
||||
$new_path = $ret->getPath();
|
||||
if (file_exists($new_path))
|
||||
Json::error('File already exists')->die();
|
||||
if (!move_uploaded_file($from_path, $new_path))
|
||||
Json::error('Failed to move uploaded file')->die();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Assumes is_uploaded_file has been done
|
||||
private function calculateExtension(array $php_file)
|
||||
{
|
||||
$path = $php_file['tmp_name'] ?? false;
|
||||
$name = $php_file['name'] ?? null;
|
||||
|
||||
// Try to get extension from mimetype
|
||||
$ext = (new finfo(FILEINFO_EXTENSION))->file($path);
|
||||
|
||||
// REVIEW: Maybe change it so it doesn't have to be separated like this but
|
||||
// do somethign like ['mime/type', null] be equivalent to this?
|
||||
if (array_search($ext, ['webp', 'png', 'jpeg']) !== false) {
|
||||
$this->extension = $ext;
|
||||
return;
|
||||
}
|
||||
|
||||
// If it doesn't work, try to figure it out from the original extension
|
||||
if ($ext == '???') {
|
||||
// We mustn't accept everything straight away, so we're only accepting
|
||||
// mime-type and original extension combinations that make sense
|
||||
$whitelist = [
|
||||
['application/zip', 'kra'],
|
||||
['application/zip', 'krz'],
|
||||
];
|
||||
|
||||
// NOTE: The original extension has to be grabbed from the original name
|
||||
$mime = mime_content_type($path);
|
||||
$ext = pathinfo($name, PATHINFO_EXTENSION);
|
||||
|
||||
if (array_search([$mime, $ext], $whitelist) !== false) {
|
||||
$this->extension = $ext;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Json::error('File mime-type and or extension not allowed.')->die();
|
||||
}
|
||||
|
||||
public function getHash(): string
|
||||
{
|
||||
return $this->hash;
|
||||
}
|
||||
public function getExtension(): string
|
||||
{
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
public function getPath(bool $absolute = false): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s/%s.%s',
|
||||
$GLOBALS[$absolute ? 'path_media' : 'path_media'],
|
||||
$this->hash,
|
||||
$this->extension
|
||||
);
|
||||
}
|
||||
public function getUri(): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s/%s/%s.%s',
|
||||
$GLOBALS['base_uri'],
|
||||
$GLOBALS['base_media'],
|
||||
$this->hash,
|
||||
$this->extension,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Json
|
||||
{
|
||||
function __construct(
|
||||
private mixed $struct
|
||||
) {
|
||||
$this->struct = $struct;
|
||||
}
|
||||
|
||||
public static function new(mixed $struct): Json
|
||||
{
|
||||
return new Json($struct);
|
||||
}
|
||||
|
||||
public static function error(mixed $msg): Json
|
||||
{
|
||||
return new Json([
|
||||
'type' => 'error',
|
||||
'msg' => $msg,
|
||||
]);
|
||||
}
|
||||
|
||||
public function die()
|
||||
{
|
||||
print(json_encode($this->struct));
|
||||
die();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue