| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // {{{ License
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 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/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // }}}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Component\Media; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use App\Core\Cache; | 
					
						
							|  |  |  | use App\Core\DB\DB; | 
					
						
							|  |  |  | use function App\Core\I18n\_m; | 
					
						
							|  |  |  | use App\Core\Log; | 
					
						
							|  |  |  | use App\Entity\Avatar; | 
					
						
							|  |  |  | use App\Entity\File; | 
					
						
							|  |  |  | use App\Util\Common; | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  | use Component\Media\Exception\NoAvatarException; | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  | use Exception; | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  | use Symfony\Component\Asset\Package; | 
					
						
							|  |  |  | use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy; | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  | use Symfony\Component\HttpFoundation\BinaryFileResponse; | 
					
						
							|  |  |  | use Symfony\Component\HttpFoundation\File\File as SymfonyFile; | 
					
						
							|  |  |  | use Symfony\Component\HttpFoundation\HeaderUtils; | 
					
						
							|  |  |  | use Symfony\Component\HttpFoundation\Response; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | abstract class Utils | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     public static function validateAndStoreFile(SymfonyFile $sfile, | 
					
						
							|  |  |  |                                                 string $dest_dir, | 
					
						
							|  |  |  |                                                 ?string $title = null, | 
					
						
							|  |  |  |                                                 bool $is_local = true, | 
					
						
							|  |  |  |                                                 ?int $actor_id = null): File | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // The following properly gets the mimetype with `file` or other
 | 
					
						
							|  |  |  |         // available methods, so should be safe
 | 
					
						
							|  |  |  |         $hash = hash_file(File::FILEHASH_ALGO, $sfile->getPathname()); | 
					
						
							|  |  |  |         $file = File::create([ | 
					
						
							|  |  |  |             'file_hash' => $hash, | 
					
						
							| 
									
										
										
										
											2020-08-15 05:15:36 +00:00
										 |  |  |             'actor_id'  => $actor_id, | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  |             'mimetype'  => $sfile->getMimeType(), | 
					
						
							|  |  |  |             'title'     => $title ?: _m('Untitled attachment'), | 
					
						
							|  |  |  |             'is_local'  => $is_local, | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |         $sfile->move($dest_dir, $hash); | 
					
						
							|  |  |  |         // TODO Normalize file types
 | 
					
						
							|  |  |  |         return $file; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Include $filepath in the response, for viewing or downloading. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws ServerException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function sendFile(string $filepath, string $mimetype, ?string $output_filename, string $disposition = 'inline'): Response | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $response = new BinaryFileResponse( | 
					
						
							|  |  |  |             $filepath, | 
					
						
							|  |  |  |             Response::HTTP_OK, | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 'Content-Description' => 'File Transfer', | 
					
						
							|  |  |  |                 'Content-Type'        => $mimetype, | 
					
						
							|  |  |  |                 'Content-Disposition' => HeaderUtils::makeDisposition($disposition, $output_filename ?: _m('untitled')), | 
					
						
							| 
									
										
										
										
											2020-09-05 21:18:21 +00:00
										 |  |  |                 'Cache-Control'       => 'public', | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  |             ], | 
					
						
							|  |  |  |             $public = true, | 
					
						
							|  |  |  |             $disposition = null, | 
					
						
							|  |  |  |             $add_etag = true, | 
					
						
							|  |  |  |             $add_last_modified = true | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         if (Common::config('site', 'x_static_delivery')) { | 
					
						
							|  |  |  |             $response->trustXSendfileTypeHeader(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $response; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 02:28:50 +00:00
										 |  |  |     public static function error($except, $id, array $res) | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  |         switch (count($res)) { | 
					
						
							|  |  |  |         case 0: | 
					
						
							| 
									
										
										
										
											2020-09-05 02:28:50 +00:00
										 |  |  |             throw new $except(); | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  |         case 1: | 
					
						
							|  |  |  |             return $res[0]; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2020-09-05 02:28:50 +00:00
										 |  |  |             Log::error('Media query returned more than one result for identifier: \"' . $id . '\"'); | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  |             throw new Exception(_m('Internal server error')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function getAvatar(string $nickname) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-09-05 02:28:50 +00:00
										 |  |  |         return self::error(NoAvatarException::class, | 
					
						
							|  |  |  |                            $nickname, | 
					
						
							|  |  |  |                            Cache::get("avatar-{$nickname}", | 
					
						
							|  |  |  |                                       function () use ($nickname) { | 
					
						
							|  |  |  |                                           return DB::dql('select a from App\\Entity\\Avatar a ' . | 
					
						
							|  |  |  |                                                          'join App\Entity\GSActor g with a.gsactor_id = g.id ' . | 
					
						
							|  |  |  |                                                          'where g.nickname = :nickname', | 
					
						
							|  |  |  |                                                          ['nickname' => $nickname]); | 
					
						
							|  |  |  |                                       })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function getFileInfo(int $id) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return self::error(NoSuchFileException::class, | 
					
						
							|  |  |  |                            $id, | 
					
						
							|  |  |  |                            Cache::get("file-info-{$id}", | 
					
						
							|  |  |  |                                       function () use ($id) { | 
					
						
							|  |  |  |                                           return DB::dql('select f.file_hash, f.mimetype, f.title ' . | 
					
						
							|  |  |  |                                                          'from App\\Entity\\File f ' . | 
					
						
							|  |  |  |                                                          'where f.id = :id', | 
					
						
							|  |  |  |                                                          ['id' => $id]); | 
					
						
							|  |  |  |                                       })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function getAttachmentFileInfo(int $id) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $res              = self::getFileInfo($id); | 
					
						
							|  |  |  |         $res['file_path'] = Common::config('attachments', 'dir') . $res['file_hash']; | 
					
						
							|  |  |  |         return $res; | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function getAvatarFileInfo(string $nickname) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         try { | 
					
						
							| 
									
										
										
										
											2020-09-05 02:28:50 +00:00
										 |  |  |             $res = self::error(NoAvatarException::class, | 
					
						
							|  |  |  |                                $nickname, | 
					
						
							|  |  |  |                                Cache::get("avatar-file-info-{$nickname}", | 
					
						
							|  |  |  |                                           function () use ($nickname) { | 
					
						
							|  |  |  |                                               return DB::dql('select f.file_hash, f.mimetype, f.title ' . | 
					
						
							|  |  |  |                                                              'from App\\Entity\\File f ' . | 
					
						
							|  |  |  |                                                              'join App\\Entity\\Avatar a with f.id = a.file_id ' . | 
					
						
							|  |  |  |                                                              'join App\\Entity\\GSActor g with g.id = a.gsactor_id ' . | 
					
						
							|  |  |  |                                                              'where g.nickname = :nickname', | 
					
						
							|  |  |  |                                                              ['nickname' => $nickname]); | 
					
						
							|  |  |  |                                           })); | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  |             $res['file_path'] = Avatar::getFilePathStatic($res['file_hash']); | 
					
						
							|  |  |  |             return $res; | 
					
						
							|  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |             $filepath = INSTALLDIR . '/public/assets/default-avatar.svg'; | 
					
						
							|  |  |  |             return ['file_path' => $filepath, 'mimetype' => 'image/svg+xml', 'title' => null]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 00:40:52 +00:00
										 |  |  |     public static function getAvatarUrl(?string $nickname = null) | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if ($nickname == null) { | 
					
						
							|  |  |  |             $user = Common::user(); | 
					
						
							|  |  |  |             if ($user != null) { | 
					
						
							|  |  |  |                 $nickname = $user->getNickname(); | 
					
						
							| 
									
										
										
										
											2020-08-20 00:40:52 +00:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 throw new Exception('No user is logged in and no avatar provided to `getAvatarUrl`'); | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-09-05 02:28:50 +00:00
										 |  |  |         return Cache::get("avatar-url-{$nickname}", function () use ($nickname) { | 
					
						
							| 
									
										
										
										
											2020-08-19 15:31:52 +00:00
										 |  |  |             try { | 
					
						
							|  |  |  |                 return self::getAvatar($nickname)->getUrl(); | 
					
						
							|  |  |  |             } catch (NoAvatarException $e) { | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $package = new Package(new EmptyVersionStrategy()); | 
					
						
							|  |  |  |             return $package->getUrl(Common::config('avatar', 'default')); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-14 22:34:58 +00:00
										 |  |  | } |