• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • parse_url()

    (PHP 4, PHP 5, PHP 7)

    解析 URL,返回其组成部分

    说明

    parse_url(string $url[,int $component=-1]): mixed

    本函数解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。

    本函数不是用来验证给定 URL 的合法性的,只是将其分解为下面列出的部分。不完整的 URL 也被接受,parse_url()会尝试尽量正确地将其解析。

    参数

    $url

    要解析的 URL。无效字符将使用_来替换。

    $component

    指定PHP_URL_SCHEMEPHP_URL_HOSTPHP_URL_PORTPHP_URL_USERPHP_URL_PASSPHP_URL_PATHPHP_URL_QUERYPHP_URL_FRAGMENT的其中一个来获取 URL 中指定的部分的string。(除了指定为PHP_URL_PORT后,将返回一个integer的值)。

    返回值

    对严重不合格的 URL,parse_url()可能会返回FALSE

    如果省略了$component参数,将返回一个关联数组array,在目前至少会有一个元素在该数组中。数组中可能的键有以下几种:

    • scheme-如http
    • host
    • port
    • user
    • pass
    • path
    • query-在问号?之后
    • fragment-在散列符号#之后

    如果指定了$component参数,parse_url()返回一个string(或在指定为PHP_URL_PORT时返回一个integer)而不是array。如果 URL 中指定的组成部分不存在,将会返回NULL

    更新日志

    版本说明
    5.4.7修复了host协议省略时的识别。
    5.3.3在 URL 解析失败时将不会产生E_WARNING级别的错误。
    5.1.2增加了参数$component

    范例

    Example #1parse_url()例子

    <?php
    $url = 'http://username:password@hostname/path?arg=value#anchor';
    print_r(parse_url($url));
    echo parse_url($url, PHP_URL_PATH);
    ?>
    

    以上例程会输出:

    Array
    (
        [scheme] => http
        [host] => hostname
        [user] => username
        [pass] => password
        [path] => /path
        [query] => arg=value
        [fragment] => anchor
    )
    /path
    

    Example #2parse_url()解析丢失协议的例子

    <?php
    $url = '//www.example.com/path?googleguy=googley';
    // 在 5.4.7 之前这会输出路径 "//www.example.com/path"
    var_dump(parse_url($url));
    ?>
    

    以上例程会输出:

    array(3) {
      ["host"]=>
      string(15) "www.example.com"
      ["path"]=>
      string(5) "/path"
      ["query"]=>
      string(17) "googleguy=googley"
    }
    

    注释

    Note:

    本函数不能用于相对 URL。

    Note:

    parse_url()是专门用来解析 URL 而不是 URI 的。不过为遵从 PHP 向后兼容的需要有个例外,对 file://协议允许三个斜线(file:///...)。其它任何协议都不能这样。

    参见

    [If you haven't yet] been able to find a simple conversion back to string from a parsed url, here's an example:
    <?php
    $url = 'http://usr:pss@example.com:81/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment';
    if ($url === unparse_url(parse_url($url))) {
     print "YES, they match!\n";
    }
    function unparse_url($parsed_url) {
     $scheme  = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
     $host   = isset($parsed_url['host']) ? $parsed_url['host'] : '';
     $port   = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
     $user   = isset($parsed_url['user']) ? $parsed_url['user'] : '';
     $pass   = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
     $pass   = ($user || $pass) ? "$pass@" : '';
     $path   = isset($parsed_url['path']) ? $parsed_url['path'] : '';
     $query  = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
     $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
     return "$scheme$user$pass$host$port$path$query$fragment";
    }
    ?>
    
    It may be worth reminding that the value of the #fragment never gets sent to the server. Anchors processing is exclusively client-side.
    Here is utf-8 compatible parse_url() replacement function based on "laszlo dot janszky at gmail dot com" work. Original incorrectly handled URLs with user:pass. Also made PHP 5.5 compatible (got rid of now deprecated regex /e modifier).
    <?php
      /**
       * UTF-8 aware parse_url() replacement.
       * 
       * @return array
       */
      function mb_parse_url($url)
      {
        $enc_url = preg_replace_callback(
          '%[^:/@?&=#]+%usD',
          function ($matches)
          {
            return urlencode($matches[0]);
          },
          $url
        );
        
        $parts = parse_url($enc_url);
        
        if($parts === false)
        {
          throw new \InvalidArgumentException('Malformed URL: ' . $url);
        }
        
        foreach($parts as $name => $value)
        {
          $parts[$name] = urldecode($value);
        }
        
        return $parts;
      }
    ?>
    
    I was writing unit tests and needed to cause this function to kick out an error and return FALSE in order to test a specific execution path. If anyone else needs to force a failure, the following inputs will work:
    <?php
    parse_url("http:///example.com");
    parse_url("http://:80");
    parse_url("http://user@:80");
    ?>
    
    Created another parse_url utf-8 compatible function.
    <?php
    function mb_parse_url($url) {
      $encodedUrl = preg_replace('%[^:/?#&=\.]+%usDe', 'urlencode(\'$0\')', $url);
      $components = parse_url($encodedUrl);
      foreach ($components as &$component)
        $component = urldecode($component);
      return $components;
    }
    ?>
    
    Here's a good way to using parse_url () gets the youtube link.
    This function I used in many works:
    <?php
    function youtube($url, $width=560, $height=315, $fullscreen=true)
    {
      parse_str( parse_url( $url, PHP_URL_QUERY ), $my_array_of_vars );
      $youtube= '<iframe allowtransparency="true" scrolling="no" width="'.$width.'" height="'.$height.'" src="//www.youtube.com/embed/'.$my_array_of_vars['v'].'" frameborder="0"'.($fullscreen?' allowfullscreen':NULL).'></iframe>';
      return $youtube;
    }
    // show youtube on my page
    $url='http://www.youtube.com/watch?v=yvTd6XxgCBE';
     youtube($url, 560, 315, true);
    ?>
    parse_url () allocates a unique youtube code and put into iframe link and displayed on your page. The size of the videos choose yourself.
    Enjoy.
    Based on the idea of "jbr at ya-right dot com" have I been working on a new function to parse the url:
    <?php
    function parseUrl($url) {
      $r = "^(?:(?P<scheme>\w+)://)?";
      $r .= "(?:(?P<login>\w+):(?P<pass>\w+)@)?";
      $r .= "(?P<host>(?:(?P<subdomain>[\w\.]+)\.)?" . "(?P<domain>\w+\.(?P<extension>\w+)))";
      $r .= "(?::(?P<port>\d+))?";
      $r .= "(?P<path>[\w/]*/(?P<file>\w+(?:\.\w+)?)?)?";
      $r .= "(?:\?(?P<arg>[\w=&]+))?";
      $r .= "(?:#(?P<anchor>\w+))?";
      $r = "!$r!";                        // Delimiters
      
      preg_match ( $r, $url, $out );
      
      return $out;
    }
    print_r ( parseUrl ( 'me:you@sub.site.org:29000/pear/validate.html?happy=me&sad=you#url' ) );
    ?>
    This returns:
    Array
    (
      [0] => me:you@sub.site.org:29000/pear/validate.html?happy=me&sad=you#url
      [scheme] => 
      [1] => 
      [login] => me
      [2] => me
      [pass] => you
      [3] => you
      [host] => sub.site.org
      [4] => sub.site.org
      [subdomain] => sub
      [5] => sub
      [domain] => site.org
      [6] => site.org
      [extension] => org
      [7] => org
      [port] => 29000
      [8] => 29000
      [path] => /pear/validate.html
      [9] => /pear/validate.html
      [file] => validate.html
      [10] => validate.html
      [arg] => happy=me&sad=you
      [11] => happy=me&sad=you
      [anchor] => url
      [12] => url
    )
    So both named and numbered array keys are possible.
    It's quite advanced, but I think it works in any case... Let me know if it doesn't...
    I have coded a function which converts relative URL to absolute URL for a project of mine. Considering I could not find it elsewhere, I figured I would post it here.
    The following function takes in 2 parameters, the first parameter is the URL you want to convert from relative to absolute, and the second parameter is a sample of the absolute URL.
    Currently it does not resolve '../' in the URL, only because I do not need it. Most webservers will resolve this for you. If you want it to resolve the '../' in the path, it just takes minor modifications.
    <?php
    function relativeToAbsolute($inurl, $absolute) {
      // Get all parts so not getting them multiple times :)
      $absolute_parts = parse_url($absolute);  
      // Test if URL is already absolute (contains host, or begins with '/')
      if ( (strpos($inurl, $absolute_parts['host']) == false) ) {
        // Define $tmpurlprefix to prevent errors below
        $tmpurlprefix = "";
        // Formulate URL prefix  (SCHEME)          
        if (!(empty($absolute_parts['scheme']))) { 
          // Add scheme to tmpurlprefix
          $tmpurlprefix .= $absolute_parts['scheme'] . "://"; 
        }
        // Formulate URL prefix (USER, PASS)  
        if ((!(empty($absolute_parts['user']))) and (!(empty($absolute_parts['pass'])))) { 
          // Add user:port to tmpurlprefix
          $tmpurlprefix .= $absolute_parts['user'] . ":" . $absolute_parts['pass'] . "@";  
        }
        // Formulate URL prefix  (HOST, PORT)  
        if (!(empty($absolute_parts['host']))) { 
          // Add host to tmpurlprefix
          $tmpurlprefix .= $absolute_parts['host'];
          // Check for a port, add if exists
          if (!(empty($absolute_parts['port']))) {
            // Add port to tmpurlprefix
            $tmpurlprefix .= ":" . $absolute_parts['port'];
          } 
        }
        // Formulate URL prefix  (PATH) and only add it if the path to image does not include ./  
        if ( (!(empty($absolute_parts['path']))) and (substr($inurl, 0, 1) != '/') ) { 
          // Get path parts
          $path_parts = pathinfo($absolute_parts['path']);
          // Add path to tmpurlprefix
          $tmpurlprefix .= $path_parts['dirname'];
          $tmpurlprefix .= "/"; 
        }
        else {  
          $tmpurlprefix .= "/";  
        }  
        // Lets remove the '/'
        if (substr($inurl, 0, 1) == '/') { $inurl = substr($inurl, 1); }  
        // Lets remove the './'
        if (substr($inurl, 0, 2) == './') { $inurl = substr($inurl, 2); }  
        return $tmpurlprefix . $inurl;
      }  
      else {
        // Path is already absolute. Return it :)
        return $inurl;
      }
    }
    // Define a sample absolute URL
    $absolute = "http://" . "user:pass@example.com:8080/path/to/index"; // Just evading php.net spam filter, not sure how example.com is spam...
    /* EXAMPLE 1 */
    echo relativeToAbsolute($absolute, $absolute) . "\n";
    /* EXAMPLE 2 */
    echo relativeToAbsolute("img.gif", $absolute) . "\n";
    /* EXAMPLE 3 */
    echo relativeToAbsolute("/img.gif", $absolute) . "\n"; 
    /* EXAMPLE 4 */
    echo relativeToAbsolute("./img.gif", $absolute) . "\n";
    /* EXAMPLE 5 */
    echo relativeToAbsolute("../img.gif", $absolute) . "\n";
    /* EXAMPLE 6 */
    echo relativeToAbsolute("images/img.gif", $absolute) . "\n";
    /* EXAMPLE 7 */
    echo relativeToAbsolute("/images/img.gif", $absolute) . "\n";
    /* EXAMPLE 8 */
    echo relativeToAbsolute("./images/img.gif", $absolute) . "\n";
    /* EXAMPLE 9 */
    echo relativeToAbsolute("../images/img.gif", $absolute) . "\n";
    ?>
    OUTPUTS:
    http :// user:pass@example.com:8080/path/to/index.html
    http :// user:pass@example.com:8080/path/to/img.gif
    http :// user:pass@example.com:8080/img.gif
    http :// user:pass@example.com:8080/path/to/img.gif
    http :// user:pass@example.com:8080/path/to/../img.gif
    http :// user:pass@example.com:8080/path/to/images/img.gif
    http :// user:pass@example.com:8080/images/img.gif
    http :// user:pass@example.com:8080/path/to/images/img.gif
    http :// user:pass@example.com:8080/path/to/../images/img.gif
    Sorry if the above code is not your style, or if you see it as "messy" or you think there is a better way to do it. I removed as much of the white space as possible.
    Improvements are welcome :)
    @ solenoid: Your code was very helpful, but it fails when the current URL has no query string (it appends '&' instead of '?' before the query). Below is a fixed version that catches this edge case and corrects it.
    <?php
    function modify_url($mod) 
    { 
      $url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; 
      $query = explode("&", $_SERVER['QUERY_STRING']);
      if (!$_SERVER['QUERY_STRING']) {$queryStart = "?";} else {$queryStart = "&";}
      // modify/delete data 
      foreach($query as $q) 
      { 
        list($key, $value) = explode("=", $q); 
        if(array_key_exists($key, $mod)) 
        { 
          if($mod[$key]) 
          { 
            $url = preg_replace('/'.$key.'='.$value.'/', $key.'='.$mod[$key], $url); 
          } 
          else 
          { 
            $url = preg_replace('/&?'.$key.'='.$value.'/', '', $url); 
          } 
        } 
      } 
      // add new data 
      foreach($mod as $key => $value) 
      { 
        if($value && !preg_match('/'.$key.'=/', $url)) 
        { 
          $url .= $queryStart.$key.'='.$value; 
        } 
      } 
      return $url; 
    } 
    ?>
    
    Here's a simple class I made that makes use of this parse_url.
    I needed a way for a page to retain get parameters but also edit or add onto them. 
    I also had some pages that needed the same GET paramaters so I also added a way to change the path.
    <?php
    class Paths{
      private $url;
      public function __construct($url){
        $this->url = parse_url($url);
      }
      
      public function returnUrl(){
        $return = $this->url['path'].'?'.$this->url['query'];
        $return = (substr($return,-1) == "&")? substr($return,0,-1) : $return;
        $this->resetQuery();
        return $return;
      }
      
      public function changePath($path){
        $this->url['path'] = $path;
      }
      
      public function editQuery($get,$value){
        $parts = explode("&",$this->url['query']);
        $return = "";
        foreach($parts as $p){
          $paramData = explode("=",$p);
          if($paramData[0] == $get){
            $paramData[1] = $value;
          }
          $return .= implode("=",$paramData).'&';
          
        }
        
        $this->url['query'] = $return;
      }
      
      public function addQuery($get,$value){
        $part = $get."=".$value;
        $and = ($this->url['query'] == "?") ? "" : "&";
        $this->url['query'] .= $and.$part;
      }
      
      public function checkQuery($get){
        $parts = explode("&",$this->url['query']);
        
          foreach($parts as $p){
            $paramData = explode("=",$p);
            if($paramData[0] == $get)
              return true;
          }
          return false;
        
      }
      
      public function buildQuery($get,$value){
        if($this->checkQuery($get))
          $this->editQuery($get,$value);
        else
          $this->addQuery($get,$value);
        
      }
      
      public function resetQuery(){
        $this->url = parse_url($_SERVER['REQUEST_URI']);
      }
      
      
      
    }
    ?>
    Useage:
    Test.php?foo=1:
    <?php
    $path = new Paths($_SERVER['REQUEST_URI']);
    $path->changePath("/baz.php");
    $path->buildQuery("foo",2);
    $path->buildQuery("bar",3);
    echo $path->returnUrl();
    ?>
    returns: /baz.php?foo=2&bar=3  
    Hope this is of some use to someone!
    UTF-8 aware parse_url() replacement.
    I've realized that even though UTF-8 characters are not allowed in URL's, I have to work with a lot of them and parse_url() will break.
    Based largely on the work of "mallluhuct at gmail dot com", I added parse_url() compatible "named values" which makes the array values a lot easier to work with (instead of just numbers). I also implemented detection of port, username/password and a back-reference to better detect URL's like this: //en.wikipedia.com
    ... which, although is technically an invalid URL, it's used extensively on sites like wikipedia in the href of anchor tags where it's valid in browsers (one of the types of URL's you have to support when crawling pages). This will be accurately detected as the host name instead of "path" as in all other examples.
    I will submit my complete function (instead of just the RegExp) which is an almost "drop-in" replacement for parse_url(). It returns a cleaned up array (or false) with values compatible with parse_url(). I could have told the preg_match() not to store the unused extra values, but it would complicate the RegExp and make it more difficult to read, understand and extend. The key to detecting UTF-8 characters is the use of the "u" parameter in preg_match().
    <?php
    function parse_utf8_url($url)
    {
      static $keys = array('scheme'=>0,'user'=>0,'pass'=>0,'host'=>0,'port'=>0,'path'=>0,'query'=>0,'fragment'=>0);
      if (is_string($url) && preg_match(
          '~^((?P<scheme>[^:/?#]+):(//))?((\\3|//)?(?:(?P<user>[^:]+):(?P<pass>[^@]+)@)?(?P<host>[^/?:#]*))(:(?P<port>\\d+))?' .
          '(?P<path>[^?#]*)(\\?(?P<query>[^#]*))?(#(?P<fragment>.*))?~u', $url, $matches))
      {
        foreach ($matches as $key => $value)
          if (!isset($keys[$key]) || empty($value))
            unset($matches[$key]);
        return $matches;
      }
      return false;
    }
    ?>
    UTF-8 URL's can/should be "normalized" after extraction with this function.
    Hello, for some odd reason, parse_url returns the host (ex. example.com) as the path when no scheme is provided in the input url. So I've written a quick function to get the real host:
    <?php
    function getHost($Address) {
      $parseUrl = parse_url(trim($Address));
      return trim($parseUrl[host] ? $parseUrl[host] : array_shift(explode('/', $parseUrl[path], 2)));
    }
    getHost("example.com"); // Gives example.com
    getHost("http://example.com"); // Gives example.com
    getHost("www.example.com"); // Gives www.example.com
    getHost("http://example.com/xyz"); // Gives example.com
    ?>
    You could try anything! It gives the host (including the subdomain if exists).
    Hope it helped you.
    https://vb.3dlat.com/
    <?php
    function url_parse($url){
    $sflfdfldf=$url;
    if(strpos($url,"?")>-1){
    $a=explode("?",$url,2);
    $url=$a[0];
    $query=$a[1];
    }
    if(strpos($url,"://")>-1){
    $scheme=substr($url,0,strpos($url,"//")-1);
    $url=substr($url,strpos($url,"//")+2,strlen($url));
    }
    if(strpos($url,"/")>-1){
    $a=explode("/",$url,2);
    $url=$a[0];
    $path="/".$a[1];
    }
    if(strpos($url,":")>-1){
    $a=explode(":",$url,2);
    $url=$a[0];
    $port=$a[1];
    }
    $host=$url;
    $url=null;
    foreach(array("url","scheme","host","port","path","query") as $var){
    if(!empty($$var)){
    $return[$var]=$$var;
    }
    }
    //return array("url"=>$sflfdfldf,"scheme"=>$scheme,"host"=>$host,"port"=>$port,"path"=>$path,"query"=>$query,"a"=>$url);
    return $return;
    }
    ?>
    <?php
    /* Compare two outputs */
    //mine
    print_r(url_parse("http://login.yahoo.com?.src=ym&.intl=gb&.lang=zh-Hans-HK&.done=https://mail.yahoo.com"));
    //internal
    print_r(parse_url("http://login.yahoo.com?.src=ym&.intl=gb&.lang=zh-Hans-HK&.done=https://mail.yahoo.com"));
    ?>
    
    Thanks to xellisx for his parse_query function. I used it in one of my projects and it works well. But it has an error. I fixed the error and improved it a little bit. Here is my version of it:
    <?php
    // Originally written by xellisx
    function parse_query($var)
     {
     /**
      * Use this function to parse out the query array element from
      * the output of parse_url().
      */
     $var = parse_url($var, PHP_URL_QUERY);
     $var = html_entity_decode($var);
     $var = explode('&', $var);
     $arr = array();
     foreach($var as $val)
      {
      $x     = explode('=', $val);
      $arr[$x[0]] = $x[1];
      }
     unset($val, $x, $var);
     return $arr;
     }
    ?>
    At the first line there was parse_query($val), I made it $var. It used to return a null array before this fix.
    I have added the parse_url line. So now the function will only focus in the query part, not the whole URL. This is useful if something like below is done:
    <?php
    $my_GET = parse_query($_SERVER['REQUEST_URI']);
    ?>
    
    Hello, for some odd reason, parse_url returns the host (ex. example.com) as the path when no scheme is provided in the input url. So I've written a quick function to get the real host:
    <?php
    function getHost($Address) {
      $parseUrl = parse_url(trim($Address));
      return trim($parseUrl[host] ? $parseUrl[host] : array_shift(explode('/', $parseUrl[path], 2)));
    }
    getHost("example.com"); // Gives example.com
    getHost("http://example.com"); // Gives example.com
    getHost("www.example.com"); // Gives www.example.com
    getHost("http://example.com/xyz"); // Gives example.com
    ?>
    You could try anything! It gives the host (including the subdomain if exists).
    Hope it helped you.
    parse_url() does not parse some obvious errors so I made a complementary function
    function url_check(string $url){
        $sym = null;
      
        $len = strlen($url);
        for ($i=0; $i<$len; $i++){
          if ($url[$i] == '?'){
            if ($sym == '?' || $sym == '&')
              return false;
      
            $sym = '?';
          }elseif ($url[$i] == '&'){
            if ($sym === null)
              return false;
      
            $sym = '&';
          } 
        }
        return true;
      }
    }
    There's a quirk where this function will return the host as the "path" if there is a leading space.
    <?php
    $url = ' https://foobar.com:80/mypath/myfile.php';
    print_r(parse_url($url));
    /*
    Array
    (
      [path] => https://foobar.com:80/mypath/myfile.php
    )
    */
    print_r(trim(parse_url($url)));
    /*
    Array
    (
      [scheme] => https
      [host] => foobar.com
      [port] => 80
      [path] => /mypath/myfile.php
    )
    */
    ?>
    
    There is a change in PHP 7 (I noticed it in 7.1 upgrading from 5.3) where if the password portion has an octothorpe (#) in it, parsing fails in 7.1, whereas it succeeds in 5.3.
    To get the params (url query) as Associative array, use this function: 
    <?php 
    /** 
    * Returns the url query as associative array 
    * 
    * @param  string  query 
    * @return  array  params 
    */ 
    function convertUrlQuery($query) { 
      $queryParts = explode('&', $query); 
      
      $params = array(); 
      foreach ($queryParts as $param) { 
        $item = explode('=', $param); 
        $params[$item[0]] = $item[1]; 
      } 
      
      return $params; 
    } 
    ?>
    
    this is my 404 error page is this ok or it need improvements 
    <?php
    /**
     * 404.php
     *
     * The template for displaying 404 pages (not found)
     *
     * @author  BetterStudio
     * @package  Publisher
     * @version  2.0.2
     */
    get_header();
    // Shows breadcrumb
    if ( publisher_show_breadcrumb() ) {
      Better_Framework() >breadcrumb() >generate( array(
        'before'    => '<div class="container bf-breadcrumb-container">',
        'after'    => '</div>',
        'custom_class' => 'bc-top-style'
      ) );
    }
    ?>
      <div class="content-wrap">
        <main <?php publisher_attr( 'content', '' ); ?>>
          <div class="container layout-1-col layout-no-sidebar">
            <div class="row main-section">
              <div class="content-column content-404">
                <div class="row first-row">
                  <div class="col-lg-12 text-404-section">
                    <p class="text-404 heading-typo">404</p>
                  </div>
                  <div class="col-lg-12 desc-section">
                    <h1 class="title-404"><?php publisher_translation_echo( '404_not_found' ); ?></h1>
                    <p><?php publisher_translation_echo( '404_not_found_message' ); ?></p>
                    <div class="action-links clearfix">
                      <script type="text/javascript">
                        if (document.referrer) {
                          document.write('<div class="search-action-container"><a href="' + document.referrer + '"><i class="fa fa-angle-double-right"></i> <?php publisher_translation_echo( '404_go_previous_page' ); ?></a></div>');
                        }
                      </script>
                      <div class="search-action-container">
                        <a href="<?php echo esc_url( home_url( '/' ) ); ?>"><i
                              class="fa fa-angle-double-right"></i> <?php publisher_translation_echo( '404_go_homepage' ); ?>
                        </a>
                      </div>
                    </div>
                  </div>
                </div><!-- .first-row -->
                <div class="row second-row">
                  <div class="col-lg-12">
                    <div class="top-line">
                      <?php get_search_form(); ?>
                    </div>
                  </div>
                </div><!-- .second-row -->
              </div><!-- .content-column -->
            </div><!-- .main-section -->
          </div> <!-- .layout-1-col -->
        </main><!-- main -->
      </div><!-- .content-wrap -->
    <?php get_footer(); ?> 
    https://bramg.net
    This function will attempt to parse relative URLs but relaying on it can produce unexpected behavior that can cause some hard to track bugs. (The following results are obtained from PHP 5.5.19)
    Attempting to parse a url like this
    http://example.com/entities/GOA:98/?search=8989157d1f22
    Correctly produces
    <?php
    array (
     'scheme' => 'http',
     'host' => 'example.com',
     'path' => '/entities/GOA:98/',
     'query' => 'search=8989157d1f22',
    );
    ?>
    However, Attempting to parse the relative URL
    entities/GOA:98/?search=8989157d1f22
    <?php
    array (
     'host' => 'entities',
     'port' => 98,
     'path' => '/GOA:98/',
     'query' => 'search=8989157d1f22',
    )
    ?>
    If I change :98 to :A98 parse_url parses the URL correctly as
    <?php
    array (
     'path' => 'entities/GOA:A98/',
     'query' => 'search=8989157d1f22',
    )
    ?>
    Bottom line, Avoid using parse_url for relative urls unless you have tested the expected input and you know parse_url will handle them well.
    https://forums.hawacastle.com/
    I've been working on a generic class that would make URI parsing / building a little easier.
    The composer package is here: https://packagist.org/packages/enrise/urihelper
    And the repository is here: https://github.com/Enrise/UriHelper
    An example of the usage:
    <?php
    $uri = new \Enrise\Uri('http://usr:pss@example.com:81/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment');
    echo $uri->getScheme(); // http
    echo $uri->getUser(); // usr
    echo $uri->getPass(); // pss
    echo $uri->getHost(); // example.com
    echo $uri->getPort(); // 81
    echo $uri->getPath(); // /mypath/myfile.html
    echo $uri->getQuery(); // a=b&b[]=2&b[]=3
    echo $uri->getFragment(); // myfragment
    echo $uri->isSchemeless(); // false
    echo $uri->isRelative(); // false
    $uri->setScheme('scheme:child:scheme.VALIDscheme123:');
    $uri->setPort(null);
    echo $uri->getUri(); //scheme:child:scheme.VALIDscheme123:usr:pss@example.com/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment
    ?>
    
    parse_url doesn't works if the protocol doesn't specified. This seems like sandard, even the youtube doesn't gives the protocol name when generates code for embedding which have a look like "//youtube.com/etc".
    So, to avoid bug, you must always check, whether the provided url has the protocol, and if not (starts with 2 slashes) -- add the "http:" prefix.
    Here's a piece of code that modifies, replaces or removes the url query. This can typically used in paging situations where there are more parameters than the page.
    <?php
    function modify_url($mod)
    {
      $url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
      $query = explode("&", $_SERVER['QUERY_STRING']);
      // modify/delete data
      foreach($query as $q)
      {
        list($key, $value) = explode("=", $q);
        if(array_key_exists($key, $mod))
        {
          if($mod[$key])
          {
            $url = preg_replace('/'.$key.'='.$value.'/', $key.'='.$mod[$key], $url);
          }
          else
          {
            $url = preg_replace('/&?'.$key.'='.$value.'/', '', $url);
          }
        }
      }
      // add new data
      foreach($mod as $key => $value)
      {
        if($value && !preg_match('/'.$key.'=/', $url))
        {
          $url .= '&'.$key.'='.$value;
        }
      }
      return $url;
    }
    // page url: "http://www.example.com/page.php?p=5&show=list&style=23"
    $url = modify_url(array('p' => 4, 'show' => 'column'));
    // $url = "http://www.example.com/page.php?p=4&show=column&style=23"
    ?>
    
    Simple static library that allows easy manipulation of url parameters:
    <?php
      /**
       * File provides easy way to manipulate url parameters
       * @author Alexander Podgorny
       */
      class Url {
        /**
         * Splits url into array of it's pieces as follows:
         * [scheme]://[user]:[pass]@[host]/[path]?[query]#[fragment]
         * In addition it adds 'query_params' key which contains array of 
         * url-decoded key-value pairs
         *
         * @param String $sUrl Url
         * @return Array Parsed url pieces
         */
        public static function explode($sUrl) {
          $aUrl = parse_url($sUrl);
          $aUrl['query_params'] = array();
          $aPairs = explode('&', $aUrl['query']);
          DU::show($aPairs);
          foreach($aPairs as $sPair) {
            if (trim($sPair) == '') { continue; }
            list($sKey, $sValue) = explode('=', $sPair);
            $aUrl['query_params'][$sKey] = urldecode($sValue);
          }
          return $aUrl;
        }
        /**
         * Compiles url out of array of it's pieces (returned by explodeUrl)
         * 'query' is ignored if 'query_params' is present
         * 
         * @param Array $aUrl Array of url pieces
         */
        public static function implode($aUrl) {
          //[scheme]://[user]:[pass]@[host]/[path]?[query]#[fragment]
          
          $sQuery = '';
          
          // Compile query
          if (isset($aUrl['query_params']) && is_array($aUrl['query_params'])) {
            $aPairs = array();
            foreach ($aUrl['query_params'] as $sKey=>$sValue) {
              $aPairs[] = $sKey.'='.urlencode($sValue);        
            }
            $sQuery = implode('&', $aPairs);  
          } else {
            $sQuery = $aUrl['query'];
          }
          
          // Compile url
          $sUrl = 
            $aUrl['scheme'] . '://' . (
              isset($aUrl['user']) && $aUrl['user'] != '' && isset($aUrl['pass']) 
                ? $aUrl['user'] . ':' . $aUrl['pass'] . '@' 
                : ''
            ) .
            $aUrl['host'] . (
              isset($aUrl['path']) && $aUrl['path'] != ''
                ? $aUrl['path']
                : ''
            ) . (
              $sQuery != ''
                ? '?' . $sQuery
                : ''
            ) . (
              isset($aUrl['fragment']) && $aUrl['fragment'] != ''
                ? '#' . $aUrl['fragment']
                : ''
            );
          return $sUrl;
        }
        /**
         * Parses url and returns array of key-value pairs of url params
         *
         * @param String $sUrl
         * @return Array
         */
        public static function getParams($sUrl) {
          $aUrl = self::explode($sUrl);
          return $aUrl['query_params'];
        }
        /**
         * Removes existing url params and sets them to those specified in $aParams
         *
         * @param String $sUrl Url
         * @param Array $aParams Array of Key-Value pairs to set url params to
         * @return String Newly compiled url 
         */
        public static function setParams($sUrl, $aParams) {
          $aUrl = self::explode($sUrl);
          $aUrl['query'] = '';
          $aUrl['query_params'] = $aParams;
          return self::implode($aUrl);
        }
        /**
         * Updates values of existing url params and/or adds (if not set) those specified in $aParams
         *
         * @param String $sUrl Url
         * @param Array $aParams Array of Key-Value pairs to set url params to
         * @return String Newly compiled url 
         */
        public static function updateParams($sUrl, $aParams) {
          $aUrl = self::explode($sUrl);
          $aUrl['query'] = '';
          $aUrl['query_params'] = array_merge($aUrl['query_params'], $aParams);
          return self::implode($aUrl);
        }
      }
    ?>
    
    Some example that determines the URL port. 
    When port not specified, it derives it from the scheme.
    <?php
    function getUrlPort( $urlInfo )
    {
      if( isset($urlInfo['port']) ) {
        $port = $urlInfo['port'];
      } else { // no port specified; get default port
        if (isset($urlInfo['scheme']) ) {
          switch( $urlInfo['scheme'] ) {
            case 'http':
              $port = 80; // default for http
              break;
            case 'https':
              $port = 443; // default for https
              break;
            case 'ftp':
              $port = 21; // default for ftp
              break;
            case 'ftps':
              $port = 990; // default for ftps
              break;
            default:
              $port = 0; // error; unsupported scheme
              break;
          }
        } else {
          $port = 0; // error; unknown scheme
        }
      }
      return $port;
    }
    $url = "http://nl3.php.net/manual/en/function.parse-url.php";
    $urlInfo = parse_url( $url );
    $urlPort = getUrlPort( $urlInfo );
    if( $urlPort !== 0 ) {
      print 'Found URL port: '.$urlPort;
    } else {
      print 'ERROR: Could not find port at URL: '.$url;
    }
    ?>
    
    I need to parse out the query string from the referrer, so I created this function.
    <?php
    function parse_query($val)
     {
     /** 
      * Use this function to parse out the query array element from
      * the output of parse_url().
      */
     $var = html_entity_decode($var);
     $var = explode('&', $var);
     $arr = array();
     foreach($var as $val)
      {
      $x     = explode('=', $val);
      $arr[$x[0]] = $x[1];
      }
     unset($val, $x, $var);
     return $arr;
     }
    ?>
    
    URL's in the query string of a relative URL will cause a problem
    fails:
    /page.php?foo=bar&url=http://www.example.com
    parses:
    http://www.foo.com/page.php?foo=bar&url=http://www.example.com
    It seems the host-part strips off the last [:port] off the end of the hostname
    When something is wrong in the actual request, this proves to be the wrong way to do things.
    It would be better to not strip off the [:port], but to keep the string *before* the first [:port] as the hostname.
    Problem with (maybe malformed) provided HTTP_HOST
    hostname:443:443
    that resolved in
    'host' => 'hostname:443'
    Which gave me problems.
    Solution would be to enforce this yourself, explicitly:
    <?php
    $p = parse_url( $url );
    $host = explode(':', $p['host']);
    $hostname = $host[0];
    ?>
    
    Here's the easiest way to get the URL to the path that your script is in (so not the actual script name itself, just the complete URL to the folder it's in)
    echo "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);
    Note that older versions of PHP (e.g., 4.1) returned an blank string as the path for URLs without any path, such as http://www.php.net
    However more recent versions of PHP (e.g., 4.4.7) don't set the path element in the array, so old code will get a PHP warning about an undefined index.
    In reply to adrian,
    Thank you very much for your function. There is a small issue with your relative protocol function. You need to remove the // when making the url the path. Here is the new function.
    function resolve_url($base, $url) {
        if (!strlen($base)) return $url;
        // Step 2
        if (!strlen($url)) return $base;
        // Step 3
        if (preg_match('!^[a-z]+:!i', $url)) return $url;
        $base = parse_url($base);
        if ($url{0} == "#") {
            // Step 2 (fragment)
            $base['fragment'] = substr($url, 1);
            return unparse_url($base);
        }
        unset($base['fragment']);
        unset($base['query']);
        if (substr($url, 0, 2) == "//") {
            // Step 4
            return unparse_url(array(
                'scheme'=>$base['scheme'],
                'path'=>substr($url,2),
            ));
        } else if ($url{0} == "/") {
            // Step 5
            $base['path'] = $url;
        } else {
            // Step 6
            $path = explode('/', $base['path']);
            $url_path = explode('/', $url);
            // Step 6a: drop file from base
            array_pop($path);
            // Step 6b, 6c, 6e: append url while removing "." and ".." from
            // the directory portion
            $end = array_pop($url_path);
            foreach ($url_path as $segment) {
                if ($segment == '.') {
                    // skip
                } else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') {
                    array_pop($path);
                } else {
                    $path[] = $segment;
                }
            }
            // Step 6d, 6f: remove "." and ".." from file portion
            if ($end == '.') {
                $path[] = '';
            } else if ($end == '..' && $path && $path[sizeof($path)-1] != '..') {
                $path[sizeof($path)-1] = '';
            } else {
                $path[] = $end;
            }
            // Step 6h
            $base['path'] = join('/', $path);
        }
        // Step 7
        return unparse_url($base);
    }
    I searched for an implementation of rfc3986, which is a newer version of rfc 2392. I may find it here : <http://www.chrsen.dk/fundanemt/files/scripter/php/misc/rfc3986.php> - read the rfc at <http://rfc.net/rfc3986.html>
    Here's a function which implements resolving a relative URL according to RFC 2396 section 5.2. No doubt there are more efficient implementations, but this one tries to remain close to the standard for clarity. It relies on a function called "unparse_url" to implement section 7, left as an exercise for the reader (or you can substitute the "glue_url" function posted earlier).
    <?php
    /**
     * Resolve a URL relative to a base path. This happens to work with POSIX
     * filenames as well. This is based on RFC 2396 section 5.2.
     */
    function resolve_url($base, $url) {
        if (!strlen($base)) return $url;
        // Step 2
        if (!strlen($url)) return $base;
        // Step 3
        if (preg_match('!^[a-z]+:!i', $url)) return $url;
        $base = parse_url($base);
        if ($url{0} == "#") {
            // Step 2 (fragment)
            $base['fragment'] = substr($url, 1);
            return unparse_url($base);
        }
        unset($base['fragment']);
        unset($base['query']);
        if (substr($url, 0, 2) == "//") {
            // Step 4
            return unparse_url(array(
                'scheme'=>$base['scheme'],
                'path'=>$url,
            ));
        } else if ($url{0} == "/") {
            // Step 5
            $base['path'] = $url;
        } else {
            // Step 6
            $path = explode('/', $base['path']);
            $url_path = explode('/', $url);
            // Step 6a: drop file from base
            array_pop($path);
            // Step 6b, 6c, 6e: append url while removing "." and ".." from
            // the directory portion
            $end = array_pop($url_path);
            foreach ($url_path as $segment) {
                if ($segment == '.') {
                    // skip
                } else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') {
                    array_pop($path);
                } else {
                    $path[] = $segment;
                }
            }
            // Step 6d, 6f: remove "." and ".." from file portion
            if ($end == '.') {
                $path[] = '';
            } else if ($end == '..' && $path && $path[sizeof($path)-1] != '..') {
                $path[sizeof($path)-1] = '';
            } else {
                $path[] = $end;
            }
            // Step 6h
            $base['path'] = join('/', $path);
        }
        // Step 7
        return unparse_url($base);
    }
    ?>
    
    Note that if you pass this function a url without a scheme (www.php.net, as opposed to http://www.php.net), the function will incorrectly parse the results. In my test case it returned the domain under the ['path'] element and nothing in the ['host'] element.
    Heres a simple function to add the $component option in for PHP4. Haven't done exhaustive testing, but should work ok.
    <?php
      ## Defines only available in PHP 5, created for PHP4
      if(!defined('PHP_URL_SCHEME')) define('PHP_URL_SCHEME', 1);
      if(!defined('PHP_URL_HOST')) define('PHP_URL_HOST', 2);
      if(!defined('PHP_URL_PORT')) define('PHP_URL_PORT', 3);
      if(!defined('PHP_URL_USER')) define('PHP_URL_USER', 4);
      if(!defined('PHP_URL_PASS')) define('PHP_URL_PASS', 5);
      if(!defined('PHP_URL_PATH')) define('PHP_URL_PATH', 6);
      if(!defined('PHP_URL_QUERY')) define('PHP_URL_QUERY', 7);            
      if(!defined('PHP_URL_FRAGMENT')) define('PHP_URL_FRAGMENT', 8);  
      
      function parse_url_compat($url, $component=NULL){
        
        if(!$component) return parse_url($url);
        
        ## PHP 5
        if(phpversion() >= 5)
          return parse_url($url, $component);
        ## PHP 4
        $bits = parse_url($url);
        
        switch($component){
          case PHP_URL_SCHEME: return $bits['scheme'];
          case PHP_URL_HOST: return $bits['host'];
          case PHP_URL_PORT: return $bits['port'];
          case PHP_URL_USER: return $bits['user'];
          case PHP_URL_PASS: return $bits['pass'];
          case PHP_URL_PATH: return $bits['path'];
          case PHP_URL_QUERY: return $bits['query'];
          case PHP_URL_FRAGMENT: return $bits['fragment'];
        }
        
      }
    ?>
    
    Hi,
    if you have problems with UTF8 encoded urls please see http://bugs.php.net/bug.php?id=52923 . parse_url breaks the utf8. :( You have to implement it yourself.
    If you need check if URL exists or not, here is one my good function for that.
    <?php
    // Return false or URL
    function url_exists($url='')
    {
      if(empty($url)) return false;
      $curl = curl_init($url);
      //don't fetch the actual page, you only want to check the connection is ok
      curl_setopt($curl, CURLOPT_NOBODY, true);
      curl_setopt($curl, CURLOPT_CONNECTTIMEOUT ,5); 
      curl_setopt($curl, CURLOPT_TIMEOUT , 2);
      //do request
      $result = curl_exec($curl);
      //if request did not fail
      if ($result !== false) {
        //if request was ok, check response code
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 
        if ((int)$statusCode === 200) return $url; 
        return false; 
      }
      curl_close($curl);
      return false;
    }
    if(url_exists("http://www.google.com")!==false)
    {
      // URL Exists
    }
    ?>
    This can help if you decide to do some dynamic URL parser or something where need validations.
    an update to the glue url function.
    you are able to put a host and a path without a slash at the beginning of the path
    <?php
    function glue_url($parsed) 
      {
      if (! is_array($parsed)) return false;
      $uri = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '':'//'): '';
      $uri .= isset($parsed['user']) ? $parsed['user'].($parsed['pass']? ':'.$parsed['pass']:'').'@':'';
      $uri .= isset($parsed['host']) ? $parsed['host'] : '';
      $uri .= isset($parsed['port']) ? ':'.$parsed['port'] : '';
      if(isset($parsed['path']))
        {
        $uri .= (substr($parsed['path'],0,1) == '/')?$parsed['path']:'/'.$parsed['path'];
        }
      $uri .= isset($parsed['query']) ? '?'.$parsed['query'] : '';
      $uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
      return $uri;
      }
    ?>
    
    this is my 404 error page is this ok or it need improvements 
    <?php
    /**
     * 404.php
     *
     * The template for displaying 404 pages (not found)
     *
     * @author  BetterStudio
     * @package  Publisher
     * @version  2.0.2
     */
    get_header();
    // Shows breadcrumb
    if ( publisher_show_breadcrumb() ) {
      Better_Framework() >breadcrumb() >generate( array(
        'before'    => '<div class="container bf-breadcrumb-container">',
        'after'    => '</div>',
        'custom_class' => 'bc-top-style'
      ) );
    }
    ?>
      <div class="content-wrap">
        <main <?php publisher_attr( 'content', '' ); ?>>
          <div class="container layout-1-col layout-no-sidebar">
            <div class="row main-section">
              <div class="content-column content-404">
                <div class="row first-row">
                  <div class="col-lg-12 text-404-section">
                    <p class="text-404 heading-typo">404</p>
                  </div>
                  <div class="col-lg-12 desc-section">
                    <h1 class="title-404"><?php publisher_translation_echo( '404_not_found' ); ?></h1>
                    <p><?php publisher_translation_echo( '404_not_found_message' ); ?></p>
                    <div class="action-links clearfix">
                      <script type="text/javascript">
                        if (document.referrer) {
                          document.write('<div class="search-action-container"><a href="' + document.referrer + '"><i class="fa fa-angle-double-right"></i> <?php publisher_translation_echo( '404_go_previous_page' ); ?></a></div>');
                        }
                      </script>
                      <div class="search-action-container">
                        <a href="<?php echo esc_url( home_url( '/' ) ); ?>"><i
                              class="fa fa-angle-double-right"></i> <?php publisher_translation_echo( '404_go_homepage' ); ?>
                        </a>
                      </div>
                    </div>
                  </div>
                </div><!-- .first-row -->
                <div class="row second-row">
                  <div class="col-lg-12">
                    <div class="top-line">
                      <?php get_search_form(); ?>
                    </div>
                  </div>
                </div><!-- .second-row -->
              </div><!-- .content-column -->
            </div><!-- .main-section -->
          </div> <!-- .layout-1-col -->
        </main><!-- main -->
      </div><!-- .content-wrap -->
    <?php get_footer(); ?> 
    https://bramg.net
    Another update to the glue_url function: applied the "isset" treatment to $parsed['pass'].
    <?php
    function glue_url($parsed)
    {
      if (!is_array($parsed)) return false;
      $uri = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '' : '//') : '';
      $uri .= isset($parsed['user']) ? $parsed['user'].(isset($parsed['pass']) ? ':'.$parsed['pass'] : '').'@' : '';
      $uri .= isset($parsed['host']) ? $parsed['host'] : '';
      $uri .= isset($parsed['port']) ? ':'.$parsed['port'] : '';
      if(isset($parsed['path']))
      {
        $uri .= (substr($parsed['path'], 0, 1) == '/') ? $parsed['path'] : ('/'.$parsed['path']);
      }
      $uri .= isset($parsed['query']) ? '?'.$parsed['query'] : '';
      $uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
      return $uri;
    }
    ?>