I wrote a simple class to deal with parsing and handling URIs for the project I'm currently working on, since it relies a lot on that functionality (eg the Router class and some HTML helpers). Here is the code already commented:
<?php
# URI class
class uri {
# URI scheme
public $scheme;
# URI host
public $host;
# URI user
public $user;
# URI password
public $password;
# URI port
public $port;
# URI path
public $path;
# URI query
public $query;
# URI fragment
public $fragment;
# Default constructor for the URI
public function __construct($uri = null) {
# No URI is set, the current request URI will be used
if($uri == null) {
# Predefine the empty parts array
$uri_parts = array();
# Extract the scheme part of the URI and add it the to array if https
if(array_key_exists('HTTPS', $_SERVER)) array_push($uri_parts, 'https://');
# Extract the scheme part of the URI and add it the to array if http
if(!array_key_exists('HTTPS', $_SERVER)) array_push($uri_parts, 'http://');
# Extract the host part of the URI and add it to the array if https
if(array_key_exists('SERVER_NAME', $_SERVER)) array_push($uri_parts, $_SERVER['SERVER_NAME']);
# Extract the request URI itself and add it to the array
if(array_key_exists('REQUEST_URI', $_SERVER)) array_push($uri_parts, $_SERVER['REQUEST_URI']);
# Set the URI string to be processed later
$uri = implode($uri_parts);
}
# An URI is provided in string form
if($uri != null and !is_array($uri)) {
# Regular Expression from RFC 2396 (appendix B)
preg_match('"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?"', $uri, $matches);
# Extract the URI scheme from the string
if(array_key_exists(2, $matches)) $this->scheme = $matches[2];
# Extract the URI authority from the string
if(array_key_exists(4, $matches)) $authority = $matches[4];
# Extract the URI path from the string
if(array_key_exists(5, $matches)) $this->path = $matches[5];
# Extract the URI query from the string
if(array_key_exists(7, $matches)) $this->query = $matches[7];
# Extract the URI fragment from the string
if(array_key_exists(9, $matches)) $this->fragment = $matches[9];
# Extract username, password, host and port from authority
preg_match('"(([^:@]*)(:([^:@]*))?@)?([^:]*)(:(.*))?"', $authority, $matches);
# Extract the URI username from the authority part
if(array_key_exists(2, $matches)) $this->user = $matches[2];
# Extract the URI password from the authority part
if(array_key_exists(4, $matches)) $this->password = $matches[4];
# Extract the URI hostname from the authority part
if(array_key_exists(5, $matches)) $this->host = $matches[5];
# Extract the URI port from the authority part
if(array_key_exists(7, $matches)) $this->port = $matches[7];
# Get the rid of the leading path slash if its present in the string
if(substr($this->path, 0, 1) == '/') $this->path = substr($this->path, 1);
# Get the rid of the ending path slash if its present in the string
if(substr($this->path, -1, 1) == '/') $this->path = substr($this->path, 0, -1);
# Set the path to an array by exploding it with the default delimiter
$this->path = explode('/', $this->path);
# Make sure that the array is really empty if the path was empty from the beginning
if(array_key_exists(0, $this->path) and empty($this->path[0])) $this->path = array();
# Split the query string into an array
parse_str($this->query, $query); $this->query = $query;
}
# An URI is provided in array form
if($uri != null and is_array($uri)) {
# Set the scheme of the URI
if(array_key_exists('scheme', $uri)) $this->scheme = $uri['scheme'];
# Set the hostname of the URI
if(array_key_exists('host', $uri)) $this->host = $uri['host'];
# Set the user of the URI
if(array_key_exists('user', $uri)) $this->user = $uri['user'];
# Set the password of the URI if the pass key is used
if(array_key_exists('pass', $uri)) $this->scheme = $uri['pass'];
# Set the password of the URI if the password key is used
if(array_key_exists('password', $uri)) $this->password = $uri['password'];
# Set the port of the URI
if(array_key_exists('port', $uri)) $this->port = $uri['port'];
# Set the path of the URI
if(array_key_exists('path', $uri)) $this->path = $uri['path'];
# Set the query of the URI
if(array_key_exists('query', $uri)) $this->path = $uri['query'];
# Set the fragment of the URI if the anchor key is used
if(array_key_exists('anchor', $uri)) $this->fragment = $uri['anchor'];
# Set the fragment of the URI if the fragment key is used
if(array_key_exists('fragment', $uri)) $this->fragment = $uri['fragment'];
}
}
# Returns the URI as a string
# You can specify what parts should be built
public function build(array $parts = array('scheme', 'user', 'password', 'host', 'path', 'query', 'fragment')) {
# Predefine an array of parts
$uri_parts = array();
# Attach the URI scheme to the parts array if not empty
if(in_array('scheme', $parts) and !empty($this->scheme)) array_push($uri_parts, $this->scheme . '://');
# Attach the URI user to the parts array if not empty
if(in_array('user', $parts) and !empty($this->user)) array_push($uri_parts, $this->user);
# Attach the URI password to the parts array if not empty
if(in_array('password', $parts) and !empty($this->password)) array_push($uri_parts, ':' . $this->password);
# Attach the URI user prefix to the parts array if not empty
if(in_array('user', $parts) and !empty($this->user)) array_push($uri_parts, '@');
# Attach the URI host to the parts array if not empty
if(in_array('host', $parts) and !empty($this->host)) array_push($uri_parts, $this->host.'/');
# Attach the URI path to the parts array if not empty
if(in_array('path', $parts) and count($this->path) > 0) array_push($uri_parts, implode('/', $this->path));
# Attach the URI query to the parts array if not empty
if(in_array('query', $parts) and count($this->query) > 0) array_push($uri_parts, '?' . http_build_query($this->query, '', '&'));
# Attach the URI fragment to the parts array if not empty
if(in_array('fragment', $parts) and !empty($this->fragment)) array_push($uri_parts, '#' . $this->fragment);
# Return the URI string
return implode($uri_parts);
}
# Default convertion to a string, returns the complete URI
public function __toString() { return $this->build(); }
}
The most simple usage of the class would be something like that
$uri = new uri;
$uri->path = array('some', 'real', 'path');
echo $uri;
which would output http://localhost/some/real/path given that you test it on localhost.
- Are there any problems you see with the possible usage of that class?
- Is there any way you would improve its functionality?
EDIT: Please notice that leading and trailing slashes are stripped from the path string on purpose, because they are unwanted in my current environment and should never appear in the URI.