CustomEmojiService.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. class CustomEmojiService
  8. {
  9. public static function get($shortcode)
  10. {
  11. if(config('federation.custom_emoji.enabled') == false) {
  12. return;
  13. }
  14. return CustomEmoji::whereShortcode($shortcode)->first();
  15. }
  16. public static function import($url, $id = false)
  17. {
  18. if(config('federation.custom_emoji.enabled') == false) {
  19. return;
  20. }
  21. if(Helpers::validateUrl($url) == false) {
  22. return;
  23. }
  24. $emoji = CustomEmoji::whereUri($url)->first();
  25. if($emoji) {
  26. return;
  27. }
  28. $res = Http::acceptJson()->get($url);
  29. if($res->successful()) {
  30. $json = $res->json();
  31. if(
  32. !$json ||
  33. !isset($json['id']) ||
  34. !isset($json['type']) ||
  35. $json['type'] !== 'Emoji' ||
  36. !isset($json['icon']) ||
  37. !isset($json['icon']['mediaType']) ||
  38. !isset($json['icon']['url']) ||
  39. !isset($json['icon']['type']) ||
  40. $json['icon']['type'] !== 'Image' ||
  41. !in_array($json['icon']['mediaType'], ['image/jpeg', 'image/png', 'image/jpg'])
  42. ) {
  43. return;
  44. }
  45. if(!self::headCheck($json['icon']['url'])) {
  46. return;
  47. }
  48. $emoji = new CustomEmoji;
  49. $emoji->shortcode = $json['name'];
  50. $emoji->uri = $json['id'];
  51. $emoji->domain = parse_url($json['id'], PHP_URL_HOST);
  52. $emoji->image_remote_url = $json['icon']['url'];
  53. $emoji->save();
  54. $ext = '.' . last(explode('/', $json['icon']['mediaType']));
  55. $dest = storage_path('app/public/emoji/') . $emoji->id . $ext;
  56. copy($emoji->image_remote_url, $dest);
  57. $emoji->media_path = 'emoji/' . $emoji->id . $ext;
  58. $emoji->save();
  59. $name = str_replace(':', '', $json['name']);
  60. Cache::forget('pf:custom_emoji');
  61. Cache::forget('pf:custom_emoji:' . $name);
  62. if($id) {
  63. StatusService::del($id);
  64. }
  65. return;
  66. } else {
  67. return;
  68. }
  69. }
  70. public static function headCheck($url)
  71. {
  72. $res = Http::head($url);
  73. if(!$res->successful()) {
  74. return false;
  75. }
  76. $type = $res->header('content-type');
  77. $length = $res->header('content-length');
  78. if(
  79. !$type ||
  80. !$length ||
  81. !in_array($type, ['image/jpeg', 'image/png', 'image/jpg']) ||
  82. $length > config('federation.custom_emoji.max_size')
  83. ) {
  84. return false;
  85. }
  86. return true;
  87. }
  88. public static function all()
  89. {
  90. return Cache::rememberForever('pf:custom_emoji', function() {
  91. $pgsql = config('database.default') === 'pgsql';
  92. return CustomEmoji::when(!$pgsql, function($q, $pgsql) {
  93. return $q->groupBy('shortcode');
  94. })
  95. ->get()
  96. ->map(function($emojo) {
  97. $url = url('storage/' . $emojo->media_path);
  98. return [
  99. 'shortcode' => str_replace(':', '', $emojo->shortcode),
  100. 'url' => $url,
  101. 'static_path' => $url,
  102. 'visible_in_picker' => $emojo->disabled == false
  103. ];
  104. })
  105. ->when($pgsql, function($collection) {
  106. return $collection->unique('shortcode');
  107. })
  108. ->toJson(JSON_UNESCAPED_SLASHES);
  109. });
  110. }
  111. }