Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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.
<?php
/**
 * Copyright 2014-2017 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file LICENSE for license information (BSD). If you
 * did not receive this file, see http://www.horde.org/licenses/bsd.
 *
 * @author   Michael Slusarz <slusarz@horde.org>
 * @category Horde
 * @license  http://www.horde.org/licenses/bsd BSD
 * @package  Idna
 */

/**
 * Provide normalized encoding/decoding support for IDNA strings.
 *
 * @author    Michael Slusarz <slusarz@horde.org>
 * @category  Horde
 * @copyright 2014-2017 Horde LLC
 * @license   http://www.horde.org/licenses/bsd BSD
 * @package   Idna
 */
class Horde_Idna
{
    /**
     * The backend to use.
     *
     * @var mixed
     */
    protected static $_backend;

    /**
     * @throws Horde_Idna_Exception
     */
    public static function encode($data)
    {
        switch ($backend = static::_getBackend()) {
        case 'INTL':
            return idn_to_ascii($data);

        case 'INTL_UTS46':
            $result = idn_to_ascii($data, 0, INTL_IDNA_VARIANT_UTS46, $info);
            self::_checkForError($info);
            return $result;

        default:
            return $backend->encode($data);
        }
    }

    /**
     * @throws Horde_Idna_Exception
     */
    public static function decode($data)
    {
        switch ($backend = static::_getBackend()) {
        case 'INTL':
        case 'INTL_UTS46':
            $parts = explode('.', $data);
            foreach ($parts as &$part) {
                if (strpos($part, 'xn--') === 0) {
                    switch ($backend) {
                    case 'INTL':
                        $part = idn_to_utf8($part);
                        break;

                    case 'INTL_UTS46':
                        $part = idn_to_utf8($part, 0, INTL_IDNA_VARIANT_UTS46, $info);
                        self::_checkForError($info);
                        break;
                    }
                }
            }
            return implode('.', $parts);

        default:
            return $backend->decode($data);
        }
    }

    /**
     * Checks if the $idna_info parameter of idn_to_ascii() or idn_to_utf8()
     * contains errors.
     *
     * @param array $info  Fourth parameter to idn_to_ascii() or idn_to_utf8().
     *
     * @throws Horde_Idna_Exception
     */
    protected static function _checkForError($info)
    {
> if (!isset($info['errors'])) { switch (true) { > return; case $info['errors'] & IDNA_ERROR_EMPTY_LABEL: > }
throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Domain name is empty" )); case $info['errors'] & IDNA_ERROR_LABEL_TOO_LONG: case $info['errors'] & IDNA_ERROR_DOMAIN_NAME_TOO_LONG: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Domain name is too long" )); case $info['errors'] & IDNA_ERROR_LEADING_HYPHEN: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Starts with a hyphen" )); case $info['errors'] & IDNA_ERROR_TRAILING_HYPHEN: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Ends with a hyphen" )); case $info['errors'] & IDNA_ERROR_HYPHEN_3_4: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Contains hyphen in the third and fourth positions" )); case $info['errors'] & IDNA_ERROR_LEADING_COMBINING_MARK: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Starts with a combining mark" )); case $info['errors'] & IDNA_ERROR_DISALLOWED: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Contains disallowed characters" )); case $info['errors'] & IDNA_ERROR_PUNYCODE: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Starts with \"xn--\" but does not contain valid Punycode" )); case $info['errors'] & IDNA_ERROR_LABEL_HAS_DOT: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Contains a dot" )); case $info['errors'] & IDNA_ERROR_INVALID_ACE_LABEL: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "ACE label does not contain a valid label string" )); case $info['errors'] & IDNA_ERROR_BIDI: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Does not meet the IDNA BiDi requirements (for right-to-left characters)" )); case $info['errors'] & IDNA_ERROR_CONTEXTJ: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Does not meet the IDNA CONTEXTJ requirements" )); case $info['errors']: throw new Horde_Idna_Exception(Horde_Idna_Translation::t( "Unknown error" )); } } /** * Return the IDNA backend. * * @return mixed IDNA backend (false if none available). */ protected static function _getBackend() { if (!isset(self::$_backend)) { if (extension_loaded('intl')) { /* Only available in PHP > 5.4.0 */ self::$_backend = defined('INTL_IDNA_VARIANT_UTS46') ? 'INTL_UTS46' : 'INTL'; } else { self::$_backend = new Horde_Idna_Punycode(); } } return self::$_backend; } }