Merge branch '5.3' into 5.4
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 6 Jul 2021 10:47:52 +0000 (12:47 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 6 Jul 2021 10:47:52 +0000 (12:47 +0200)
1  2 
wcfsetup/install/files/lib/system/style/FontManager.class.php

index 0799dcc33c81bbf0e61fb1a3ff21cfbb1cdbd26d,92e57e07919b3cc887156e03ad7229d7c55872d1..58466c4c874ce254d96b2e7cf6b71c0aae6268e4
@@@ -16,147 -13,110 +16,147 @@@ use wcf\util\JSON
  
  /**
   * Manages webfont families.
 - * 
 - * @author    Tim Duesterhus
 - * @copyright 2001-2020 WoltLab GmbH
 - * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 - * @package   WoltLabSuite\Core\System\Style
 - * @since     5.3
 + *
 + * @author  Tim Duesterhus
 + * @copyright   2001-2020 WoltLab GmbH
 + * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 + * @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/',
 -                      'timeout' => 10,
 -              ]);
 -      }
 -      
 -      /**
 -       * 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/<family> and
 -       * returns the decoded font manifest.
 -       * 
 -       * @param       string  $family
 -       * @return      mixed[]
 -       */
 -      public function downloadFamily($family) {
 -              try {
 -                      $response = $this->http->send(new Request('GET', \rawurlencode($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', \rawurlencode($family) . '/' . \rawurlencode($filename)), [
 -                                      // https://github.com/guzzle/guzzle/issues/2735
 -                                      'sink' => \GuzzleHttp\Psr7\stream_for(fopen("php://temp", "w+")),
 -                              ]);
 -                              
 -                              $file = new AtomicWriter($familyDirectory.'/'.$filename);
 -                              while (!$response->getBody()->eof()) {
 -                                      $file->write($response->getBody()->read(8192));
 -                              }
 -                              $response->getBody()->close();
 -                              $file->flush();
 -                              $file->close();
 -                              
 -                              $css = str_replace('url("' . $filename . '")', 'url(getFont("'.rawurlencode($filename).'", "'.rawurlencode($family).'", "'.TIME_NOW.'"))', $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);
 -              }
 -      }
 +class FontManager extends SingletonFactory
 +{
 +    /**
 +     * @var ClientInterface
 +     */
 +    protected $http;
 +
 +    /**
 +     * @inheritDoc
 +     */
 +    protected function init()
 +    {
 +        $this->http = HttpFactory::makeClient([
 +            'base_uri' => 'https://fonts.woltlab.com/',
 +            RequestOptions::TIMEOUT => 10,
 +        ]);
 +    }
 +
 +    /**
 +     * 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  bool
 +     */
 +    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/<family> 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'));
++            $response = $this->http->send(new Request('GET', \rawurlencode($family) . '/manifest.json'));
 +            $manifest = JSON::decode($response->getBody());
 +
 +            $familyDirectory = \dirname($this->getCssFilename($family));
 +            FileUtil::makePath($familyDirectory);
 +
 +            $css = $manifest['css'];
 +
 +            $preload = [];
 +            if (isset($manifest['preload']) && \is_array($manifest['preload'])) {
 +                $preload = $manifest['preload'];
 +            }
 +
 +            $preloadRequests = "";
 +            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));
++                $response = $this->http->send(new Request('GET', \rawurlencode($family) . '/' . \rawurlencode($filename)));
 +
 +                $file = new AtomicWriter($familyDirectory . '/' . $filename);
 +                while (!$response->getBody()->eof()) {
 +                    $file->write($response->getBody()->read(8192));
 +                }
 +                $response->getBody()->close();
 +                $file->flush();
 +                $file->close();
 +
 +                $css = \str_replace(
 +                    'url("' . $filename . '")',
 +                    \sprintf(
 +                        'url(getFont("%s", "%s", "%d"))',
 +                        \rawurlencode($filename),
 +                        \rawurlencode($family),
 +                        TIME_NOW
 +                    ),
 +                    $css
 +                );
 +
 +                if (\in_array($filename, $preload)) {
 +                    $preloadRequests .= \sprintf(
 +                        <<<'EOT'
 +                    --woltlab-suite-preload: #{preload(
 +                        %s,
 +                        $as: "font",
 +                        $crossorigin: true
 +                    )};
 +EOT
 +                        ,
 +                        \sprintf(
 +                            'getFont("%s", "%s", "%d")',
 +                            \rawurlencode($filename),
 +                            \rawurlencode($family),
 +                            TIME_NOW
 +                        )
 +                    );
 +                }
 +            }
 +
 +            $css .= "woltlab-suite-preload:root { {$preloadRequests} }";
 +
 +            \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);
 +        }
 +    }
  }