[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/algo26-matthias/idna-convert/src/Punycode/ -> ToPunycode.php (source)

   1  <?php
   2  
   3  namespace Algo26\IdnaConvert\Punycode;
   4  
   5  use Algo26\IdnaConvert\Exception\AlreadyPunycodeException;
   6  use Algo26\IdnaConvert\Exception\InvalidCharacterException;
   7  use Algo26\IdnaConvert\Exception\InvalidIdnVersionException;
   8  use Algo26\IdnaConvert\NamePrep\NamePrep;
   9  
  10  class ToPunycode extends AbstractPunycode implements PunycodeInterface
  11  {
  12      /** @var NamePrep */
  13      private $namePrep;
  14  
  15      /**
  16       * @throws InvalidIdnVersionException
  17       */
  18      public function __construct(?string $idnVersion = null)
  19      {
  20          $this->namePrep = new NamePrep($idnVersion);
  21          parent::__construct();
  22      }
  23  
  24      /**
  25       * @param array $decoded
  26       *
  27       * @return string
  28       * @throws AlreadyPunycodeException
  29       * @throws InvalidCharacterException
  30       */
  31      public function convert(array $decoded): string
  32      {
  33          // We cannot encode a domain name containing the Punycode prefix
  34          $checkForPrefix = array_slice($decoded, 0, self::$prefixLength);
  35          if (self::$prefixAsArray === $checkForPrefix) {
  36              throw new AlreadyPunycodeException('This is already a Punycode string', 100);
  37          }
  38          // We will not try to encode strings consisting of basic code points only
  39          $canEncode = false;
  40          foreach ($decoded as $k => $v) {
  41              if ($v > 0x7a) {
  42                  $canEncode = true;
  43                  break;
  44              }
  45          }
  46          if (!$canEncode) {
  47              return false;
  48          }
  49  
  50          // Do NAMEPREP
  51          $decoded = $this->namePrep->do($decoded);
  52          if (!$decoded || !is_array($decoded)) {
  53              return false; // NAMEPREP failed
  54          }
  55  
  56          $decodedLength = count($decoded);
  57          if (!$decodedLength) {
  58              return false; // Empty array
  59          }
  60  
  61          $codeCount = 0; // How many chars have been consumed
  62          $encoded = '';
  63          // Copy all basic code points to output
  64          for ($i = 0; $i < $decodedLength; ++$i) {
  65              $test = $decoded[$i];
  66              // Will match [-0-9a-zA-Z]
  67              if ((0x2F < $test && $test < 0x40)
  68                  || (0x40 < $test && $test < 0x5B)
  69                  || (0x60 < $test && $test <= 0x7B)
  70                  || (0x2D == $test)
  71              ) {
  72                  $encoded .= chr($decoded[$i]);
  73                  $codeCount++;
  74              }
  75          }
  76          if ($codeCount === $decodedLength) {
  77              return $encoded; // All codepoints were basic ones
  78          }
  79  
  80          // Start with the prefix; copy it to output
  81          $encoded = self::punycodePrefix . $encoded;
  82          // If we have basic code points in output, add an hyphen to the end
  83          if ($codeCount) {
  84              $encoded .= '-';
  85          }
  86          // Now find and encode all non-basic code points
  87          $isFirst = true;
  88          $currentCode = self::initialN;
  89          $bias = self::initialBias;
  90          $delta = 0;
  91          while ($codeCount < $decodedLength) {
  92              // Find the smallest code point >= the current code point and
  93              // remember the last occurrence of it in the input
  94              for ($i = 0, $nextCode = self::maxUcs; $i < $decodedLength; $i++) {
  95                  if ($decoded[$i] >= $currentCode && $decoded[$i] <= $nextCode) {
  96                      $nextCode = $decoded[$i];
  97                  }
  98              }
  99              $delta += ($nextCode - $currentCode) * ($codeCount + 1);
 100              $currentCode = $nextCode;
 101  
 102              // Scan input again and encode all characters whose code point is $currentCode
 103              for ($i = 0; $i < $decodedLength; $i++) {
 104                  if ($decoded[$i] < $currentCode) {
 105                      $delta++;
 106                  } elseif ($decoded[$i] == $currentCode) {
 107                      for ($q = $delta, $k = self::base; 1; $k += self::base) {
 108                          $t = ($k <= $bias)
 109                              ? self::tMin
 110                              : (($k >= $bias + self::tMax)
 111                                  ? self::tMax
 112                                  : $k - $bias
 113                              );
 114                          if ($q < $t) {
 115                              break;
 116                          }
 117  
 118                          $encoded .= $this->encodeDigit(intval($t + (($q - $t) % (self::base - $t))));
 119                          $q = (int) (($q - $t) / (self::base - $t));
 120                      }
 121                      $encoded .= $this->encodeDigit($q);
 122                      $bias = $this->adapt($delta, $codeCount + 1, $isFirst);
 123                      $codeCount++;
 124                      $delta = 0;
 125                      $isFirst = false;
 126                  }
 127              }
 128              $delta++;
 129              $currentCode++;
 130          }
 131  
 132          return $encoded;
 133      }
 134  
 135      /**
 136       * Encoding a certain digit
 137       * @param    int $d
 138       * @return string
 139       */
 140      private function encodeDigit($d): string
 141      {
 142          return chr($d + 22 + 75 * ($d < 26));
 143      }
 144  }


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