Created
December 19, 2011 22:40
-
-
Save rodneyrehm/1499238 to your computer and use it in GitHub Desktop.
PHP: URL wrangler class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare( encoding = 'UTF-8' ); | |
namespace shurlook\net | |
{ | |
class URL | |
{ | |
const PROTOCOL = 'scheme'; | |
const HOST = 'host'; | |
const PORT = 'port'; | |
const USERNAME = 'user'; | |
const PASSWORD = 'pass'; | |
const PATH = 'path'; | |
const QUERY = 'query'; | |
const FRAGMENT = 'fragment'; | |
// http://www.iana.org/assignments/uri-schemes.html | |
protected static $defaultPorts = array( | |
'http' => 80, | |
'https' => 443, | |
); | |
protected $parts = array(); | |
protected $cache = null; | |
public function __construct( $parts=null ) | |
{ | |
if( is_string( $parts ) ) | |
$this->parts = parse_url( trim($parts) ); | |
else if( is_array( $parts ) ) | |
$this->parts = $parts; | |
} | |
public function __toString() | |
{ | |
if( $this->cache ) | |
return $this->cache; | |
$t = array(); | |
if( !empty( $this->parts[ self::PROTOCOL ] ) ) | |
$t[] = $this->parts[ self::PROTOCOL ] .'://'; | |
if( !empty( $this->parts[ self::USERNAME ] ) ) | |
{ | |
$t[] = $this->parts[ self::USERNAME ]; | |
if( !empty( $this->parts[ self::PASSWORD ] ) ) | |
$t[] = ':'. $this->parts[ self::PASSWORD ]; | |
$t[] = '@'; | |
} | |
if( !empty( $this->parts[ self::HOST ] ) ) | |
$t[] = $this->parts[ self::HOST ]; | |
if( !empty( $this->parts[ self::PATH ] ) ) | |
$t[] = $this->parts[ self::PATH ]; | |
if( !empty( $this->parts[ self::QUERY ] ) ) | |
$t[] = '?'. $this->parts[ self::QUERY ]; | |
if( !empty( $this->parts[ self::FRAGMENT ] ) ) | |
$t[] = '#'. $this->parts[ self::FRAGMENT ]; | |
return $this->cache = join( $t ); | |
} | |
public function setProtocol( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::PROTOCOL ] = $v; | |
return $this; | |
} | |
public function getProtocol() | |
{ | |
return !empty( $this->parts[ self::PROTOCOL ] ) ? $this->parts[ self::PROTOCOL ] : null; | |
} | |
public function setHost( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::HOST ] = $v; | |
return $this; | |
} | |
public function getHost() | |
{ | |
return !empty( $this->parts[ self::HOST ] ) ? $this->parts[ self::HOST ] : null; | |
} | |
public function setPort( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::PORT ] = $v; | |
return $this; | |
} | |
public function getPort() | |
{ | |
if( !empty( $this->parts[ self::PORT ] ) ) | |
return $this->parts[ self::PORT ]; | |
} | |
public function getProtocolDefaultPort() | |
{ | |
if( empty( $this->parts[ self::PROTOCOL ] ) ) | |
return null; | |
$p = $this->parts[ self::PROTOCOL ]; | |
if( empty( self::$defaultPorts[ $p ] ) ) | |
return null; | |
return self::$defaultPorts[ $p ]; | |
} | |
public function getPortOrDefault() | |
{ | |
if( $p = $this->getPort() ) | |
return $p; | |
return $this->getProtocolDefaultPort(); | |
} | |
public function setUsername( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::USERNAME ] = $v; | |
return $this; | |
} | |
public function getUsername() | |
{ | |
return !empty( $this->parts[ self::USERNAME ] ) ? $this->parts[ self::USERNAME ] : null; | |
} | |
public function setPassword( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::PASSWORD ] = $v; | |
return $this; | |
} | |
public function getPassword() | |
{ | |
return !empty( $this->parts[ self::PASSWORD ] ) ? $this->parts[ self::PASSWORD ] : null; | |
} | |
public function setPath( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::PATH ] = $v; | |
return $this; | |
} | |
public function getPath() | |
{ | |
return !empty( $this->parts[ self::PATH ] ) ? $this->parts[ self::PATH ] : null; | |
} | |
public function getPathDirectory() | |
{ | |
if( empty( $this->parts[ self::PATH ] ) ) | |
return null; | |
if( mb_substr( $this->parts[ self::PATH ], -1 ) == '/' ) | |
return $this->parts[ self::PATH ]; | |
$t = dirname( $this->parts[ self::PATH ] ); | |
return $t . ($t != '/' ? '/' : ''); | |
} | |
public function getPathFile() | |
{ | |
if( empty( $this->parts[ self::PATH ] ) ) | |
return null; | |
if( mb_substr( $this->parts[ self::PATH ], -1 ) == '/' ) | |
return null; | |
return basename( $this->parts[ self::PATH ] ); | |
} | |
public function isRelativePath() | |
{ | |
if( !($p = $this->getPath()) ) | |
return null; | |
return substr( $p, 0, 1 ) != '/'; | |
} | |
public function setQuery( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::QUERY ] = $v; | |
return $this; | |
} | |
public function getQuery() | |
{ | |
return !empty( $this->parts[ self::QUERY ] ) ? $this->parts[ self::QUERY ] : null; | |
} | |
public function addQuery( $key, $value ) | |
{ | |
$this->cache = null; | |
$t = $key .'='. urlencode( $value ); | |
if( empty( $this->parts[ self::QUERY ] ) ) | |
{ | |
$this->parts[ self::QUERY ] = $t; | |
return $this; | |
} | |
$this->parts[ self::QUERY ] .= '&'. $t; | |
return $this; | |
} | |
public function getQueryArray() | |
{ | |
if( empty( $this->parts[ self::QUERY ] ) ) | |
return array(); | |
$t = array(); | |
parse_str( $this->parts[ self::QUERY ], $t ); | |
return $t; | |
} | |
public function setFragment( $v ) | |
{ | |
$this->cache = null; | |
$this->parts[ self::FRAGMENT ] = $v; | |
return $this; | |
} | |
public function getFragment() | |
{ | |
return !empty( $this->parts[ self::FRAGMENT ] ) ? $this->parts[ self::FRAGMENT ] : null; | |
} | |
public function getResource() | |
{ | |
if( $t = $this->getQuery() ) | |
return $this->getPath() .'?'. $this->getQuery(); | |
return $this->getPath(); | |
} | |
public function hostIsIp() | |
{ | |
if( empty( $this->parts[ self::HOST ] ) ) | |
return null; | |
return preg_match( '#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/#iuS', $this->parts[ self::HOST ] ); | |
} | |
public function getDomain() | |
{ | |
if( empty( $this->parts[ self::HOST ] ) || $this->hostIsIp() ) | |
return null; | |
$matches = array(); | |
if( !preg_match( '#[^\.]*\.[^\.]*$#uS', $this->parts[ self::HOST ], $matches ) ) | |
return $this->parts[ self::HOST ]; | |
return $matches[0]; | |
} | |
public function isRelativeURL() | |
{ | |
return !$this->getHost(); | |
} | |
// http://tools.ietf.org/html/rfc3986#section-5 | |
public function absoluteTo( $base ) | |
{ | |
// abort if this is not a relative URL | |
if( !$this->isRelativeURL() ) | |
return clone $this; | |
if( is_string( $base ) ) | |
$base = new URL( $base ); | |
// abort if $base is a relative URL | |
if( $base->isRelativeURL() ) | |
throw new \Exception( '"'. $base .'" is a relative URL and thus not suited as the base URL for relative-to-absolute-URL-translation' ); | |
// don't modify the current object | |
$url = clone $this; | |
$url->setProtocol( $base->getProtocol() ); | |
$url->setUsername( $base->getUsername() ); | |
$url->setPassword( $base->getPassword() ); | |
$url->setHost( $base->getHost() ); | |
$url->setPort( $base->getPort() ); | |
if( $url->isRelativePath() ) | |
{ | |
$p = $base->getPath(); | |
$basePath = ( !$p || $p == '/' ) ? '/' : $base->getPathDirectory(); | |
$url->setPath( $basePath . $url->getPath() ); | |
} | |
return $url; | |
} | |
} | |
if( false ) | |
{ | |
$urls = array( | |
'mailto:[email protected]', | |
'http://www.google.de/path/to/file?some=query#hash', | |
'http://xyz.www.google.de/path/to/file?some=query#hash', | |
'www.google.de/path/to/file?some=query#hash', | |
'/path/to/file?some=query#hash', | |
'path/to/file?some=query#hash', | |
); | |
foreach( $urls as $url ) | |
{ | |
$u = new URL( $url ); | |
var_dump( | |
$url, | |
$u, | |
$u->getProtocol(), | |
$u->getDomain(), | |
$u->getPathDirectory(), | |
$u->getPathFile() | |
); | |
echo '<hr>'; | |
} | |
$urls = array( | |
'relative/path?blubber#hash1' => 'http://www.google.de/path/to/file?some=query#hash', | |
'/absolute/path?blubber#hash1' => 'http://www.google.de/path/to/file?some=query#hash', | |
'relative/path?blubber#hash2' => 'www.google.de/path/to/file?some=query#hash', | |
'/absolute/path?blubber#hash2' => 'www.google.de/path/to/file?some=query#hash', | |
'relative/path?blubber#hash3' => 'http://user:[email protected]:1234/path/to/file?some=query#hash', | |
'/absolute/path?blubber#hash3' => 'http://user:[email protected]:1234/path/to/file?some=query#hash', | |
'relative/path?blubber#hash4' => 'http://www.google.de/path/to/', | |
'/absolute/path?blubber#hash4' => 'http://www.google.de/path/to/', | |
'relative/path?blubber#hash5' => 'http://www.google.de/path/to', | |
'/absolute/path?blubber#hash5' => 'http://www.google.de/path/to', | |
'relative/path?blubber#hash6' => 'http://www.google.de/', | |
'/absolute/path?blubber#hash6' => 'http://www.google.de/', | |
'relative/path?blubber#hash7' => 'http://www.google.de/?some=query', | |
'/absolute/path?blubber#hash7' => 'http://www.google.de/?some=query', | |
'relative/path?blubber#hash8' => 'http://www.google.de', | |
'/absolute/path?blubber#hash8' => 'http://www.google.de', | |
'relative/path?blubber#hash9' => 'http://www.google.de?some=query', | |
'/absolute/path?blubber#hash9' => 'http://www.google.de?some=query', | |
); | |
foreach( $urls as $rel => $base ) | |
{ | |
try | |
{ | |
$relURL = new URL( $rel ); | |
$baseURL = new URL( $base ); | |
$url = $relURL->absoluteTo( $baseURL ); | |
var_dump( $rel, $base, $baseURL, $url->__toString() ); | |
} | |
catch( \Exception $e ) | |
{ | |
var_dump( $rel, $base, $e->getMessage() ); | |
} | |
echo '<hr>'; | |
} | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment