[AVATAR] Handle avatar upload without js and save and validate uploaded files

This commit is contained in:
Hugo Sales 2020-08-07 02:08:55 +00:00 committed by Hugo Sales
parent 48971b70a0
commit 2bf914f96f
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0

View File

@ -1,7 +1,6 @@
<?php <?php
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
// GNU social is free software: you can redistribute it and/or modify // GNU social is free software: you can redistribute it and/or modify
@ -16,7 +15,6 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
// }}} // }}}
/** /**
@ -39,8 +37,12 @@ use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log;
use App\Entity\File;
use App\Util\ClientException;
use App\Util\Common; use App\Util\Common;
use App\Util\Form\ArrayTransformer; use App\Util\Form\ArrayTransformer;
use Component\Media\Media;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Exception; use Exception;
use Functional as F; use Functional as F;
@ -53,6 +55,7 @@ use Symfony\Component\Form\Extension\Core\Type\LanguageType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\File\File as SymfonyFile;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
// }}} Imports // }}} Imports
@ -100,20 +103,53 @@ class UserPanel extends AbstractController
public function avatar(Request $request) public function avatar(Request $request)
{ {
$avatar = Form::create([ $avatar = Form::create([
['avatar', FileType::class, ['label' => _m('Avatar'), 'help' => _m('You can upload your personal avatar. The maximum file size is 2MB.')]], ['avatar', FileType::class, ['label' => _m('Avatar'), 'help' => _m('You can upload your personal avatar. The maximum file size is 2MB.')]],
['hidden', HiddenType::class, []], ['hidden', HiddenType::class, []],
['save', SubmitType::class, ['label' => _m('Submit')]], ['save', SubmitType::class, ['label' => _m('Submit')]],
]); ]);
$avatar->handleRequest($request); $avatar->handleRequest($request);
if ($avatar->isSubmitted() && $avatar->isValid()) { if ($avatar->isSubmitted() && $avatar->isValid()) {
$data = $avatar->getData()['hidden']; $data = $avatar->getData();
list($type, $data) = explode(';', $data); $sfile = $file_title = null;
list(, $data) = explode(',', $data); if (isset($data['hidden'])) {
$data = base64_decode($data); // Cropped client side
$matches = [];
file_put_contents('/tmp/image.png', $data); if (!empty(preg_match('/data:([^;]*)(;(base64))?,(.*)/', $data['hidden'], $matches))) {
list(, $mimetype_user, , $encoding_user, $data_user) = $matches;
if ($encoding_user == 'base64') {
$data_user = base64_decode($data_user);
$tmp_file = tmpfile();
fwrite($tmp_file, $data_user);
try {
$sfile = new SymfonyFile(stream_get_meta_data($tmp_file)['uri']);
$file_title = $data['avatar']->getFilename();
} finally {
fclose($tmp_file);
}
} else {
Log::info('Avatar upload got an invalid encoding, something\'s fishy and/or wrong');
}
}
} elseif (isset($data['avatar'])) {
// Cropping failed (e.g. disabled js), have file as uploaded
$sfile = $data['avatar'];
} else {
throw new ClientException('Invalid form');
}
try {
$profile_id = Common::user()->getProfile()->getId();
$file = Media::validateAndStoreFile($sfile, Common::config('avatar', 'dir'), $file_title);
$fs_files_to_delete = DB::find('avatar', ['profile_id' => $profile_id])->delete();
DB::persist(Avatar::create(['profile_id' => $profile_id, 'file_id' => $file->getId()]));
DB::persist($file);
DB::flush();
// Only delete files if the commit went through
File::deleteFiles($fs_files_to_delete);
} catch (Exception $e) {
throw $e;
}
} }
return ['_template' => 'settings/avatar.html.twig', 'avatar' => $avatar->createView()]; return ['_template' => 'settings/avatar.html.twig', 'avatar' => $avatar->createView()];