Pull to refresh

Разбор URL в Zend Framework 2

Reading time3 min
Views6.4K
Задача:
  1. Иметь метод, разбирающий на составляющие строку содержащую URL. Строка может содержать как абсолютный, так и относительный URL, и оба эти варианты должны быть правильно разобраны.
  2. Причём в стоке допустим «неправильный» формат абсолютной ссылки — без «http://». Далее по тексту ссылки «неправильного» формата будем называть неполными абсолютными ссылками.
  3. Реализовать поддержку «РФ» доменов.


Пример: site.ru/page.php /page.php site.ru/page.php
scheme http
host site.ru site.ru
path page.php page.php page.php

Реализация пунктов 1 и 2 нашей задачи


В этом нам должен помочь класс Zend\Uri\Http. У него есть нужные нам методы parse($uri), getHost(), getPath() и т.п.
Но! При разборе URL'а типа «site.ru/page.php» (без «http://») getHost() вернёт пустую строку, а getPath() вернёт «site.ru/page.php».

Вот мой способ достичь желаемого. По формату абсолютная неполная ссылка идентична ссылке относительно источнику (тип относительной ссылки). Распознать абсолютную неполную ссылку можно проверив её TDL (домен первого уровня). Если такой домен существует — ссылку можно считать абсолютной неполной.

    public function myParse($url){
        $Http = new Http($url);
        if($Http->isValidRelative()){
            // если url разобран как относительный
            $path = $Http->getPath();
            // если path начинается со «/» — ссылка не может быть воспринята как «неправильный» формат абсолютной ссылки
            // и считается относительной
            if( $path{0} !== '/' ){ 
                // иначе пробуем собрать абсолютную ссылку...
                $absoluteUrl = '//'.urldecode($Http->toString());
                $absoluteHttp = new Http($absoluteUrl);
                // (1)
                $Hostname = new Hostname(array('allow'=>Hostname::ALLOW_DNS, 'useTldCheck'=>false));
                $decode = true;
                // ... и проверить её хост на правильность (2)
                if ($Hostname->isValid($absoluteHttp->getHost($decode))) {
                    // в случае правильности хоста считаем, что ссылку абсолютной «неправильного» формата
                    $Http = $absoluteHttp;
                }
            }
        }
        return $Http;
    }

Комментарии к коду

  1. Настраиваем Zend\Validator\Hostname так, чтобы он проверил присутствие домена первого уровня ссылки в массиве $validIdns
  2. Передаём методу getHost() параметр $decode = true; для того чтобы декодировать хост. Метод getHost() класса Zend\Uri\Http не предполагает ни каких параметров и ни чего не декодирует! Для чего тогда это и как это работает?!.. Читайте ниже.

Реализация пункта 3 нашей задачи. IDN РФ и работа с ним


К сожалению, ZF2 толком не работает с IDN, что нам придётся компенсировать. Для этого нужно скачать любой понравившийся класс, кодирующий и декодирующий url с помощью punycode и расширить класс Zend\Uri\Http.


namespace Application\Other;

use Zend\Uri\Http as ZendHttp;

use Application\Model\IdnaConvert;

class Http extends ZendHttp
{   
    public function setHost($host){
        if($host){
            $idn = new IdnaConvert();
            $host = $idn->encode($host);
        }
        return parent::setHost($host);
    }
    public function getHost($decode=false) {
        if($decode && $this->host){
            $idn = new IdnaConvert();
            return $idn->decode($this->host);
        }        
        return parent::getHost();
    }
}

Соответственно, наш метод myParse() должен использовать именно расширенный класс Http, который при разборе URL сможет кодировать РФ-домены; а при вызове метода getHost($decode), мы будем иметь возможность вернуть Punycode-представление или декодированное представление, в зависимости от переданного методу параметра.

P.S. Есть сомнения по качеству вышеизложенного, но вместе с тем это один из поводов опубликовать пост, чтобы узнать мнение тех, кто более опытен по части ZF2. Ещё один повод — я ни где не нашёл решения этой, казалось бы, очевидной задачи. Может быть от вас я узнаю о других, быть может более простых и грамотных вариантах.
Tags:
Hubs:
-1
Comments7

Articles