diff --git a/README.md b/README.md index 348946e..9956b8b 100644 --- a/README.md +++ b/README.md @@ -70,31 +70,96 @@ var_dump( ### Address -Includes useful methods to work with network addresses +Includes methods to work with network addresses. +#### Base address methods + +Different operations with address parts: + +* `scheme` +* `user` +* `password` +* `host` +* `protocol` +* `path` +* `query` +* `fragment` + +#### Address conversion from relative to absolute format + +**Document root** + +``` +$base = new \Yggverse\Net\Address( + 'http://yo.ygg/a1/b1/c1' +); + +$address = new \Yggverse\Net\Address( + '/a2' +); + +var_dump( + $address->getAbsolute( + $base + ) // return http://yo.ygg/a2 +); +``` + +**Current folder** + +``` +$base = new \Yggverse\Net\Address( + 'http://yo.ygg/a1/b1/c1' +); + +$address = new \Yggverse\Net\Address( + 'c2' +); + +var_dump( + $address->getAbsolute( + $base + ) // return http://yo.ygg/a1/b1/c2 +); ``` + +**Ending slash** + +``` +$base = new \Yggverse\Net\Address( + 'http://yo.ygg/a1/b1/c1/' +); + $address = new \Yggverse\Net\Address( - 'http://yo.ygg' + '../../b2/c2' ); var_dump( - $address->getScheme() // Scheme substring + $address->getAbsolute( + $base + ) // return http://yo.ygg/a1/b2/c2 ); +``` -... +**All options** -$subject = new \Yggverse\Net\Address( - './some/uri' +``` +$base = new \Yggverse\Net\Address( + 'http://user:password@yo.ygg/a1/b1/c1?attribute=value#anchor' +); + +$address = new \Yggverse\Net\Address( + '../../a2/b2?attribute2=value2#anchor2' ); var_dump( - $address->absolute( - $subject - ) // return http://yo.ygg/some/uri + $address->getAbsolute( + $base + ) // return http://user:password@yo.ygg/a2/b2?attribute2=value2#anchor2 ); ``` ## Integrations * [Network API with native Yggdrasil/IPv6 support](https://github.com/YGGverse/web-api) -* [Yo! Search Crawler for different networks](https://github.com/YGGverse/Yo) +* [Yo! Crawler for different networks](https://github.com/YGGverse/Yo) diff --git a/src/Address.php b/src/Address.php index 4c1977e..f7567f2 100644 --- a/src/Address.php +++ b/src/Address.php @@ -15,10 +15,10 @@ class Address private ?string $_query = null; private ?string $_fragment = null; - private array $_dirs = []; - private string $_separator = '/'; + private array $_segments = []; + public function __construct(?string $address = null) { if ($address) @@ -39,7 +39,7 @@ class Address if ($pass = parse_url($address, PHP_URL_PASS)) { - $this->setPath( + $this->setPass( (string) $pass ); } @@ -150,10 +150,12 @@ class Address { if (false !== strpos($value, '\\')) { - $this->_separator = '\\'; + $this->setSeparator( + '\\' + ); } - $this->_dirs = explode( + $this->_segments = explode( $this->_separator, $value ); @@ -161,9 +163,9 @@ class Address $this->_path = $value; } - public function getDirs(): array + public function getSegments(): array { - return $this->_dirs; + return $this->_segments; } public function getQuery(): ?string @@ -191,6 +193,11 @@ class Address return $this->_separator; } + public function setSeparator(?string $value): void + { + $this->_separator = $value; + } + public function get(): string { $address = ''; @@ -198,8 +205,10 @@ class Address if ($scheme = $this->getScheme()) { $address .= sprintf( - '%s://', - $scheme + '%s:%s%s', + $scheme, + $this->getSeparator(), + $this->getSeparator() ); } @@ -210,7 +219,7 @@ class Address $address .= sprintf( '%s:%s@', $user, - pass + $pass ); } @@ -238,14 +247,7 @@ class Address if ($path = $this->getPath()) { - $address .= sprintf( - '%s%s', - $this->getSeparator(), - trim( - $path, - $this->getSeparator() - ) - ); + $address .= $path; } if ($query = $this->getQuery()) @@ -267,35 +269,102 @@ class Address return $address; } - public function absolute( - \Yggverse\Net\Address $address - ): string + public function getAbsolute( + \Yggverse\Net\Address $base + ): ?string { - if ($address->isAbsolute()) + if ($this->isAbsolute()) + { + return $this->get(); + } + + if ($base->isRelative()) { - return $address->get(); + return null; } - $address->setScheme( - $this->getScheme() + $this->setScheme( + $base->getScheme() ); - $address->setUser( - $this->getUser() + $this->setUser( + $base->getUser() ); - $address->setPass( - $this->getPass() + $this->setPass( + $base->getPass() ); - $address->setHost( - $this->getHost() + $this->setHost( + $base->getHost() ); - $address->setPort( - $this->getPort() + $this->setPort( + $base->getPort() ); - return ''; // @TODO + $this->setSeparator( + $base->getSeparator() + ); + + if (str_starts_with((string) $this->getPath(), $this->getSeparator())) + { + return $this->get(); + } + + if ($path = $this->getPath()) + { + $prefix = array_reverse( + $base->getSegments() + ); + + array_shift( + $prefix + ); + + $navigate = true; + + $postfix = []; + + foreach ($this->getSegments() as $index => $segment) + { + if ($segment == '.') + { + continue; + } + + if ($navigate && $segment == '..') + { + if (empty($prefix[$index])) + { + return null; + } + + unset( + $prefix[$index] + ); + + continue; + } + + $navigate = false; + + $postfix[] = $segment; + } + + $this->setPath( + implode( + $this->getSeparator(), + array_merge( + array_reverse( + $prefix + ), + $postfix + ) + ) + ); + } + + return $this->get(); } } \ No newline at end of file