progressive_image_loading-8.x-1.x-dev/src/ProgressiveImageLoadingManager.php

src/ProgressiveImageLoadingManager.php
<?php

namespace Drupal\progressive_image_loading;

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PrivateStream;
use Drupal\Core\StreamWrapper\PublicStream;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * The Progressive Image Loading manager service.
 */
class ProgressiveImageLoadingManager implements ProgressiveImageLoadingManagerInterface {

  /**
   * An alias manager to find the alias for the current system path.
   *
   * @var \Drupal\Core\Path\AliasManagerInterface
   */
  protected $aliasManager;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The current path.
   *
   * @var \Drupal\Core\Path\CurrentPathStack
   */
  protected $currentPath;

  /**
   * The file system.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The image style storage.
   *
   * @var \Drupal\image\ImageStyleStorageInterface
   */
  protected $imageStyleStorage;

  /**
   * The path matcher.
   *
   * @var \Drupal\Core\Path\PathMatcherInterface
   */
  protected $pathMatcher;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The app root.
   *
   * @var string
   */
  protected $root;

  /**
   * Constructs a new ProgressiveImageLoadingManager object.
   *
   * @param string $root
   *   The app root.
   * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
   *   An alias manager to find the alias for the current system path.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Path\CurrentPathStack $current_path
   *   The current path.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
   *   The path matcher service.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function __construct($root, AliasManagerInterface $alias_manager, ConfigFactoryInterface $config_factory, CurrentPathStack $current_path, EntityTypeManagerInterface $entity_type_manager, PathMatcherInterface $path_matcher, RequestStack $request_stack, FileSystemInterface $file_system) {
    $this->aliasManager = $alias_manager;
    $this->configFactory = $config_factory;
    $this->currentPath = $current_path;
    $this->fileSystem = $file_system;
    $this->imageStyleStorage = $entity_type_manager->getStorage('image_style');
    $this->pathMatcher = $path_matcher;
    $this->requestStack = $request_stack;
    $this->root = $root;
  }

  /**
   * {@inheritdoc}
   */
  public function createPlaceholder(string $url, $width = 1, $height = 1) {
    try {
      // Skip inline images or unsupported extensions.
      if (strpos($url, 'data:') === FALSE && $this->isSupportedExtension($url)) {
        $original_uri = $this->buildUri($url);
        // If is an internal uri and exists.
        if (!UrlHelper::isExternal($original_uri) && file_exists($original_uri)) {
          $image_style = $this->imageStyleStorage->load($this->configFactory->get('progressive_image_loading.settings')->get('low_quality_image_style'));
          $derivative_uri = $image_style->buildUri($original_uri);
          // Make sure image style exists.
          if (file_exists($derivative_uri) ||
            (!file_exists($derivative_uri) && $image_style->createDerivative($original_uri, $derivative_uri))) {

            // Returns base64 encoded image or URL.
            if ($this->configFactory->get('progressive_image_loading.settings')->get('inline_image')) {
              $mime = getimagesize($derivative_uri)['mime'];
              $data = base64_encode(file_get_contents($derivative_uri));

              return "data:$mime;base64,$data";
            }

            return file_url_transform_relative($image_style->buildUrl($original_uri));
          }
        }
      }
      elseif (strpos($url, 'data:') !== FALSE) {
        return $url;
      }
    }
    catch (\Exception $exception) {
      // Nothing to do.
    }

    // If we can't generate a placeholder, just return base64 encoded
    // transparent svg.
    return "data:image/svg+xml;charset=utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 1 1%22 width=%22$width%22 height=%22$height%22%3E%3C/svg%3E";
  }

  /**
   * {@inheritdoc}
   */
  public function currentPathIsExcluded() {
    // Convert path to lowercase. This allows comparison of the same path
    // with different case. Ex: /Page, /page, /PAGE.
    $paths = mb_strtolower($this->configFactory->get('progressive_image_loading.settings')->get('excluded_paths'));
    if (empty($paths)) {
      return FALSE;
    }

    $request = $this->requestStack->getCurrentRequest();
    // Compare the lowercase path alias (if any) and internal path.
    $path = $this->currentPath->getPath($request);
    // Do not trim a trailing slash if that is the complete path.
    $path = $path === '/' ? $path : rtrim($path, '/');
    $path_alias = mb_strtolower($this->aliasManager->getAliasByPath($path));

    return ($this->pathMatcher->matchPath($path_alias, $paths) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $paths)));
  }

  /**
   * Returns the URI from the given image URL, relevant for un-managed files.
   *
   * @param string $image_url
   *   The URL to convert into uri.
   *
   * @return string|false
   *   True converted uri.
   */
  protected function buildUri($image_url) {
    // Check if the URL is a valid URI and return it.
    if (preg_match('/public:\/\/|private:\/\//', $image_url)) {
      return $image_url;
    }

    // Convert our own external urls into relative urls.
    if (UrlHelper::isExternal($image_url) && $this->isInternalDomain($image_url)) {
      $image_url = parse_url($image_url)['path'];
    }

    if (!UrlHelper::isExternal($image_url) && $normal_path = parse_url($image_url)['path']) {
      $public_path = Settings::get('file_public_path', PublicStream::basePath());
      $private_path = Settings::get('file_private_path', PrivateStream::basePath());
      if ($public_path[0] != '/') {
        $public_path = '/' . $public_path;
      }
      if ($private_path[0] != '/') {
        $private_path = '/' . $private_path;
      }

      // Only concerns for the correct URI, not image URL which is already being
      // displayed via SRC attribute.
      if ($public_path && strpos($normal_path, $public_path) !== FALSE) {
        $rel_path = str_replace($public_path, '', $normal_path);

        return file_build_uri($rel_path);
      }
      elseif ($private_path && strpos($normal_path, $private_path) !== FALSE) {
        $uri = 'private://' . str_replace($private_path, '', $normal_path);

        return file_stream_wrapper_uri_normalize($uri);
      }
      // We can't generate image styles of theme or module image, so if we
      // return a base64 encoded image, we can copy this image into the
      // temporary directory and return its uri, otherwise we can't guarantee
      // the existence of the image.
      elseif ($this->configFactory->get('progressive_image_loading.settings')->get('inline_image')) {
        return $this->fileSystem->copy($this->root . $normal_path, 'temporary://');
      }
    }

    return FALSE;
  }

  /**
   * Checks if an URL has an internal domain.
   *
   * @param string $url
   *   The URL to check.
   *
   * @return bool
   *   True if the URL is internal.
   */
  protected function isInternalDomain(string $url) {
    $domains_pattern = $this->configFactory->get('progressive_image_loading.settings')->get('internal_paths');

    return (bool) empty($domains_pattern) ? FALSE : preg_match($domains_pattern, $url);
  }

  /**
   * Checks if an URL has a valid extension.
   *
   * @param string $url
   *   The URL to check.
   *
   * @return bool
   *   True if the URL is supported.
   */
  protected function isSupportedExtension(string $url) {
    $allowed_extension = ['png', 'gif', 'jpg', 'jpeg'];

    $url = UrlHelper::parse($url)['path'];
    $extension = pathinfo($url, PATHINFO_EXTENSION);

    return (bool) empty($extension) ? FALSE : in_array($extension, $allowed_extension);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc