<?php
/**
* PHP library for working with URI's. Requires
* PHP 5.3.7 or later. Replaces and extends PHP's
* parse_url()
*
* Based on P Guardiario's original work
*
* @author Nicholas Jordon
* @copyright 2014 Nicholas Jordon - All Rights Reserved
* @license http://opensource.org/licenses/MIT
* @version 0.1.0
*/
/**
* PHP URI
*/
class uri {
/*** Variables ***/
public $input;
public $scheme;
public $protocol;
public $scheme_name;
public $user;
public $username;
public $pass;
public $password;
public $host;
public $fqdn;
public $port;
public $authority;
public $path;
public $query;
public $fragment;
public $error;
public $error_msg;
/*** Methods ***/
public function __construct($input) {
$t = $this;
$t->input = $input;
$t->error = FALSE;
$t->protocol = &$this->scheme;
$t->username = &$this->user;
$t->password = &$this->pass;
$t->fqdn = &$this->host;
if (!is_string($input)) {
$t->error = TRUE;
$t->error_msg = 'Input was not a string!';
$t->scheme = FALSE;
$t->scheme_name = FALSE;
$t->user = FALSE;
$t->pass = FALSE;
$t->host = FALSE;
$t->port = FALSE;
$t->authority = FALSE;
$t->path = FALSE;
$t->query = FALSE;
$t->fragment = FALSE;
} else {
$this->parse($input);
}
}
protected function parse($uri) {
if ($this->error) {
return FALSE;
}
$t = $this;
$parsed = $t->_parse((string) $uri);
if (empty($parsed)) {
$t->error = TRUE;
$t->error = 'Could not parse the input as a URI';
return $parsed;
}
$defaults = array(
'scheme' => '',
'scheme_name' => '',
'user' => '',
'pass' => '',
'host' => '',
'port' => '',
'authority' => '',
'path' => '',
'query' => '',
'fragment' => ''
);
$values = $parsed + $defaults;
if (!empty($values['scheme'])) {
$t->scheme = $values['scheme'].'://';
} else {
$t->scheme = '';
}
$t->scheme_name = $values['scheme'];
$t->user = $values['user'];
$t->pass = $values['pass'];
$t->host = $values['host'];
$t->port = $values['port'];
$t->path = $values['path'];
$t->query = $values['query'];
$t->fragment = $values['fragment'];
$t->gen_authority();
}
private function _parse($uri) {
$uri = (string) $uri;
if (!version_compare(PHP_VERSION, '5.4.7') >= 0) {
if ($uri[0] == '/') {
unset($uri[0]);
}
if ($uri[0] == '/') {
unset($uri[0]);
}
}
return parse_url((string) $uri);
}
private function gen_authority() {
$t = $this;
$authority = '';
if (!empty($t->user)) {
$authority .= $t->user;
if (empty($t->pass)) {
$authority .= '@';
} else {
$authority .= ':';
}
}
if (!empty($t->pass)) {
$authority .= $t->pass.'@';
}
if (!empty($t->host)) {
$authority .= $t->host;
}
if (!empty($t->port)) {
$authority .= ':'.$t->port;
}
$t->authority = $authority;
}
public function arr() {
if ($this->error) {
return FALSE;
}
return array(
'scheme' => $this->scheme,
'user' => $this->user,
'pass' => $this->pass,
'host' => $this->host,
'port' => $this->port,
'authority' => $this->authority,
'path' => $this->path,
'query' => $this->query,
'fragment' => $this->fragment
);
}
public function str() {
if ($this->error) {
return FALSE;
}
$t = $this;
$str = '';
if (!empty($t->scheme)) {
$str .= $t->scheme;
}
if (!empty($t->user)) {
$str .= $t->user;
if (empty($t->pass)) {
$str .= '@';
} else {
$str .= ':';
$str .= $t->pass.'@';
}
}
if (!empty($t->host)) {
$str .= $t->host;
}
if (!empty($t->port)) {
$str .= ':'.$t->port;
}
if (!empty($t->path)) {
$str .= $t->path;
}
if (!empty($t->query)) {
$str .= '?'.$t->query;
}
if (!empty($t->fragment)) {
$str .= '#'.$t->fragment;
}
return $str;
}
public function p_str() {
if ($this->error) {
return FALSE;
}
echo $this->str();
}
public function path_info() {
if ($this->error) {
return FALSE;
}
$info = pathinfo($this->path);
$arr = explode('/',$this->path);
$last = count($arr) - 1;
if ($arr[$last] == '') {
unset($arr[$last]);
}
if ($arr[0] == '') {
array_shift($arr);
}
$info['array'] = $arr;
return $info;
}
public function query_arr() {
if ($this->error) {
return FALSE;
}
parse_str($this->query, $return);
return $return;
}
public function append($section, $str, $disable_safety = FALSE) {
if ($this->error) {
return FALSE;
}
$section = strtolower($section);
if (!isset($this->$section)) {
return FALSE;
}
if ($disable_safety) {
$this->$section = $this->$section.$str;
} else {
$test = $this->$section.$str;
$safety = $this->safety($section, $test);
if ($safety != FALSE) {
$this->$section = $safety;
} else {
return FALSE;
}
}
$this->gen_authority();
return $this->str();
}
public function prepend($section, $str, $disable_safety = FALSE) {
if ($this->error) {
return FALSE;
}
$section = strtolower($section);
if (!isset($this->$section)) {
return FALSE;
}
if ($disable_safety) {
$this->$section = $str.$this->$section;
} else {
$test = $str.$this->$section;
$safety = $this->safety($section, $test);
if ($safety != FALSE) {
$this->$section = $safety;
} else {
return FALSE;
}
}
$this->gen_authority();
return $this->str();
}
public function replace($section, $str, $disable_safety = FALSE) {
if ($this->error) {
return FALSE;
}
$section = strtolower($section);
if (!isset($this->$section)) {
return FALSE;
}
if ($disable_safety) {
$this->$section = $str;
} else {
$safety = $this->safety($section, $str);
if ($safety != FALSE) {
$this->$section = $safety;
} else {
return FALSE;
}
}
$this->gen_authority();
return $this->str();
}
protected function safety($type, $str) {
$type = strtoupper((string) $type);
if ($type != 'QUERY') {
$str = trim((string) $str);
}
$err = 0;
switch ($type) {
case 'SCHEME_NAME':
if (!preg_match('/\A[a-z]{1,10}\Z/', $str)) {
$err++;
}
break;
case 'SCHEME':
if (strpos($str, '\\') !== FALSE) {
$str = str_replace('\\', '/', $str);
}
if (strpos($str, '//') === FALSE && stripos($str, ':') === FALSE) {
if (!empty($str)) {
$str = $str.'://'; // assume it is generic
} else {
break; // there is nothing to check
}
}
$str = strtolower($str);
if (!stripos($str, '://') === FALSE) { // explicit generic
if (!preg_match('/\A[a-z]{1,10}:\/\/(\/)?\Z/', $str)) {
$err++;
}
} elseif(stripos($str, ':') === FALSE) { // explicit pipe
if (!preg_match('/\A[a-z]{1,10}:\Z/', $str)) {
$err++;
}
} elseif(stripos($str, '//') === FALSE) { // inherit
if ($str != '//') {
$err++;
}
}
break;
case 'USER':
$str = rawurlencode($str);
break;
case 'PASS':
$str = rawurlencode($str);
break;
case 'HOST':
$str = strtolower($str);
if (
(
!preg_match('/\A(([a-z0-9_]([a-z0-9\-_]+)?)\.)+[a-z0-9]([a-z0-9\-]+)?\Z/', $str) // fqdn
&&
!preg_match('/\A([0-9]\.){3}[0-9]\Z/', $str) // ip
)
||
strlen($str) > 255
) {
$err++;
}
break;
case 'PORT':
if ($str[0] == ':') {
$str = substr($str, 1);
}
if (!preg_match('/\A[0-9]{0,5}\Z/', $str)) {
$err++;
}
break;
case 'PATH':
$str = str_replace(array('//', '\\'), '/', $str); // common mistakes
$path_arr = explode('/', $str);
$safe_arr = array();
foreach ($path_arr as $path_part) {
$safe_arr[] = rawurlencode($path_part);
}
$str = implode('/', $safe_arr);
break;
case 'QUERY':
if (is_array($str)) {
$str = http_build_query($str);
}
if ($str[0] == '?') {
$str = substr($str, 1);
}
$frag_loc = strpos($str, '#');
if ($frag_loc) {
$str = substr($str, 0, ($frag_loc - 1));
} elseif ($str[0] == '#') {
$str = '';
}
break;
case 'FRAGMENT':
if ($str[0] == '#') {
unset($str[0]);
}
$str = urlencode($str);
break;
default:
return FALSE;
break;
}
if ($err) {
return FALSE;
}
return $str;
}
public function reset() {
$this->__construct($this->input);
}
}
$uri = new uri('http://example.com/path/to/file.ext');
$uri->replace('QUERY', array('rand', (string) rand(1, 10)));
$uri->replace('PATH', '/foo/bar');
$uri->append('PATH', '.baz');
$new = $uri->prepend('HOST', 'www.');
$uri->reset();
$original = $uri->str();
$uri->replace('FRAGMENT', 'Checkout');
$secure = $uri->replace('SCHEME', 'https');
echo $new.PHP_EOL;
echo $original.PHP_EOL;
echo $secure.PHP_EOL;
- Output for 5.3.8, 5.3.15, 5.4.2, 5.4.6, 5.4.12, 5.4.28, 5.4.32, 5.5.6 - 5.5.7, 5.6.5, 5.6.22, 7.0.7, 7.1.25, 7.2.0, 7.2.18, 7.3.4, 7.3.12
- http://www.example.com/foo/bar.baz?0=rand&1=4
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.10, 5.3.12, 5.4.38, 5.5.9, 5.5.12, 5.5.16, 5.5.23 - 5.5.24, 5.5.27 - 5.5.28, 5.5.35, 5.6.7, 5.6.12, 7.0.0, 7.0.10, 7.2.3, 7.3.1, 7.3.11
- http://www.example.com/foo/bar.baz?0=rand&1=6
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.3, 5.3.7, 5.4.10, 5.4.18 - 5.4.19, 5.4.41 - 5.4.42, 5.5.3 - 5.5.5, 5.5.13, 5.5.18, 5.5.34, 5.5.38, 5.6.6, 5.6.19 - 5.6.20, 7.0.5, 7.1.7, 7.1.26, 7.2.7, 7.2.9, 7.2.22, 7.3.10
- http://www.example.com/foo/bar.baz?0=rand&1=2
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.5, 5.3.11, 5.3.13, 5.3.26, 5.3.29, 5.4.7, 5.4.14, 5.4.16, 5.4.34, 5.5.2, 5.5.10, 5.5.30, 5.6.3, 7.0.1, 7.0.9, 7.1.28, 7.2.5 - 7.2.6, 7.3.0, 7.3.9
- http://www.example.com/foo/bar.baz?0=rand&1=3
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.16 - 5.3.17, 5.3.20, 5.4.3, 5.4.5, 5.4.24, 5.5.21, 5.5.25 - 5.5.26, 5.5.31, 5.5.36 - 5.5.37, 5.6.17, 7.1.30, 7.2.1 - 7.2.2, 7.2.11, 7.2.24, 7.3.7 - 7.3.8
- http://www.example.com/foo/bar.baz?0=rand&1=5
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.14, 5.3.21, 5.4.4, 5.4.9, 5.4.30, 5.4.36, 5.4.40, 5.4.44, 5.5.14, 5.6.0, 5.6.4, 5.6.9, 5.6.16, 5.6.28, 7.0.3 - 7.0.4, 7.0.6, 7.0.14, 7.2.4, 7.2.13, 7.2.17, 7.3.3, 7.3.5 - 7.3.6
- http://www.example.com/foo/bar.baz?0=rand&1=7
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.0, 5.3.4, 5.3.25, 5.3.28, 5.4.35, 5.5.0 - 5.5.1, 5.5.8, 5.5.33, 5.6.10 - 5.6.11, 5.6.18, 7.0.8, 7.1.5, 7.1.33, 7.2.12, 7.3.2
- http://www.example.com/foo/bar.baz?0=rand&1=10
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.1, 5.3.9, 5.3.19, 5.3.22, 5.3.27, 5.4.0 - 5.4.1, 5.4.11, 5.4.13, 5.4.22, 5.4.26, 5.4.29, 5.5.19, 5.5.22, 5.6.2, 5.6.14, 7.1.6, 7.1.27, 7.1.29, 7.1.32, 7.2.10, 7.2.15, 7.2.19 - 7.2.21, 7.2.23
- http://www.example.com/foo/bar.baz?0=rand&1=8
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.2, 5.4.15, 5.4.17, 5.4.20, 5.4.23, 5.4.37, 5.4.39, 5.6.1, 5.6.23, 5.6.25, 7.0.2, 7.1.0, 7.2.8, 7.2.14, 7.2.16
- http://www.example.com/foo/bar.baz?0=rand&1=1
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
- Output for 5.3.6, 5.3.18, 5.3.23 - 5.3.24, 5.4.8, 5.4.21, 5.4.25, 5.4.27, 5.4.31, 5.4.43, 5.4.45, 5.5.11, 5.5.15, 5.5.20, 5.5.29, 5.5.32, 5.6.8, 5.6.13, 5.6.15, 5.6.21, 5.6.24, 7.0.20, 7.1.31
- http://www.example.com/foo/bar.baz?0=rand&1=9
http://example.com/path/to/file.ext
https://example.com/path/to/file.ext#Checkout
preferences:
169.71 ms | 405 KiB | 209 Q