From 114dbb4022defc62e882b0c5c9ed9f2d99825b46 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Wed, 15 Jul 2020 11:24:12 +0200 Subject: [PATCH] Add FontManager see #3394 --- .../lib/system/style/FontManager.class.php | 118 ++++++++++++++++++ .../exception/FontDownloadFailed.class.php | 31 +++++ 2 files changed, 149 insertions(+) create mode 100644 wcfsetup/install/files/lib/system/style/FontManager.class.php create mode 100644 wcfsetup/install/files/lib/system/style/exception/FontDownloadFailed.class.php diff --git a/wcfsetup/install/files/lib/system/style/FontManager.class.php b/wcfsetup/install/files/lib/system/style/FontManager.class.php new file mode 100644 index 0000000000..0e2907876d --- /dev/null +++ b/wcfsetup/install/files/lib/system/style/FontManager.class.php @@ -0,0 +1,118 @@ + + * @package WoltLabSuite\Core\System\Style + * @since 5.3 + */ +class FontManager extends SingletonFactory { + /** + * @var ClientInterface + */ + protected $http; + + /** + * @inheritDoc + */ + protected function init() { + $this->http = HttpFactory::makeClient([ + 'base_uri' => 'https://fonts.woltlab.com/' + ]); + } + + /** + * Returns the path to the family's CSS file. + * + * @return string + */ + public function getCssFilename($family) { + return WCF_DIR.'font/families/'.$family.'/font.css'; + } + + /** + * Returns whether the family's CSS file exists, implying that + * the family is available. + * + * @return boolean + */ + public function isFamilyDownloaded($family) { + return is_readable($this->getCssFilename($family)); + } + + /** + * Fetch the list of available families and returns it as an array. + * + * @return string[] + */ + public function fetchAvailableFamilies() { + $response = $this->http->send(new Request('GET', 'families.json')); + return JSON::decode($response->getBody()); + } + + /** + * Downloads the given font family, stores it in font/families/ and + * returns the decoded font manifest. + * + * @param string $family + * @return mixed[] + */ + public function downloadFamily($family) { + try { + $response = $this->http->send(new Request('GET', $family.'/manifest.json')); + $manifest = JSON::decode($response->getBody()); + + $familyDirectory = dirname($this->getCssFilename($family)); + FileUtil::makePath($familyDirectory); + + $css = $manifest['css']; + + foreach ($manifest['font_files'] as $filename) { + if ($filename !== basename($filename)) { + throw new \InvalidArgumentException("Invalid filename '".$filename."' given."); + } + + $response = $this->http->send(new Request('GET', $family.'/'.$filename)); + + $file = new AtomicWriter($familyDirectory.'/'.$filename); + while (!$response->getBody()->eof()) { + $file->write($response->getBody()->read(4096)); + } + $response->getBody()->close(); + $file->flush(); + $file->close(); + + $css = str_replace('url("' . $filename . '")', 'url("../font/getFont.php?family='.rawurlencode($family).'&filename='.rawurlencode($filename).'")', $css); + } + + file_put_contents($this->getCssFilename($family), $css); + + return $manifest; + } + catch (ClientException $e) { + if ($e->getResponse()->getStatusCode() == 404) { + throw new FontDownloadFailed("Unable to download font family '".$family."'.", 'notFound', $e); + } + else { + throw new FontDownloadFailed("Unable to download font family '".$family."'.", '', $e); + } + } + catch (RequestException $e) { + throw new FontDownloadFailed("Unable to download font family '".$family."'.", '', $e); + } + } +} diff --git a/wcfsetup/install/files/lib/system/style/exception/FontDownloadFailed.class.php b/wcfsetup/install/files/lib/system/style/exception/FontDownloadFailed.class.php new file mode 100644 index 0000000000..0d9c6eedd8 --- /dev/null +++ b/wcfsetup/install/files/lib/system/style/exception/FontDownloadFailed.class.php @@ -0,0 +1,31 @@ + + * @package WoltLabSuite\Core\System\Style + * @since 5.3 + */ +class FontDownloadFailed extends \Exception { + /** + * @var string + */ + private $reason = ''; + + public function __construct($message, $reason = '', \Throwable $previous = null) { + parent::__construct($message, 0, $previous); + + $this->reason = $reason; + } + + /** + * @return string + */ + public function getReason() { + return $this->reason; + } +} -- 2.20.1