CustomEmojiService.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. namespace App\Services;
  3. use App\Models\CustomEmoji;
  4. use App\Util\ActivityPub\Helpers;
  5. use Illuminate\Support\Facades\Http;
  6. use Illuminate\Support\Facades\Cache;
  7. use Illuminate\Support\Facades\Storage;
  8. use Illuminate\Http\Client\RequestException;
  9. class CustomEmojiService
  10. {
  11. public static function get($shortcode)
  12. {
  13. if(config('federation.custom_emoji.enabled') == false) {
  14. return;
  15. }
  16. return CustomEmoji::whereShortcode($shortcode)->first();
  17. }
  18. public static function import($url, $id = false)
  19. {
  20. if(config('federation.custom_emoji.enabled') == false) {
  21. return;
  22. }
  23. if(Helpers::validateUrl($url) == false) {
  24. return;
  25. }
  26. $emoji = CustomEmoji::whereUri($url)->first();
  27. if($emoji) {
  28. return;
  29. }
  30. try {
  31. $res = Http::acceptJson()->get($url);
  32. } catch (RequestException $e) {
  33. return;
  34. } catch (\Exception $e) {
  35. return;
  36. }
  37. if($res->successful()) {
  38. $json = $res->json();
  39. if(
  40. !$json ||
  41. !isset($json['id']) ||
  42. !isset($json['type']) ||
  43. $json['type'] !== 'Emoji' ||
  44. !isset($json['icon']) ||
  45. !isset($json['icon']['mediaType']) ||
  46. !isset($json['icon']['url']) ||
  47. !isset($json['icon']['type']) ||
  48. $json['icon']['type'] !== 'Image' ||
  49. !in_array($json['icon']['mediaType'], ['image/jpeg', 'image/png', 'image/jpg'])
  50. ) {
  51. return;
  52. }
  53. if(!self::headCheck($json['icon']['url'])) {
  54. return;
  55. }
  56. $emoji = CustomEmoji::firstOrCreate([
  57. 'shortcode' => $json['name'],
  58. 'domain' => parse_url($json['id'], PHP_URL_HOST)
  59. ], [
  60. 'uri' => $json['id'],
  61. 'image_remote_url' => $json['icon']['url']
  62. ]);
  63. if($emoji->wasRecentlyCreated == false) {
  64. if(Storage::exists('public/' . $emoji->media_path)) {
  65. Storage::delete('public/' . $emoji->media_path);
  66. }
  67. }
  68. $ext = '.' . last(explode('/', $json['icon']['mediaType']));
  69. $dest = storage_path('app/public/emoji/') . $emoji->id . $ext;
  70. copy($json['icon']['url'], $dest);
  71. $emoji->media_path = 'emoji/' . $emoji->id . $ext;
  72. $emoji->save();
  73. $name = str_replace(':', '', $json['name']);
  74. Cache::forget('pf:custom_emoji');
  75. Cache::forget('pf:custom_emoji:' . $name);
  76. if($id) {
  77. StatusService::del($id);
  78. }
  79. return;
  80. } else {
  81. return;
  82. }
  83. }
  84. public static function headCheck($url)
  85. {
  86. try {
  87. $res = Http::head($url);
  88. } catch (RequestException $e) {
  89. return false;
  90. } catch (\Exception $e) {
  91. return false;
  92. }
  93. if(!$res->successful()) {
  94. return false;
  95. }
  96. $type = $res->header('content-type');
  97. $length = $res->header('content-length');
  98. if(
  99. !$type ||
  100. !$length ||
  101. !in_array($type, ['image/jpeg', 'image/png', 'image/jpg']) ||
  102. $length > config('federation.custom_emoji.max_size')
  103. ) {
  104. return false;
  105. }
  106. return true;
  107. }
  108. public static function all()
  109. {
  110. return Cache::rememberForever('pf:custom_emoji', function() {
  111. $pgsql = config('database.default') === 'pgsql';
  112. return CustomEmoji::when(!$pgsql, function($q, $pgsql) {
  113. return $q->groupBy('shortcode');
  114. })
  115. ->get()
  116. ->map(function($emojo) {
  117. $url = url('storage/' . $emojo->media_path);
  118. return [
  119. 'shortcode' => str_replace(':', '', $emojo->shortcode),
  120. 'url' => $url,
  121. 'static_url' => $url,
  122. 'visible_in_picker' => $emojo->disabled == false
  123. ];
  124. })
  125. ->when($pgsql, function($collection) {
  126. return $collection->unique('shortcode');
  127. })
  128. ->toJson(JSON_UNESCAPED_SLASHES);
  129. });
  130. }
  131. }