Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  /**
   3   * Copyright 2014-2017 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file LICENSE for license information (BSD). If you
   6   * did not receive this file, see http://www.horde.org/licenses/bsd.
   7   *
   8   * @author   Michael Slusarz <slusarz@horde.org>
   9   * @category Horde
  10   * @license  http://www.horde.org/licenses/bsd BSD
  11   * @package  Idna
  12   */
  13  
  14  /**
  15   * Provide normalized encoding/decoding support for IDNA strings.
  16   *
  17   * @author    Michael Slusarz <slusarz@horde.org>
  18   * @category  Horde
  19   * @copyright 2014-2017 Horde LLC
  20   * @license   http://www.horde.org/licenses/bsd BSD
  21   * @package   Idna
  22   */
  23  class Horde_Idna
  24  {
  25      /**
  26       * The backend to use.
  27       *
  28       * @var mixed
  29       */
  30      protected static $_backend;
  31  
  32      /**
  33       * @throws Horde_Idna_Exception
  34       */
  35      public static function encode($data)
  36      {
  37          switch ($backend = static::_getBackend()) {
  38          case 'INTL':
  39              return idn_to_ascii($data);
  40  
  41          case 'INTL_UTS46':
  42              $result = idn_to_ascii($data, 0, INTL_IDNA_VARIANT_UTS46, $info);
  43              self::_checkForError($info);
  44              return $result;
  45  
  46          default:
  47              return $backend->encode($data);
  48          }
  49      }
  50  
  51      /**
  52       * @throws Horde_Idna_Exception
  53       */
  54      public static function decode($data)
  55      {
  56          switch ($backend = static::_getBackend()) {
  57          case 'INTL':
  58          case 'INTL_UTS46':
  59              $parts = explode('.', $data);
  60              foreach ($parts as &$part) {
  61                  if (strpos($part, 'xn--') === 0) {
  62                      switch ($backend) {
  63                      case 'INTL':
  64                          $part = idn_to_utf8($part);
  65                          break;
  66  
  67                      case 'INTL_UTS46':
  68                          $part = idn_to_utf8($part, 0, INTL_IDNA_VARIANT_UTS46, $info);
  69                          self::_checkForError($info);
  70                          break;
  71                      }
  72                  }
  73              }
  74              return implode('.', $parts);
  75  
  76          default:
  77              return $backend->decode($data);
  78          }
  79      }
  80  
  81      /**
  82       * Checks if the $idna_info parameter of idn_to_ascii() or idn_to_utf8()
  83       * contains errors.
  84       *
  85       * @param array $info  Fourth parameter to idn_to_ascii() or idn_to_utf8().
  86       *
  87       * @throws Horde_Idna_Exception
  88       */
  89      protected static function _checkForError($info)
  90      {
  91          switch (true) {
  92          case $info['errors'] & IDNA_ERROR_EMPTY_LABEL:
  93              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
  94                  "Domain name is empty"
  95              ));
  96          case $info['errors'] & IDNA_ERROR_LABEL_TOO_LONG:
  97          case $info['errors'] & IDNA_ERROR_DOMAIN_NAME_TOO_LONG:
  98              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
  99                  "Domain name is too long"
 100              ));
 101          case $info['errors'] & IDNA_ERROR_LEADING_HYPHEN:
 102              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 103                  "Starts with a hyphen"
 104              ));
 105          case $info['errors'] & IDNA_ERROR_TRAILING_HYPHEN:
 106              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 107                  "Ends with a hyphen"
 108              ));
 109          case $info['errors'] & IDNA_ERROR_HYPHEN_3_4:
 110              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 111                  "Contains hyphen in the third and fourth positions"
 112              ));
 113          case $info['errors'] & IDNA_ERROR_LEADING_COMBINING_MARK:
 114              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 115                  "Starts with a combining mark"
 116              ));
 117          case $info['errors'] & IDNA_ERROR_DISALLOWED:
 118              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 119                  "Contains disallowed characters"
 120              ));
 121          case $info['errors'] & IDNA_ERROR_PUNYCODE:
 122              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 123                  "Starts with \"xn--\" but does not contain valid Punycode"
 124              ));
 125          case $info['errors'] & IDNA_ERROR_LABEL_HAS_DOT:
 126              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 127                  "Contains a dot"
 128              ));
 129          case $info['errors'] & IDNA_ERROR_INVALID_ACE_LABEL:
 130              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 131                  "ACE label does not contain a valid label string"
 132              ));
 133          case $info['errors'] & IDNA_ERROR_BIDI:
 134              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 135                  "Does not meet the IDNA BiDi requirements (for right-to-left characters)"
 136              ));
 137          case $info['errors'] & IDNA_ERROR_CONTEXTJ:
 138              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 139                  "Does not meet the IDNA CONTEXTJ requirements"
 140              ));
 141          case $info['errors']:
 142              throw new Horde_Idna_Exception(Horde_Idna_Translation::t(
 143                  "Unknown error"
 144              ));
 145          }
 146      }
 147  
 148      /**
 149       * Return the IDNA backend.
 150       *
 151       * @return mixed  IDNA backend (false if none available).
 152       */
 153      protected static function _getBackend()
 154      {
 155          if (!isset(self::$_backend)) {
 156              if (extension_loaded('intl')) {
 157                  /* Only available in PHP > 5.4.0 */
 158                  self::$_backend = defined('INTL_IDNA_VARIANT_UTS46')
 159                      ? 'INTL_UTS46'
 160                      : 'INTL';
 161              } else {
 162                  self::$_backend = new Horde_Idna_Punycode();
 163              }
 164          }
 165  
 166          return self::$_backend;
 167      }
 168  
 169  }