inline_image_saver-1.0.x-dev/src/InlineImageFinder.php

src/InlineImageFinder.php
<?php

declare(strict_types=1);

namespace Drupal\inline_image_saver;

use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\file\FileInterface;
use Drupal\file\FileRepositoryInterface;
use Drupal\filehash\Algorithm;
use Drupal\filehash\FileHashInterface;
use Drupal\inline_image_saver\Struct\InlineImageData;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Provides a inline image finder.
 */
class InlineImageFinder implements InlineImageFinderInterface {

  /**
   * Cache of stream wrapper base URIs mapped to their base URLs.
   *
   * @var array<string, string>
   */
  protected array $streamRootUris;

  /**
   * Cache of enabled file hash algorithms.
   *
   * @var string[]
   */
  protected array $enabledHashAlgorithms;

  public function __construct(
    protected readonly EntityTypeManagerInterface $entityTypeManager,
    protected readonly FileRepositoryInterface $fileRepository,
    protected readonly UuidInterface $uuid,
    protected readonly StreamWrapperManagerInterface $streamWrapperManager,
    protected readonly ModuleExtensionList $moduleExtensionList,
    #[Autowire('@filehash')]
    protected ?FileHashInterface $fileHash = NULL,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function findByHash(InlineImageData $data): ?FileInterface {
    if (!$hash_algorithms = $this->getEnabledHashAlgorithms()) {
      return NULL;
    }
    $file_storage = $this->entityTypeManager->getStorage('file');
    $file_query = $file_storage->getQuery()->accessCheck();
    foreach ($hash_algorithms as $algo) {
      $file_query->condition($algo, hash($algo, $data->data));
    }
    /** @var \Drupal\file\FileInterface $file */
    foreach ($file_storage->loadMultiple($file_query->execute()) as $file) {
      if ($file->access('download')) {
        return $file;
      }
    }
    return NULL;
  }

  /**
   * Returns the list of enabled hash algorithms from the filehash module.
   *
   * @return string[]
   *   An array of enabled hash algorithm names.
   */
  protected function getEnabledHashAlgorithms(): array {
    if (!isset($this->enabledHashAlgorithms)) {
      $this->enabledHashAlgorithms = [];
      if ($this->fileHash) {
        $filehash_version = $this->moduleExtensionList->getExtensionInfo('filehash')['version'];
        if (version_compare($filehash_version, '3.0.0', '>=') && version_compare($filehash_version, '4.0.0', '<')) {
          foreach ($this->fileHash->getEnabledAlgorithms() as $algo) {
            if ($algo = Algorithm::from($algo)->getHashAlgo()) {
              $this->enabledHashAlgorithms[] = $algo;
            }
          }
        }
      }
    }
    return $this->enabledHashAlgorithms;
  }

  /**
   * {@inheritdoc}
   */
  public function findBySrc(InlineImageData $data): ?FileInterface {
    if (!$data->src || !$stream_uris = $this->getStreamUris()) {
      return NULL;
    }
    $src = $this->stripProtocol($data->src);
    foreach ($stream_uris as $base_uri => $base_path) {
      if (!str_starts_with($src, $base_path)) {
        continue;
      }
      $file = $this->fileRepository->loadByUri(str_replace($base_path, $base_uri, $src));
      if (!$file || !$file->access('download')) {
        continue;
      }
      $data_hash ??= hash(static::HASH_ALGO, $data->data);
      if (hash_file(static::HASH_ALGO, $file->getFileUri()) === $data_hash) {
        return $file;
      }
    }
    return NULL;
  }

  /**
   * Returns a mapping of stream wrapper URIs to their external base URLs.
   *
   * @return array<string, string>
   *   The URI-to-URL mapping.
   */
  protected function getStreamUris(): array {
    if (!isset($this->streamRootUris)) {
      $this->streamRootUris = [];
      $fake_path = $this->uuid->generate();
      foreach ($this->streamWrapperManager->getWrappers(StreamWrapperInterface::READ_VISIBLE) as $scheme => $definition) {
        $uri_base = "$scheme://";
        try {
          $fake_url = $this->streamWrapperManager->getViaUri("$uri_base/$fake_path")->getExternalUrl();
          if (str_ends_with($fake_url, $fake_path) && substr_count($fake_url, $fake_path) === 1) {
            $this->streamRootUris[$uri_base] = $this->stripProtocol(str_replace($fake_path, '', $fake_url));
          }
        }
        catch (\Throwable) {
          // Ignore.
        }
      }
    }
    return $this->streamRootUris;
  }

  /**
   * Removes the scheme and leading slashes from a URL.
   *
   * @param string $url
   *   The URL to normalize.
   *
   * @return string
   *   The cleaned value without scheme or slashes.
   */
  protected function stripProtocol(string $url): string {
    return preg_replace('#^(.*:)?//#', '', $url);
  }

}

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

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