You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
4.2 KiB
214 lines
4.2 KiB
<?php |
|
|
|
declare(strict_types=1); |
|
|
|
namespace Yggverse\Gemini\Client; |
|
|
|
class Request |
|
{ |
|
private ?string $_ip = null; |
|
|
|
private string $_host; |
|
private int $_port; |
|
private string $_path; |
|
private string $_query; |
|
|
|
private array $_options = |
|
[ |
|
'ssl' => |
|
[ |
|
'verify_peer' => false, |
|
'verify_peer_name' => false |
|
] |
|
]; |
|
|
|
public function __construct(string $url, ?string $ip = null) |
|
{ |
|
if ($host = parse_url($url, PHP_URL_HOST)) |
|
{ |
|
$this->setHost( |
|
$host |
|
); |
|
} |
|
|
|
else |
|
{ |
|
throw new \Exception( |
|
_('Host required') |
|
); |
|
} |
|
|
|
if ($port = parse_url($url, PHP_URL_PORT)) |
|
{ |
|
$this->setPort( |
|
$port |
|
); |
|
} |
|
|
|
else |
|
{ |
|
$this->setPort( |
|
1965 |
|
); |
|
} |
|
|
|
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( |
|
'tls://%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( |
|
"gemini://%s:%d%s%s\r\n", |
|
$this->_host, |
|
$this->_port, |
|
$this->_path, |
|
$this->_query ? sprintf( |
|
'?%s', |
|
$this->_query |
|
) : null |
|
) |
|
); |
|
|
|
while ($part = fgets($connection)) |
|
{ |
|
$length = $length + mb_strlen( |
|
$part |
|
); |
|
|
|
if ($limit && $length > $limit) |
|
{ |
|
break; |
|
} |
|
|
|
$response .= $part; |
|
} |
|
|
|
fclose( |
|
$connection |
|
); |
|
|
|
return $response; |
|
} |
|
} |