AppsService.php
2 weeks ago
CollaborationCommentService.php
2 weeks ago
CollaborationService.php
2 weeks ago
CollectionItemService.php
2 weeks ago
CollectionService.php
2 weeks ago
EditorService.php
2 weeks ago
FontService.php
2 weeks ago
MediaService.php
2 weeks ago
PageService.php
2 weeks ago
PageSettingsService.php
2 weeks ago
UtilityPageService.php
2 weeks ago
FontService.php
172 lines
| 1 | <?php |
| 2 | |
| 3 | namespace Kirki\App\Services; |
| 4 | |
| 5 | use Exception; |
| 6 | use Kirki\App\DTO\GoogleFontDTO; |
| 7 | use Kirki\App\Supports\Facades\GlobalData; |
| 8 | use Kirki\Framework\Http\Response; |
| 9 | use Kirki\Framework\Supports\Facades\File; |
| 10 | use Kirki\Framework\Supports\Facades\Http; |
| 11 | |
| 12 | use function Kirki\App\get_upload_directory; |
| 13 | use function Kirki\App\get_upload_directory_url; |
| 14 | |
| 15 | defined('ABSPATH') || exit; |
| 16 | |
| 17 | class FontService |
| 18 | { |
| 19 | public static function create() |
| 20 | { |
| 21 | return new static(); |
| 22 | } |
| 23 | |
| 24 | public function download_google_font(GoogleFontDTO $payload) |
| 25 | { |
| 26 | // Extra security: keep only a-z, 0-9, and hyphens |
| 27 | $font_family_slug = preg_replace('/[^a-z0-9\-]/i', '', sanitize_title_with_dashes($payload->family)); |
| 28 | |
| 29 | if (empty($font_family_slug) || strpos($font_family_slug, '..') !== false) { |
| 30 | throw new Exception(esc_html__('Not valid font family.', 'kirki'), Response::FORBIDDEN); |
| 31 | } |
| 32 | |
| 33 | $has_write_permission = File::is_writable(get_upload_directory()); |
| 34 | |
| 35 | if (!$has_write_permission) { |
| 36 | throw new Exception(esc_html__('Upload directory is not writable.', 'kirki'), Response::FORBIDDEN); |
| 37 | } |
| 38 | |
| 39 | $font_dir = get_upload_directory() . "/kirki-fonts/{$font_family_slug}"; |
| 40 | $css_file_path = $font_dir . "/{$font_family_slug}.css"; |
| 41 | |
| 42 | if (File::exists($css_file_path)) { |
| 43 | throw new Exception(esc_html__('Font already downloaded.', 'kirki'), Response::FORBIDDEN); |
| 44 | } |
| 45 | |
| 46 | if (stripos($payload->fontUrl, 'fonts.googleapis.com') === false) { |
| 47 | throw new Exception(esc_html__('Only Google Fonts is supported.', 'kirki'), Response::FORBIDDEN); |
| 48 | } |
| 49 | |
| 50 | try { |
| 51 | if (!File::is_directory($font_dir)) { |
| 52 | File::make_dir($font_dir); |
| 53 | } |
| 54 | |
| 55 | $css = Http::get($payload->fontUrl); |
| 56 | |
| 57 | if ($css->failed()) { |
| 58 | throw new Exception(esc_html__('Failed to fetch Google Fonts CSS.', 'kirki')); |
| 59 | } |
| 60 | |
| 61 | if (isset($payload->files['regular'])) { |
| 62 | $payload->files['400'] = $payload->files['regular']; |
| 63 | unset($payload->files['regular']); |
| 64 | } |
| 65 | |
| 66 | $formats = [ |
| 67 | 'woff2' => 'woff2', |
| 68 | 'woff' => 'woff', |
| 69 | 'ttf' => 'truetype', |
| 70 | 'otf' => 'opentype', |
| 71 | ]; |
| 72 | $local_css = ''; |
| 73 | |
| 74 | foreach ($payload->files as $weight => $url) { |
| 75 | $allowed_ext = array_keys($formats); |
| 76 | $extension = strtolower(pathinfo($url, PATHINFO_EXTENSION)); |
| 77 | |
| 78 | if (!in_array($extension, $allowed_ext, true)) { |
| 79 | /* translators: %s: file extension */ |
| 80 | throw new Exception(esc_html(sprintf(__('Invalid or unsafe file extension: %s.', 'kirki'), $extension))); |
| 81 | } |
| 82 | |
| 83 | $file_name = "{$weight}.{$extension}"; |
| 84 | $file_path = $font_dir . '/' . $file_name; |
| 85 | |
| 86 | $font_data = Http::get($url); |
| 87 | |
| 88 | if ($font_data->failed()) { |
| 89 | throw new Exception(esc_html__('Failed to fetch font file.', 'kirki')); |
| 90 | } |
| 91 | |
| 92 | File::put($file_path, $font_data->__toString()); |
| 93 | |
| 94 | $format = $formats[$extension] ?? 'truetype'; |
| 95 | $local_css .= "@font-face { |
| 96 | font-family: '{$payload->family}'; |
| 97 | font-style: normal; |
| 98 | font-weight: {$weight}; |
| 99 | font-display: swap; |
| 100 | src: url('{$file_name}') format('{$format}'); |
| 101 | }\n"; |
| 102 | } |
| 103 | |
| 104 | if (empty($local_css)) { |
| 105 | throw new Exception(esc_html__('No usable font files were downloaded.', 'kirki')); |
| 106 | } |
| 107 | |
| 108 | File::put($css_file_path, $local_css); |
| 109 | $payload->localUrl = get_upload_directory_url() . "/kirki-fonts/{$font_family_slug}/{$font_family_slug}.css"; |
| 110 | |
| 111 | $this->save_google_font_into_global_custom_fonts($payload); |
| 112 | |
| 113 | return $payload; |
| 114 | |
| 115 | } catch (Exception $exception) { |
| 116 | if (File::is_directory($font_dir)) { |
| 117 | File::delete($font_dir); |
| 118 | } |
| 119 | |
| 120 | throw $exception; |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | public function remove_google_font(GoogleFontDTO $payload) { |
| 125 | $font_family_slug = sanitize_title_with_dashes( basename( $payload->family ) ); |
| 126 | $font_dir = get_upload_directory() . "/kirki-fonts/{$font_family_slug}"; |
| 127 | |
| 128 | if (File::is_directory($font_dir)) { |
| 129 | File::delete($font_dir); |
| 130 | } |
| 131 | |
| 132 | $payload->exclude(['localUrl']); |
| 133 | |
| 134 | $this->save_google_font_into_global_custom_fonts($payload); |
| 135 | |
| 136 | return true; |
| 137 | } |
| 138 | |
| 139 | protected function save_google_font_into_global_custom_fonts(GoogleFontDTO $font) { |
| 140 | // first get the font data |
| 141 | $custom_fonts = GlobalData::get_global_custom_fonts(); |
| 142 | |
| 143 | if (empty($custom_fonts)) { |
| 144 | $custom_fonts = []; |
| 145 | } |
| 146 | |
| 147 | if (!empty($font->family)) { |
| 148 | $custom_fonts[$font->family] = $font->to_array(); |
| 149 | |
| 150 | GlobalData::update_global_custom_fonts($custom_fonts); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | public function remove_custom_fonts_permanently(array $fonts) |
| 155 | { |
| 156 | foreach ($fonts as $font) { |
| 157 | $upload_dir = get_upload_directory() . '/kirki-fonts/' . $font['family']; |
| 158 | |
| 159 | if (File::is_directory($upload_dir)) { |
| 160 | File::delete($upload_dir); |
| 161 | } |
| 162 | |
| 163 | // Remove font from local. |
| 164 | $font_family_slug = sanitize_title_with_dashes($font['family']); |
| 165 | $font_local_dir = get_upload_directory() . "/kirki-fonts/{$font_family_slug}"; |
| 166 | |
| 167 | if (File::is_directory($font_local_dir)) { |
| 168 | File::delete($font_local_dir); |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | } |