[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/typo3/phar-stream-wrapper/src/Resolver/ -> PharInvocationResolver.php (source)

   1  <?php
   2  declare(strict_types=1);
   3  namespace TYPO3\PharStreamWrapper\Resolver;
   4  
   5  /*
   6   * This file is part of the TYPO3 project.
   7   *
   8   * It is free software; you can redistribute it and/or modify it under the terms
   9   * of the MIT License (MIT). For the full copyright and license information,
  10   * please read the LICENSE file that was distributed with this source code.
  11   *
  12   * The TYPO3 project - inspiring people to share!
  13   */
  14  
  15  use TYPO3\PharStreamWrapper\Helper;
  16  use TYPO3\PharStreamWrapper\Manager;
  17  use TYPO3\PharStreamWrapper\Phar\Reader;
  18  use TYPO3\PharStreamWrapper\Phar\ReaderException;
  19  use TYPO3\PharStreamWrapper\Resolvable;
  20  
  21  class PharInvocationResolver implements Resolvable
  22  {
  23      const RESOLVE_REALPATH = 1;
  24      const RESOLVE_ALIAS = 2;
  25      const ASSERT_INTERNAL_INVOCATION = 32;
  26  
  27      /**
  28       * @var string[]
  29       */
  30      private $invocationFunctionNames = [
  31          'include',
  32          'include_once',
  33          'require',
  34          'require_once'
  35      ];
  36  
  37      /**
  38       * Contains resolved base names in order to reduce file IO.
  39       *
  40       * @var string[]
  41       */
  42      private $baseNames = [];
  43  
  44      /**
  45       * Resolves PharInvocation value object (baseName and optional alias).
  46       *
  47       * Phar aliases are intended to be used only inside Phar archives, however
  48       * PharStreamWrapper needs this information exposed outside of Phar as well
  49       * It is possible that same alias is used for different $baseName values.
  50       * That's why PharInvocationCollection behaves like a stack when resolving
  51       * base-name for a given alias. On the other hand it is not possible that
  52       * one $baseName is referring to multiple aliases.
  53       * @see https://secure.php.net/manual/en/phar.setalias.php
  54       * @see https://secure.php.net/manual/en/phar.mapphar.php
  55       *
  56       * @param string $path
  57       * @param int|null $flags
  58       * @return null|PharInvocation
  59       */
  60      public function resolve(string $path, int $flags = null)
  61      {
  62          $hasPharPrefix = Helper::hasPharPrefix($path);
  63          $flags = $flags ?? static::RESOLVE_REALPATH | static::RESOLVE_ALIAS;
  64  
  65          if ($hasPharPrefix && $flags & static::RESOLVE_ALIAS) {
  66              $invocation = $this->findByAlias($path);
  67              if ($invocation !== null) {
  68                  return $invocation;
  69              }
  70          }
  71  
  72          $baseName = $this->resolveBaseName($path, $flags);
  73          if ($baseName === null) {
  74              return null;
  75          }
  76  
  77          if ($flags & static::RESOLVE_REALPATH) {
  78              $baseName = $this->baseNames[$baseName];
  79          }
  80  
  81          return $this->retrieveInvocation($baseName, $flags);
  82      }
  83  
  84      /**
  85       * Retrieves PharInvocation, either existing in collection or created on demand
  86       * with resolving a potential alias name used in the according Phar archive.
  87       *
  88       * @param string $baseName
  89       * @param int $flags
  90       * @return PharInvocation
  91       */
  92      private function retrieveInvocation(string $baseName, int $flags): PharInvocation
  93      {
  94          $invocation = $this->findByBaseName($baseName);
  95          if ($invocation !== null) {
  96              return $invocation;
  97          }
  98  
  99          if ($flags & static::RESOLVE_ALIAS) {
 100              $alias = (new Reader($baseName))->resolveContainer()->getAlias();
 101          } else {
 102              $alias = '';
 103          }
 104          // add unconfirmed(!) new invocation to collection
 105          $invocation = new PharInvocation($baseName, $alias);
 106          Manager::instance()->getCollection()->collect($invocation);
 107          return $invocation;
 108      }
 109  
 110      /**
 111       * @param string $path
 112       * @param int $flags
 113       * @return null|string
 114       */
 115      private function resolveBaseName(string $path, int $flags)
 116      {
 117          $baseName = $this->findInBaseNames($path);
 118          if ($baseName !== null) {
 119              return $baseName;
 120          }
 121  
 122          $baseName = Helper::determineBaseFile($path);
 123          if ($baseName !== null) {
 124              $this->addBaseName($baseName);
 125              return $baseName;
 126          }
 127  
 128          $possibleAlias = $this->resolvePossibleAlias($path);
 129          if (!($flags & static::RESOLVE_ALIAS) || $possibleAlias === null) {
 130              return null;
 131          }
 132  
 133          $trace = debug_backtrace();
 134          foreach ($trace as $item) {
 135              if (!isset($item['function']) || !isset($item['args'][0])
 136                  || !in_array($item['function'], $this->invocationFunctionNames, true)) {
 137                  continue;
 138              }
 139              $currentPath = $item['args'][0];
 140              if (Helper::hasPharPrefix($currentPath)) {
 141                  continue;
 142              }
 143              $currentBaseName = Helper::determineBaseFile($currentPath);
 144              if ($currentBaseName === null) {
 145                  continue;
 146              }
 147              // ensure the possible alias name (how we have been called initially) matches
 148              // the resolved alias name that was retrieved by the current possible base name
 149              try {
 150                  $currentAlias = (new Reader($currentBaseName))->resolveContainer()->getAlias();
 151              } catch (ReaderException $exception) {
 152                  // most probably that was not a Phar file
 153                  continue;
 154              }
 155              if (empty($currentAlias) || $currentAlias !== $possibleAlias) {
 156                  continue;
 157              }
 158              $this->addBaseName($currentBaseName);
 159              return $currentBaseName;
 160          }
 161  
 162          return null;
 163      }
 164  
 165      /**
 166       * @param string $path
 167       * @return null|string
 168       */
 169      private function resolvePossibleAlias(string $path)
 170      {
 171          $normalizedPath = Helper::normalizePath($path);
 172          return strstr($normalizedPath, '/', true) ?: null;
 173      }
 174  
 175      /**
 176       * @param string $baseName
 177       * @return null|PharInvocation
 178       */
 179      private function findByBaseName(string $baseName)
 180      {
 181          return Manager::instance()->getCollection()->findByCallback(
 182              function (PharInvocation $candidate) use ($baseName) {
 183                  return $candidate->getBaseName() === $baseName;
 184              },
 185              true
 186          );
 187      }
 188  
 189      /**
 190       * @param string $path
 191       * @return null|string
 192       */
 193      private function findInBaseNames(string $path)
 194      {
 195          // return directly if the resolved base name was submitted
 196          if (in_array($path, $this->baseNames, true)) {
 197              return $path;
 198          }
 199  
 200          $parts = explode('/', Helper::normalizePath($path));
 201  
 202          while (count($parts)) {
 203              $currentPath = implode('/', $parts);
 204              if (isset($this->baseNames[$currentPath])) {
 205                  return $currentPath;
 206              }
 207              array_pop($parts);
 208          }
 209  
 210          return null;
 211      }
 212  
 213      /**
 214       * @param string $baseName
 215       */
 216      private function addBaseName(string $baseName)
 217      {
 218          if (isset($this->baseNames[$baseName])) {
 219              return;
 220          }
 221          $this->baseNames[$baseName] = Helper::normalizeWindowsPath(
 222              realpath($baseName)
 223          );
 224      }
 225  
 226      /**
 227       * Finds confirmed(!) invocations by alias.
 228       *
 229       * @param string $path
 230       * @return null|PharInvocation
 231       * @see \TYPO3\PharStreamWrapper\PharStreamWrapper::collectInvocation()
 232       */
 233      private function findByAlias(string $path)
 234      {
 235          $possibleAlias = $this->resolvePossibleAlias($path);
 236          if ($possibleAlias === null) {
 237              return null;
 238          }
 239          return Manager::instance()->getCollection()->findByCallback(
 240              function (PharInvocation $candidate) use ($possibleAlias) {
 241                  return $candidate->isConfirmed() && $candidate->getAlias() === $possibleAlias;
 242              },
 243              true
 244          );
 245      }
 246  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer