parse_url

(PHP 3, PHP 4, PHP 5)

parse_url -- 解析 URL,返回其组成部分

描述

array parse_url ( string url )

此函数返回一个关联数组,包含现有 URL 的各种组成部分。如果缺少了其中的某一个,则不会为这个组成部分创建数组项。组成部分为:

  • scheme - 如 http

  • host

  • port

  • user

  • pass

  • path

  • query - 在问号 ? 之后

  • fragment - 在散列符号 # 之后

此函数并 意味着给定的 URL 是合法的,它只是将上方列表中的各部分分开。parse_url() 可接受不完整的 URL,并尽量将其解析正确。

注: 此函数对相对路径的 URL 不起作用。

例子 1. parse_url() 示例

$ php -r 'print_r(parse_url("http://username:password@hostname/path?arg=value#anchor"));'
Array
(
    [scheme] => http
    [host] => hostname
    [user] => username
    [pass] => password
    [path] => /path
    [query] => arg=value
    [fragment] => anchor
)

$ php -r 'print_r(parse_url("http://invalid_host..name/"));'
Array
(
    [scheme] => http
    [host] => invalid_host..name
    [path] => /
)

参见 pathinfo()parse_str()dirname()basename()


add a note add a note User Contributed Notes
Vladimir Kornea
13-May-2006 03:21
See Also http_build_query()

(editors: please add this function to "See Also" section of the official documentation.)
php dot net at NOSPAM dot juamei dot com
09-May-2006 07:18
Modfied version of glue_url to avoid error messages if the error_reporting is set high.

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'] : '';
       $uri .= isset($parsed['path']) ? $parsed['path'] : '';
       $uri .= isset($parsed['query']) ? '?'.$parsed['query'] : '';
       $uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
   return $uri;
}
peyn at tlen dot pl
10-Mar-2006 03:26
a little bugfix to greg dot linton at gmail dot com function:

you have to change:
<?php
else
{
  
$ending = $var[ 0 ] . '=' . urlencode( $var[ 1 ] );
}
?>

with

<?php
else
{
   if(
$action == '+' )
   {
      
$ending = $var[ 0 ] . '=' . urlencode( $var[ 1 ] );
   }
}
?>

otherwise when using function like this
<?php
$url
= ChangeQuery( '-', 'test' );
echo
$url;
?>

you will see: index.php?t=e

best regards
Tyron Madlener
15-Feb-2006 06:24
Oh, missed something. It should be HEAD instead of GET, because it only needs to read the header of the http response.
Tyron Madlener
15-Feb-2006 05:15
I needed to get information about the real URL, because some URL are just redirects to the real one. This function here tracks down the real URL as long as it gets redirects (errorcode 301,302, 303, 305 or 307) as response.
In this example i resolve my homepage www.tyron.at which redirects to a subdirectory.

$real_url = ResolveURL("http://www.tyron.at");

echo "<pre>";
print_r(parse_url($real_url));

function ResolveURL($url) {
  $info = parse_url($url);
  
  //echo "url: '$url'<br><pre>";
  //print_r($info);
  $fp = fsockopen($info['host'],80);

  if($fp) {
   $path = $info['path'];
   if(!strlen($path)) $path = "/";
   if(strlen($info['query'])) $path.="?".$info['query'];

   $out  = "GET $path HTTP/1.1\r\n";
   $out .= "Host: ".$info['host']."\r\n";
   $out .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.8) Gecko/20050511  Firefox/1.0.4\r\n";
   $out .= "Connection: Close\r\n\r\n";   
   fwrite($fp, $out);

   if(ereg("HTTP/1.1 30(1|2|3|5|7)",$resp = fgets($fp,512))) {     
     while (!feof($fp)) {
       if(preg_match("/Location: (.*)$/",$line=fgets($fp, 1024),$matches))
         $url = ResolveURL(chop($matches[1]));
     }
   }
   //echo $resp;
   fclose($fp);
  }
  return $url;
}
12-Jan-2006 07:42
small bugfix to greg dot linton at gmail dot com's very handy changeQuery - blank URIs weren't being processed correctly.

<?php
// line dealing with blank URI's:
$ending = $varName . '=' . urlencode($varVal);

// works if changed to:
$ending = $var[0] . '=' . urlencode($var[1]);

?>
greg dot linton at gmail dot com
31-Dec-2005 05:14
I needed to work both ways (adding & deleteing) query items to the url. Corey's function worked well for adding, but I needed the opposite. I modifed his to work for both ways leaving me with this:
<?php

/**
 * Edit the Query portion of an url
 *
 * @param    string    $action    ethier a "+" or a "-" depending on what action you want to perform
 * @param    mixed    $var    array (+) or string (-)
 * @param    string    $uri    the URL to use. if this is left out, it uses $_SERVER['PHP_SELF']
 * @version      1.0.0
 */
function ChangeQuery($action, $var = NULL, $uri = NULL) {

       if ((
$action == "+" && ! is_array($var))
             ||
           (
$action == "-" && $var == "")
             ||
          
$var == NULL)
               return
FALSE;

   if (
is_null($uri)) {//Piece together uri string
      
$beginning = $_SERVER['PHP_SELF'];
      
$ending = ( isset($_SERVER['QUERY_STRING']) ) ? $_SERVER['QUERY_STRING'] : '';
   } else {
      
$qstart = strpos($uri, '?');
       if (
$qstart === false) {
          
$beginning = $uri; //$ending is '' anyway
      
} else {
          
$beginning = substr($uri, 0, $qstart);
          
$ending = substr($uri, $qstart);
       }
   }

   if (
strlen($ending) > 0) {
      
$vals = array();
      
$ending = str_replace('?','', $ending);
      
parse_str($ending, $vals);
               if (
$action == "+")
                      
$vals[$var[0]] = $var[1];
      
$ending = '';
      
$count = 0;
       foreach(
$vals as $k => $v) {
           if (
$action == "-" && $k == $var) continue;
           if (
$count > 0) { $ending .= '&'; }
           else {
$count++; }
          
$ending .= "$k=" . urlencode($v);
       }
   } else {
          
$ending = $varName . '=' . urlencode($varVal);
   }

  
$result = $beginning . '?' . $ending;

   return
$result;
}
?>

with this test:
<?php
$url
= "http://www.somesite.com/somepage.php?id=53&sec=1&sort=up";

$url = ChangeQuery("+",array("test",5),$url);
echo
$url."<br>";
$url = ChangeQuery("-","sort", $url);
echo
$url."<br>";
$url = ChangeQuery("-","test", $url);
echo
$url."<br>";
$url = ChangeQuery("+",array("sort","dn"), $url);
echo
$url."<br>";

?>

I got
http://www.somesite.com/somepage.php?id=53&sec=1&sort=up&test=5
http://www.somesite.com/somepage.php?id=53&sec=1&test=5
http://www.somesite.com/somepage.php?id=53&sec=1
http://www.somesite.com/somepage.php?id=53&sec=1&sort=dn

?>
If you're adding to the url, the second argument has to be an array, where the first element is the name and the second is the value. If you're deleting from the query, it's the name of var to delete

I hope this helps somebody down the line.
jon _at_ gaarsmand _dot_ com
02-Aug-2005 03:51
Some developers look here for a mean of validating an url. So here is a simple way of validating an url.

$uri = 'http://some-domain-name.org';
if( preg_match( '/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}'
       .'((:[0-9]{1,5})?\/.*)?$/i' ,$uri))
{
  echo $uri . ' is a valid url';
}
else
{
  echo $uri . ' is NOT a valid url';
}

Beware - it only validates scemes: http and https, and it only takes into account host and port part of the uri. It does not accept username and password.

For an email validator you could look at http://gaarsmand.com/index.php/IT_l%F8sninger/Kode_eksempler/PHP_kode.
scott a t connerly d o t net
07-Mar-2005 03:34
re: <b>osfist at yahoo dot com</b>'s http_implode function. 
Here is a companion function for that:

  function http_explode($stringInput) {
   if (! is_string($stringInput))
     return false;
   $arr_query=NULL;
   $args=explode('&',$stringInput);
   foreach($args as $arg) {
     $parts=explode('=',$arg);
     $arr_query[$parts[0]]=$parts[1];
   } return $arr_query;
  }
TheShadow
31-Dec-2004 04:36
You may want to check out the PEAR NET_URL class. It provides easy means to manipulate URL strings.

http://pear.php.net/package/Net_URL
corey at eyewantmedia dot com
23-Dec-2004 01:18
Just in case this helps someone, this is a quick and dirty way to add or replace values to your query string, which I found especially useful when modifying urls to allow paging through resultsets.

/**
 * @return string
 * @param string $varName
 * @param string $varVal
 * @param string $uri
 * @desc Returns the a string that is either
 *        $uri if you pass it or the current
 *        uri with the variable name $varName
 *        equal to the value urlencode($varVal)
 *        It replaces a current value if it find
 *        it or adds the variable and value pair
 *        if they are new.
*/
function AddToQuery($varName, $varVal, $uri=null) {
   $result = '';
   $beginning = '';
   $ending = '';
  
   if (is_null($uri)) {//Piece together uri string
       $beginning = $_SERVER['PHP_SELF'];
       $ending = ( isset($_SERVER['QUERY_STRING']) ) ? $_SERVER['QUERY_STRING'] : '';
   } else {
       $qstart = strpos($uri, '?');
       if ($qstart === false) {
           $beginning = $uri; //$ending is '' anyway
       } else {
           $beginning = substr($uri, 0, $qstart);
           $ending = substr($uri, $qstart);
       }
   }
  
   if (strlen($ending) > 0) {
       $vals = array();
       $ending = str_replace('?','', $ending);
       parse_str($ending, $vals);
       $vals[$varName] = $varVal;
       $ending = '';
       $count = 0;
       foreach($vals as $k => $v) {
           if ($count > 0) { $ending .= '&'; }
           else { $count++; }
           $ending .= "$k=" . urlencode($v);
       }
   } else {
       $ending = $varName . '=' . urlencode($varVal);
   }
  
   $result = $beginning . '?' . $ending;
  
   return $result;
}
duellj at gmail dot com
13-Oct-2004 06:13
A quick note about something that tripped me up:

the url you are parsing must include the scheme, or it will be parsed into the 'path' key.
Example:
<?
$parsed
= parse_url("www.php.net");
print_r($parsed);

/*
outputs:
Array
(
   [path] => www.php.net
)
*/
?>
esm at baseclass dot modulweb dot dk
17-Aug-2004 09:32
Hi

I did an URL Validator that also parses the URL into subparts. The validator does not use PHP specific functions, so it can be easily ported to javascript or another language. If you are looking at this page, chances are my validator might interest you.

http://baseclass.modulweb.dk/urlvalidator

Regards
Aceb
matt at cryptography dot com
10-May-2004 04:36
Modified version of glue_url()
Cox's,Anonimous fucntion

<?php
function glue_url($parsed) {
   if (!
is_array($parsed)) return false;
      
$uri = $parsed['scheme'] ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '':'//'): '';
      
$uri .= $parsed['user'] ? $parsed['user'].($parsed['pass']? ':'.$parsed['pass']:'').'@':'';
      
$uri .= $parsed['host'] ? $parsed['host'] : '';
      
$uri .= $parsed['port'] ? ':'.$parsed['port'] : '';
      
$uri .= $parsed['path'] ? $parsed['path'] : '';
      
$uri .= $parsed['query'] ? '?'.$parsed['query'] : '';
      
$uri .= $parsed['fragment'] ? '#'.$parsed['fragment'] : '';
  return
$uri;
}
?>
osfist at yahoo dot com
01-Mar-2004 03:11
Functions to edit a url query key and its value.
You can also add a new query key and its value.

I gathered and modified useful functions for my code.
It works fine as you see at the test result.

<?php
function get_query_edited_url($url, $arg, $val) {
  
$parsed_url = parse_url($url);
  
parse_str($parsed_url['query'],$url_query);
  
$url_query[$arg] = $val;
  
  
$parsed_url['query'] = http_implode($url_query);
  
$url = glue_url($parsed_url);
   return
$url;
}

function
http_implode($arrayInput) {
   if (!
is_array($arrayInput))
       return
false;

  
$url_query="";
   foreach (
$arrayInput as $key=>$value) {
      
      
$url_query .=(strlen($url_query)>1)?'&':"";
      
$url_query .= urlencode($key).'='.urlencode($value);
   }
   return
$url_query;
}

function
glue_url($parsed) {
   if (!
is_array($parsed))
       return
false;
  
  
$url = $parsed['scheme'] ? $parsed['scheme'].':'
      
.((strtolower($parsed['scheme']) == 'mailto') ? '':'//'): '';
  
$url .= $parsed['user'] ? $parsed['user']
       .(
$parsed['pass']? ':'.$parsed['pass']:'').'@':'';
  
$url .= $parsed['host'] ? $parsed['host'] : '';
  
$url .= $parsed['port'] ? ':'.$parsed['port'] : '';
  
$url .= $parsed['path'] ? $parsed['path'] : '';
  
$url .= $parsed['query'] ? '?'.$parsed['query'] : '';
  
$url .= $parsed['fragment'] ? '#'.$parsed['fragment'] : '';
   return
$url;
}

/* Test & Output

$url =
"http://user:pass@host/path?arg1=value&arg2=myval2#anchor";
print  "<br>0:".$url;
print  "<br>1:".get_query_edited_url($url,'arg1','CHANGED'); //Arg1
print  "<br>2:".get_query_edited_url($url,'arg2','CHANGED'); //Arg2
print  "<br>3:".get_query_edited_url($url,'arg3','NEW'); //New Argument
*/

// Output
//http://user:pass@host/path?arg=value&arg2=myval2#anchor
//http://user:pass@host/path?arg=value&arg2=CHANGED#anchor
//http://user:pass@host/path?arg=CHANGED&arg2=myval2#anchor
?>
alan at zeroasterisk dot com
23-Dec-2003 05:06
<?
/*
Alan -- here is a useful function for displaying links...  if you don't do this, an improper query string could mess up html code...  (by having a > or " or something...)

If you have simple improvements or flaws, please email me. [at]zeroasterisk[d0t]com
*/

function linkprep($link)
   {
      
$link_array=parse_url($link);
    
$return= str_replace($link_array['query'], rawurlencode($link_array['query']), $link);
    
$return= str_replace($link_array['fragment'], rawurlencode($link_array['fragment']), $return);
     return
$return;
   }

?>
sjt at 5jt dot com
22-Oct-2003 10:45
It gets better...

parse_str($_SERVER['QUERY_STRING']);

though you might flinch at random names from the URI query string showing up as variables. Safer to secure them in a hash table, eg

   parse_str($_SERVER['QUERY_STRING'],$vars);
   $lang = $vars['lang'];
   echo "Your language is $lang";

sjt
bermi.ferrer ) a t ( akelos dot com
02-Feb-2003 07:23
This is a small update for Steve's function. It removes the Argument even if its repeated more than once in the URL.

This function performance is better than the one I posted before (delete_value_from_url).

 function RemoveArgFromURL($URL,$Arg)
 {
    
   while($Pos = strpos($URL,"$Arg="))
   {

     if ($Pos)
     {
       if ($URL[$Pos-1] == "&")
       {
         $Pos--;
       }
       $nMax = strlen($URL);
       $nEndPos = strpos($URL,"&",$Pos+1);

       if ($nEndPos === false)
       {
       $URL = substr($URL,0,$Pos);
       }
       else
       {
         $URL = str_replace(substr($URL,$Pos,$nEndPos-$Pos),'',$URL);
       }
     }
   }
   return $URL;
 }
steve at mg-rover dot org
25-Jan-2003 01:59
An alternative and more straightforward to the remove an argument from a URL code above is below. I'm not saying its any better than the one above, but its easier to read ;) :p

----------------
  function RemoveArgFromURL($URL,$Arg)
  {
   $Pos = strpos($URL,"$Arg=");
  
   if ($Pos)
   {
     if ($URL[$Pos-1] == "&")
     {
       // If Pos-1 is pointing to a '&' knock Pos back 1 so its removed.
       $Pos--;
     }
     $nMax = strlen($URL);
     $nEndPos = strpos($URL,"&",$Pos+1);

     if ($nEndPos === false)
     {
       // $Arg is on the end of the URL
       $URL = substr($URL,0,$Pos);
     }
     else
     {
       // $Arg is in the URL
       $URL = str_replace(substr($URL,$Pos,$nEndPos-$Pos),'',$URL);
     }
   }
   return $URL;
  }
----------------
Anonimous
09-May-2002 08:51
Modified version of glue_url() Cox's fucntion.
----------------------------------------------

// $parsed is a parse_url() resulting array
function glue_url($parsed) {
  
   if (! is_array($parsed)) return false;

   if (isset($parsed['scheme'])) {
     $sep = (strtolower($parsed['scheme']) == 'mailto' ? ':' : '://');
     $uri = $parsed['scheme'] . $sep;
   } else {
     $uri = '';
   }
 
   if (isset($parsed['pass'])) {
     $uri .= "$parsed[user]:$parsed[pass]@";
   } elseif (isset($parsed['user'])) {
     $uri .= "$parsed[user]@";
   }
 
   if (isset($parsed['host']))    $uri .= $parsed['host'];
   if (isset($parsed['port']))    $uri .= ":$parsed[port]";
   if (isset($parsed['path']))    $uri .= $parsed['path'];
   if (isset($parsed['query']))    $uri .= "?$parsed[query]";
   if (isset($parsed['fragment'])) $uri .= "#$parsed[fragment]";
 
   return $uri;
}