This repository has been archived on 2024-06-26. You can view files and clone it, but cannot push or open issues or pull requests.
sakura/app/Controllers/FileController.php

218 lines
5.9 KiB
PHP
Raw Normal View History

2016-02-15 21:20:46 +00:00
<?php
/**
* Holds the file controller.
* @package Sakura
*/
namespace Sakura\Controllers;
2016-09-13 22:05:03 +00:00
use Phroute\Phroute\Exception\HttpMethodNotAllowedException;
use Phroute\Phroute\Exception\HttpRouteNotFoundException;
2016-02-15 21:20:46 +00:00
use Sakura\Config;
2016-09-13 22:05:03 +00:00
use Sakura\CurrentSession;
use Sakura\DB;
use Sakura\Exceptions\FileException;
2016-02-15 21:20:46 +00:00
use Sakura\File;
2016-09-13 22:05:03 +00:00
use Sakura\Perms;
use Sakura\Perms\Manage;
2016-02-15 21:20:46 +00:00
use Sakura\Perms\Site;
2016-04-01 15:31:05 +00:00
use Sakura\Template;
2016-03-27 21:18:57 +00:00
use Sakura\User;
2016-02-15 21:20:46 +00:00
/**
* File controller, handles user uploads like avatars.
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
2016-02-27 16:46:16 +00:00
class FileController extends Controller
2016-02-15 21:20:46 +00:00
{
2016-09-13 22:05:03 +00:00
/**
* Possible modes.
*/
const MODES = [
'avatar',
'background',
'header',
];
2016-03-27 21:18:57 +00:00
/**
* The base for serving a file.
2016-08-05 02:35:37 +00:00
* @param string $data
* @param string $mime
* @param string $name
2016-03-27 21:18:57 +00:00
* @return string
*/
private function serve($data, $mime, $name)
2016-02-15 21:20:46 +00:00
{
2016-03-27 21:18:57 +00:00
header("Content-Disposition: inline; filename={$name}");
header("Content-Type: {$mime}");
2016-02-15 21:20:46 +00:00
return $data;
}
2016-03-27 21:18:57 +00:00
/**
2016-09-13 22:05:03 +00:00
* Handles file uploads.
* @param string $mode
* @param array $file
* @return array
2016-03-27 21:18:57 +00:00
*/
2016-09-13 22:05:03 +00:00
private function upload($mode, $file, $user)
2016-02-15 21:20:46 +00:00
{
2016-09-13 22:05:03 +00:00
// Handle errors
switch ($file['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new FileException("Your file was too large!");
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
case UPLOAD_ERR_PARTIAL:
throw new FileException("The upload failed!");
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
case UPLOAD_ERR_NO_TMP_DIR:
case UPLOAD_ERR_CANT_WRITE:
throw new FileException("Wasn't able to save the file, contact a staff member!");
case UPLOAD_ERR_EXTENSION:
default:
throw new FileException("Something prevented the file upload!");
2016-02-15 21:20:46 +00:00
}
2016-09-13 22:05:03 +00:00
// Get the temp filename
$tmpName = $file['tmp_name'];
// Get the image meta data
$meta = getimagesize($tmpName);
// Check if image
if (!$meta
|| (
$meta[2] !== IMAGETYPE_GIF
&& $meta[2] !== IMAGETYPE_JPEG
&& $meta[2] !== IMAGETYPE_PNG
)
) {
throw new FileException("Please upload a valid image!");
2016-02-15 21:20:46 +00:00
}
2016-09-13 22:05:03 +00:00
// Check dimensions
$maxWidth = config("file.{$mode}.max_width");
$maxHeight = config("file.{$mode}.max_height");
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
if ($meta[0] > $maxWidth
|| $meta[1] > $maxHeight) {
throw new FileException("Your image can't be bigger than {$maxWidth}x{$maxHeight}" .
", yours was {$meta[0]}x{$meta[1]}!");
2016-02-15 21:20:46 +00:00
}
2016-09-13 22:05:03 +00:00
// Check file size
$maxFileSize = config("file.{$mode}.max_file_size");
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
if (filesize($tmpName) > $maxFileSize) {
$maxSizeFmt = byte_symbol($maxFileSize);
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
throw new FileException("Your image is not allowed to be larger than {$maxSizeFmt}!");
2016-02-15 21:20:46 +00:00
}
2016-09-13 22:05:03 +00:00
$userId = $user->id;
$ext = image_type_to_extension($meta[2]);
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
$filename = "{$mode}_{$userId}{$ext}";
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
// Create the file
$file = File::create(file_get_contents($tmpName), $filename, $user);
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
// Delete the old file
$this->delete($mode, $user);
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
$column = "user_{$mode}";
// Save new avatar
DB::table('users')
->where('user_id', $user->id)
->update([
$column => $file->id,
]);
2016-02-15 21:20:46 +00:00
}
2016-03-27 21:18:57 +00:00
/**
2016-09-13 22:05:03 +00:00
* Deletes a file.
* @param string $mode
*/
public function delete($mode, $user)
{
$fileId = $user->{$mode};
if ($fileId) {
(new File($fileId))->delete();
}
}
/**
* Catchall serve.
* @param string $method
* @param array $params
* @todo add a specific permission for mods to override uploads.
2016-03-27 21:18:57 +00:00
* @return string
*/
2016-09-13 22:05:03 +00:00
public function __call($method, $params)
2016-02-15 21:20:46 +00:00
{
2016-09-13 22:05:03 +00:00
if (!in_array($method, self::MODES)) {
throw new HttpRouteNotFoundException;
}
2016-02-15 21:20:46 +00:00
2016-09-13 22:05:03 +00:00
$user = User::construct($params[0] ?? 0);
if (session_check()) {
2016-09-16 19:57:51 +00:00
if (!CurrentSession::$user->permission(Manage::CHANGE_IMAGES, Perms::MANAGE)
2016-09-13 22:05:03 +00:00
&& ($user->id !== CurrentSession::$user->id
|| !$user->permission(constant("Sakura\Perms\Site::CHANGE_" . strtoupper($method)))
|| $user->permission(Site::DEACTIVATED)
|| $user->permission(Site::RESTRICTED))
) {
throw new HttpMethodNotAllowedException;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$error = null;
try {
$this->upload($method, $_FILES['file'] ?? null, $user);
} catch (FileException $e) {
$error = $e->getMessage();
}
return $this->json(compact('error'));
} elseif ($_SERVER['REQUEST_METHOD'] === 'DELETE') {
$this->delete($method, $user);
return;
}
2016-02-15 21:20:46 +00:00
}
2016-09-13 22:05:03 +00:00
$noFile = ROOT . 'public/' . str_replace(
'%tplname%',
Template::$name,
config("user.{$method}_none")
);
$none = [
'name' => basename($noFile),
'data' => file_get_contents($noFile),
'mime' => getimagesizefromstring($noFile)['mime'],
];
2016-02-15 21:20:46 +00:00
2016-03-27 21:18:57 +00:00
if ($user->permission(Site::DEACTIVATED)
|| $user->permission(Site::RESTRICTED)
2016-09-13 22:05:03 +00:00
|| !$user->{$method}) {
2016-03-27 21:18:57 +00:00
return $this->serve($none['data'], $none['mime'], $none['name']);
2016-02-15 21:20:46 +00:00
}
2016-09-13 22:05:03 +00:00
$serve = new File($user->{$method});
2016-02-15 21:20:46 +00:00
if (!$serve->id) {
2016-03-27 21:18:57 +00:00
return $this->serve($none['data'], $none['mime'], $none['name']);
2016-02-15 21:20:46 +00:00
}
2016-03-27 21:18:57 +00:00
return $this->serve($serve->data, $serve->mime, $serve->name);
2016-02-15 21:20:46 +00:00
}
}