diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/README.md b/README.md index faa0623..02a16f5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,69 @@ # nex-php -PHP 8 / Composer Library for Nex Protocol + +PHP 8 Library for Nex Protocol + +## Usage + +``` +composer require yggverse/nex +``` + +## Client + +PHP interface for Nex protocol queries + +### Request + +``` php +$request = new \Yggverse\Nex\Client\Request( + 'nex://nightfall.city/nex/' +); +``` + +**Resolved request (SNI)** + +For direct connection provide resolved IP as the second argument + +``` php +$request = new \Yggverse\Nex\Client\Request( + 'nex://nightfall.city/nex/' // target URL + '46.23.92.144' // resolved IP, skip to use system-wide resolver +); +``` + +Alternatively, use `setResolvedHost` method of `Request` object before `getResponse` + +#### Request::setResolvedHost + +``` php +$request->setResolvedHost( + '46.23.92.144' +) +``` + +* to resolve network address with PHP, take a look on the [net-php](https://github.com/YGGverse/net-php) library! + +#### Request::getResolvedHost + +Get resolved host back + +#### Request::setHost +#### Request::getHost +#### Request::setPort +#### Request::getPort +#### Request::setPath +#### Request::getPath +#### Request::setQuery +#### Request::getQuery +#### Request::getResponse + +Execute requested URL and return raw response + +``` php +var_dump( + $request->getResponse() +); +``` + +#### Request::getOptions +#### Request::setOptions \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..24a9a02 --- /dev/null +++ b/composer.json @@ -0,0 +1,19 @@ +{ + "name": "yggverse/nex", + "description": "PHP 8 Library for Nex Protocol", + "keywords": [ "yggverse", "nex", "nex-protocol", "client" ], + "homepage": "https://github.com/yggverse/nex-php", + "type": "library", + "license": "MIT", + "autoload": { + "psr-4": { + "Yggverse\\Nex\\": "src/" + } + }, + "authors": [ + { + "name": "YGGverse" + } + ], + "require": {} +} diff --git a/src/Client/Request.php b/src/Client/Request.php new file mode 100644 index 0000000..3522d37 --- /dev/null +++ b/src/Client/Request.php @@ -0,0 +1,202 @@ +setHost( + $host + ); + } + + else + { + throw new Exception(); // @TODO + } + + if ($port = parse_url($url, PHP_URL_PORT)) + { + $this->setPort( + $port + ); + } + + else + { + $this->setPort( + 1900 + ); + } + + if ($path = parse_url($url, PHP_URL_PATH)) + { + $this->setPath( + $path + ); + } + + else + { + $this->setPath( + '' + ); + } + + if ($query = parse_url($url, PHP_URL_QUERY)) + { + $this->setQuery( + $query + ); + } + + else + { + $this->setQuery( + '' + ); + } + + if ($ip && false !== filter_var($ip, FILTER_VALIDATE_IP)) + { + $this->setResolvedHost( + $ip + ); + } + } + + public function setOptions(array $value): void + { + $this->_options = $value; + } + + public function getOptions(): array + { + return $this->_options; + } + + public function setHost(string $value): void + { + $this->_host = $value; + } + + public function getHost(): string + { + return $this->_host; + } + + public function setPort(int $value): void + { + $this->_port = $value; + } + + public function getPort(): int + { + return $this->_port; + } + + public function setPath(string $value): void + { + $this->_path = $value; + } + + public function getPath(): string + { + return $this->_path; + } + + public function setQuery(string $value): void + { + $this->_query = $value; + } + + public function getQuery(): string + { + return $this->_query; + } + + public function setResolvedHost(?string $value): void + { + $this->_ip = $value; + } + + public function getResolvedHost(): ?string + { + return $this->_ip; + } + + public function getResponse( + int $timeout = 30, // socket timeout, useful for offline resources + ?int $limit = null, // content length, null for unlimited + ?int &$length = 0, // initial response length, do not change without special needs + ?int &$code = null, // error code for debug + ?string &$message = null, // error message for debug + string &$response = '' // response init, also returning by this method + ): ?string + { + $connection = stream_socket_client( + sprintf( + 'tcp://%s:%d', + $this->_ip ? $this->_ip : $this->_host, + $this->_port + ), + $code, + $message, + $timeout, + STREAM_CLIENT_CONNECT, + stream_context_create( + $this->_options + ) + ); + + if (!is_resource($connection)) + { + return null; + } + + fwrite( + $connection, + sprintf( + "nex://%s:%d%s%s\r\n", + $this->_host, + $this->_port, + $this->_path, + $this->_query + ) + ); + + while ($part = fgets($connection)) + { + $length = $length + mb_strlen( + $part + ); + + if ($limit && $length > $limit) + { + break; + } + + $response .= $part; + } + + fclose( + $connection + ); + + return $response; + } +} \ No newline at end of file