|
parse_url
Parse a URL and return its components
(PHP 4, PHP 5)
Example 2572. A parse_url() example<?php The above example will output: Array Related Examples ( Source code ) » parse_url Examples ( Source code ) » Feed Validator Code Examples / Notes » parse_urltheshadow
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 dawalama
With few modifications /** * source: http://us2.php.net/manual/en/function.parse-url.php#60237 * 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 change_query($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 $ending = ""; } else { $beginning = substr($uri, 0, $qstart); $ending = substr($uri, $qstart); } } $vals = array (); $ending = str_replace('?', '', $ending); parse_str($ending, $vals); switch ($action) { case '+' : $vals[$var[0]] = $var[1]; break; case '-' : if (isset ($vals[$var])) { unset ($vals[$var]); } break; default : break; } $params = array(); foreach ($vals as $k => $value) { $params[] = $k."=".urlencode($value); } $result = $beginning . (count($params) ? '?' . implode("&", $params) : ''); return $result; } nick smith
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. elliott brueggeman
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.
matt
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; } ?> php dot net
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; } spam
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); } christian
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>
corgilabs
I hope this is helpful! Cheers! -eo <? # Author: Eric O # Date: July 13, 2006 # Go Zizou!! :O) # Creating Automatic Self-Redirect To Secure Version # of Website as Seen on Paypal and other secure sites # Changes HTTP to HTTPS #gets the URI of the script $url = $_SERVER['SCRIPT_URI']; #chops URI into bits BORK BORK BORK $chopped = parse_url($url); #HOST and PATH portions of your final destination $destination = $chopped[host].$chopped[path]; #if you are not HTTPS, then do something about it if($chopped[scheme] != "https"){ #forwards to HTTP version of URI with secure certificate header("Location: https://$destination"); exit(); } ?> alistair
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']; } } ?> adrian-php
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); } ?> kjensen
Here is a simple extended version of ParseURL(). I needed to make a link that will be saved off site but point to different file than the one creating the link. So I needed to get the path without the file name so I could change the file name. Here it is: <?php function ParseURLplus($url){ $URLpcs = (parse_url($url)); $PathPcs = explode("/",$URLpcs['path']); $URLpcs['file'] = end($PathPcs); unset($PathPcs[key($PathPcs)]); $URLpcs['dir'] = implode("/",$PathPcs); return ($URLpcs); } $url = 'http://username:password@hostname/path/directory/file.php?arg= value#anchor'; $URLpcs = ParseURLplus($url); print_r($URLpcs); ?> Now I can change the $URLpcs['file'] and then glue itback together to make a new url. marc-antoine ross
Do not look for the fragment in $_SERVER['QUERY_STRING'], you will not find it. You should read the fragment in JavaScript for example.
michael muryn
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; } ?> stevenlewis
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; } ?> antti haapala
Actually the behaviour noticed by the previous poster is quite correct. When the URI scheme is not present, it is plain wrong to assume that something starting with www. is a domain name, and that the scheme is HTTP. Internet Explorer does it that way, sure, but it does not make it any more correct. The documentation says that the function tries to decode the URL as well as it can, and the only sensible and standards-compliant way to decode such URL is to expect it to be a relative URI.
|