Разбор URL в Zend Framework 2

в 16:32, , рубрики: Zend Framework, zend framework 2, zf2, метки: ,

Задача:

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

Пример: http://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 нашей задачи

В этом нам должен помочь класс ZendUriHttp. У него есть нужные нам методы 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. Настраиваем ZendValidatorHostname так, чтобы он проверил присутствие домена первого уровня ссылки в массиве $validIdns
  2. Передаём методу getHost() параметр $decode = true; для того чтобы декодировать хост. Метод getHost() сласса ZendUriHttp не предполагает ни каких параметров и ни чего не декодирует! Для чего тогда это и как это работает?!.. Читайте ниже.

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

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


namespace ApplicationOther;

use ZendUriHttp as ZendHttp;

use ApplicationModelIdnaConvert;

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. Ещё один повод — я ни где не нашёл решения этой, казалось бы, очевидной задачи. Может быть от вас я узнаю о других, быть может более простых и грамотных вариантах.

Автор: deffect

Источник

Поделиться

* - обязательные к заполнению поля