Skip to content

Instantly share code, notes, and snippets.

@rodneyrehm
Created December 19, 2011 22:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodneyrehm/1499238 to your computer and use it in GitHub Desktop.
Save rodneyrehm/1499238 to your computer and use it in GitHub Desktop.
PHP: URL wrangler class
<?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:rodney@rehmfamily.de',
'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:pass@www.google.de:1234/path/to/file?some=query#hash',
'/absolute/path?blubber#hash3' => 'http://user:pass@www.google.de: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