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.