Use the Index router in Uiharu.
This commit is contained in:
parent
0a668992d9
commit
9948642a5a
5 changed files with 695 additions and 575 deletions
2
public/index.html
Normal file
2
public/index.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<!doctype html>
|
||||||
|
<pre>Metadata lookup service - OK</pre>
|
295
public/index.php
295
public/index.php
|
@ -2,98 +2,24 @@
|
||||||
namespace Uiharu;
|
namespace Uiharu;
|
||||||
|
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Index\Http\HttpFx;
|
||||||
use Index\MediaType;
|
use Index\MediaType;
|
||||||
use Index\Performance\Stopwatch;
|
use Index\Performance\Stopwatch;
|
||||||
|
|
||||||
require_once __DIR__ . '/../uiharu.php';
|
require_once __DIR__ . '/../uiharu.php';
|
||||||
|
|
||||||
define('UIH_CACHE', !UIH_DEBUG || isset($_GET['_cache']));
|
function uih_origin_allowed(string $origin): bool {
|
||||||
define('UIH_INCLUDE_RAW', UIH_DEBUG || isset($_GET['include_raw']));
|
$origin = mb_strtolower(parse_url($origin, PHP_URL_HOST));
|
||||||
|
|
||||||
function uih_media_type_json(MediaType $mediaType): array {
|
if($origin === $_SERVER['HTTP_HOST'])
|
||||||
$parts = [
|
return true;
|
||||||
'string' => (string)$mediaType,
|
|
||||||
'type' => $mediaType->getCategory(),
|
|
||||||
'subtype' => $mediaType->getKind(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if(!empty($suffix = $mediaType->getSuffix()))
|
$allowed = Config::get('CORS', 'origins', []);
|
||||||
$parts['suffix'] = $suffix;
|
if(empty($allowed))
|
||||||
|
return true;
|
||||||
|
|
||||||
if(!empty($params = $mediaType->getParams()))
|
return in_array($origin, $allowed);
|
||||||
$parts['params'] = $params;
|
|
||||||
|
|
||||||
return $parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
function uih_parse_url(string $url): array|false {
|
|
||||||
$parts = parse_url($url);
|
|
||||||
if($parts === false)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// v1 compat
|
|
||||||
$parts['uri'] = uih_build_url($parts);
|
|
||||||
if(isset($parts['pass']))
|
|
||||||
$parts['password'] = $parts['pass'];
|
|
||||||
|
|
||||||
return $parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
function uih_build_url(array $parts): string {
|
|
||||||
$string = '';
|
|
||||||
|
|
||||||
if(!empty($parts['scheme']))
|
|
||||||
$string .= $parts['scheme'] . ':';
|
|
||||||
|
|
||||||
$authority = '';
|
|
||||||
|
|
||||||
if(isset($parts['user']) || isset($parts['pass'])) {
|
|
||||||
if(isset($parts['user']))
|
|
||||||
$authority .= $parts['user'];
|
|
||||||
if(isset($parts['pass']))
|
|
||||||
$authority .= ':' . $parts['pass'];
|
|
||||||
$authority .= '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($parts['host'])) {
|
|
||||||
$authority .= $parts['host'];
|
|
||||||
if(isset($parts['port']))
|
|
||||||
$authority .= ':' . $parts['port'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$hasAuthority = !empty($authority);
|
|
||||||
if($hasAuthority)
|
|
||||||
$string .= '//' . $authority;
|
|
||||||
|
|
||||||
$path = $parts['path'] ?? '';
|
|
||||||
$hasPath = !empty($path);
|
|
||||||
|
|
||||||
if($hasAuthority && (!$hasPath || $path[0] !== '/'))
|
|
||||||
$string .= '/';
|
|
||||||
elseif(!$hasAuthority && $path[1] === '/')
|
|
||||||
$path = '/' . trim($path, '/');
|
|
||||||
|
|
||||||
$string .= $path;
|
|
||||||
|
|
||||||
if(!empty($parts['query'])) {
|
|
||||||
$string .= '?';
|
|
||||||
$queryParts = explode('&', $parts['query']);
|
|
||||||
|
|
||||||
foreach($queryParts as $queryPart) {
|
|
||||||
$kvp = explode('=', $queryPart, 2);
|
|
||||||
$string .= rawurlencode($kvp[0]);
|
|
||||||
if(isset($kvp[1]))
|
|
||||||
$string .= '=' . rawurlencode($kvp[1]);
|
|
||||||
$string .= '&';
|
|
||||||
}
|
|
||||||
|
|
||||||
$string = substr($string, 0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!empty($parts['fragment']))
|
|
||||||
$string .= '#' . rawurlencode($parts['fragment']);
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function uih_eeprom_lookup(stdClass $resp, string $eepromFileId, string $domain = 'flashii'): void {
|
function uih_eeprom_lookup(stdClass $resp, string $eepromFileId, string $domain = 'flashii'): void {
|
||||||
|
@ -126,108 +52,85 @@ function uih_eeprom_lookup(stdClass $resp, string $eepromFileId, string $domain
|
||||||
$resp->site_name = 'Flashii EEPROM';
|
$resp->site_name = 'Flashii EEPROM';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_dir(UIH_SEM_PATH))
|
|
||||||
mkdir(UIH_SEM_PATH, 0777, true);
|
|
||||||
|
|
||||||
header('X-Powered-By: Uiharu');
|
|
||||||
|
|
||||||
$db->execute('DELETE FROM `uih_metadata_cache` WHERE `metadata_created` < NOW() - INTERVAL 7 DAY');
|
$db->execute('DELETE FROM `uih_metadata_cache` WHERE `metadata_created` < NOW() - INTERVAL 7 DAY');
|
||||||
|
|
||||||
$reqMethod = filter_input(INPUT_SERVER, 'REQUEST_METHOD');
|
/*apis = [
|
||||||
$reqPath = '/' . trim(parse_url(filter_input(INPUT_SERVER, 'REQUEST_URI'), PHP_URL_PATH), '/');
|
new \Uiharu\APIs\v1_0,
|
||||||
$reqHead = false;
|
];*/
|
||||||
|
|
||||||
if($reqMethod == 'HEAD') {
|
$router = new HttpFx;
|
||||||
$reqMethod = 'GET';
|
$router->use('/', function($response) {
|
||||||
$reqHead = true;
|
$response->setPoweredBy('Uiharu');
|
||||||
}
|
});
|
||||||
|
|
||||||
if(!empty($_SERVER['HTTP_ORIGIN'])) {
|
$router->use('/', function($response, $request) {
|
||||||
$originLast12 = substr($_SERVER['HTTP_ORIGIN'], -12, 12);
|
$origin = $request->getHeaderLine('Origin');
|
||||||
$originLast10 = substr($_SERVER['HTTP_ORIGIN'], -10, 10);
|
|
||||||
if($originLast12 !== '/flashii.net' && $originLast12 !== '.flashii.net'
|
if(!empty($origin)) {
|
||||||
&& $originLast10 !== '/edgii.net' && $originLast10 !== '.edgii.net'
|
if(!uih_origin_allowed($origin))
|
||||||
&& $_SERVER['HTTP_ORIGIN'] !== 'https://flashii.net'
|
return 403;
|
||||||
&& $_SERVER['HTTP_ORIGIN'] !== 'http://flashii.net'
|
|
||||||
&& $_SERVER['HTTP_ORIGIN'] !== 'https://edgii.net'
|
$response->setHeader('Access-Control-Allow-Origin', $origin);
|
||||||
&& $_SERVER['HTTP_ORIGIN'] !== 'http://edgii.net') {
|
$response->setHeader('Vary', 'Origin');
|
||||||
http_response_code(403);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
|
$router->use('/', function($response, $request) {
|
||||||
header('Vary: Origin');
|
if($request->getMethod() === 'OPTIONS') {
|
||||||
}
|
$response->setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST');
|
||||||
|
return 204;
|
||||||
if($reqMethod === 'OPTIONS') {
|
|
||||||
http_response_code(204);
|
|
||||||
//header('Access-Control-Allow-Credentials: true');
|
|
||||||
//header('Access-Control-Allow-Headers: Authorization');
|
|
||||||
header('Access-Control-Allow-Methods: OPTIONS, GET, POST');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($reqPath === '/metadata') {
|
|
||||||
// Allow using POST for ridiculous urls.
|
|
||||||
if($reqMethod !== 'GET' && $reqMethod !== 'POST') {
|
|
||||||
http_response_code(405);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
$router->get('/', function($response) {
|
||||||
if($reqHead)
|
$response->accelRedirect('/index.html');
|
||||||
|
$response->setContentType('text/html; charset=utf-8');
|
||||||
|
});
|
||||||
|
|
||||||
|
$metaDataHandlerV1 = function($response, $request) use ($db) {
|
||||||
|
$response->setContentType('application/json; charset=utf-8');
|
||||||
|
if($request->getMethod() === 'HEAD')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
$sw = Stopwatch::startNew();
|
$sw = Stopwatch::startNew();
|
||||||
$resp = new stdClass;
|
$resp = new stdClass;
|
||||||
|
|
||||||
if($_SERVER['HTTP_HOST'] === 'mii.flashii.net') {
|
if($request->getMethod() === 'POST') {
|
||||||
$resp->type = 'object';
|
if(!$request->isStreamContent()) {
|
||||||
$resp->content_type = [];
|
$response->setStatusCode(400);
|
||||||
$resp->content_type['string'] = 'application/x-update-your-script-to-use-uiharu.flashii.net-instead-of-mii.flashii.net';
|
return $resp;
|
||||||
$resp->content_type['type'] = 'text';
|
|
||||||
$resp->content_type['subtype'] = 'deprecation';
|
|
||||||
$resp->title = 'Update your URLs: mii.flashii.net -> uiharu.flashii.net';
|
|
||||||
$resp->description = 'Update your URLs: mii.flashii.net -> uiharu.flashii.net';
|
|
||||||
$resp->site_name = 'Deprecation notice';
|
|
||||||
$resp->took = 35.1;
|
|
||||||
echo json_encode($resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($reqMethod === 'POST') {
|
$targetUrl = $request->getContent()->getStream()->read(1000);
|
||||||
$targetUrl = substr((string)file_get_contents('php://input'), 0, 1000);
|
|
||||||
} else {
|
} else {
|
||||||
$targetUrl = (string)filter_input(INPUT_GET, 'url');
|
$targetUrl = (string)$request->getParam('url');
|
||||||
}
|
}
|
||||||
|
|
||||||
$parsedUrl = uih_parse_url($targetUrl);
|
if(empty($targetUrl)) {
|
||||||
if($parsedUrl === false) {
|
$response->setStatusCode(400);
|
||||||
http_response_code(400);
|
return $resp;
|
||||||
$resp->error = 'metadata:uri';
|
|
||||||
echo json_encode($resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$resp->uri = $parsedUrl;
|
|
||||||
|
|
||||||
// if no scheme is specified, try https
|
|
||||||
if(empty($parsedUrl['scheme'])) {
|
|
||||||
$parsedUrl['scheme'] = 'https';
|
|
||||||
$parsedUrl = uih_parse_url(uih_build_url($parsedUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
$urlHash = hash('sha256', uih_build_url($parsedUrl));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$semPath = UIH_SEM_PATH . DIRECTORY_SEPARATOR . $urlHash;
|
$parsedUrl = Url::parse($targetUrl);
|
||||||
if(!is_file($semPath))
|
} catch(InvalidArgumentException $ex) {
|
||||||
touch($semPath);
|
$response->setStatusCode(400);
|
||||||
$ftok = ftok($semPath, UIH_SEM_NAME);
|
$resp->error = 'metadata:uri';
|
||||||
$semaphore = sem_get($ftok, 1);
|
return $resp;
|
||||||
while(!sem_acquire($semaphore)) usleep(100);
|
}
|
||||||
|
|
||||||
if(UIH_CACHE) {
|
// if no scheme is specified, try https
|
||||||
|
if(!$parsedUrl->hasScheme())
|
||||||
|
$parsedUrl->setScheme('https');
|
||||||
|
|
||||||
|
$resp->uri = $parsedUrl->toV1();
|
||||||
|
|
||||||
|
$urlHash = $parsedUrl->calculateHash(false);
|
||||||
|
|
||||||
|
$enableCache = !UIH_DEBUG || $request->hasParam('_cache');
|
||||||
|
$includeRawResult = UIH_DEBUG || $request->hasParam('include_raw');
|
||||||
|
|
||||||
|
if($enableCache) {
|
||||||
$cacheFetch = $db->prepare('SELECT `metadata_resp` FROM `uih_metadata_cache` WHERE `metadata_url` = UNHEX(?) AND `metadata_created` > NOW() - INTERVAL 10 MINUTE');
|
$cacheFetch = $db->prepare('SELECT `metadata_resp` FROM `uih_metadata_cache` WHERE `metadata_url` = UNHEX(?) AND `metadata_created` > NOW() - INTERVAL 10 MINUTE');
|
||||||
$cacheFetch->addParameter(1, $urlHash);
|
$cacheFetch->addParameter(1, $urlHash);
|
||||||
$cacheFetch->execute();
|
$cacheFetch->execute();
|
||||||
|
@ -240,19 +143,21 @@ if($reqPath === '/metadata') {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($resp->type)) {
|
if(empty($resp->type)) {
|
||||||
$urlScheme = strtolower($parsedUrl['scheme']);
|
$urlScheme = strtolower($parsedUrl->getScheme());
|
||||||
$urlHost = strtolower($parsedUrl['host']);
|
$urlHost = strtolower($parsedUrl->getHost());
|
||||||
$urlPath = '/' . trim($parsedUrl['path'], '/');
|
$urlPath = '/' . trim($parsedUrl->getPath(), '/');
|
||||||
|
|
||||||
if($urlScheme === 'eeprom') {
|
if($urlScheme === 'eeprom') {
|
||||||
if(preg_match('#^([A-Za-z0-9-_]+)$#', $parsedUrl['path'], $matches)) {
|
if(preg_match('#^([A-Za-z0-9-_]+)$#', $parsedUrl->getPath(), $matches)) {
|
||||||
$resp->uri = $parsedUrl = uih_parse_url('https://i.fii.moe/' . $matches[1]);
|
$parsedUrl = Url::parse('https://i.fii.moe/' . $matches[1]);
|
||||||
|
$resp->uri = $parsedUrl->toV1();
|
||||||
$continueRaw = true;
|
$continueRaw = true;
|
||||||
uih_eeprom_lookup($resp, $matches[1]);
|
uih_eeprom_lookup($resp, $matches[1]);
|
||||||
}
|
}
|
||||||
} elseif($urlScheme === 'devrom') {
|
} elseif($urlScheme === 'devrom') {
|
||||||
if(preg_match('#^([A-Za-z0-9-_]+)$#', $parsedUrl['path'], $matches)) {
|
if(preg_match('#^([A-Za-z0-9-_]+)$#', $parsedUrl->getPath(), $matches)) {
|
||||||
$resp->uri = $parsedUrl = uih_parse_url('https://i.edgii.net/' . $matches[1]);
|
$parsedUrl = Url::parse('https://i.edgii.net/' . $matches[1]);
|
||||||
|
$resp->uri = $parsedUrl->toV1();
|
||||||
$continueRaw = true;
|
$continueRaw = true;
|
||||||
uih_eeprom_lookup($resp, $matches[1], 'edgii');
|
uih_eeprom_lookup($resp, $matches[1], 'edgii');
|
||||||
}
|
}
|
||||||
|
@ -359,7 +264,7 @@ if($reqPath === '/metadata') {
|
||||||
$youtubeVideoId = substr($urlPath, 1);
|
$youtubeVideoId = substr($urlPath, 1);
|
||||||
case 'youtube.com': case 'www.youtube.com':
|
case 'youtube.com': case 'www.youtube.com':
|
||||||
case 'youtube-nocookie.com': case 'www.youtube-nocookie.com':
|
case 'youtube-nocookie.com': case 'www.youtube-nocookie.com':
|
||||||
parse_str($parsedUrl['query'], $queryString);
|
parse_str($parsedUrl->getQuery(), $queryString);
|
||||||
|
|
||||||
if(!isset($youtubeVideoId) && $urlPath === '/watch')
|
if(!isset($youtubeVideoId) && $urlPath === '/watch')
|
||||||
$youtubeVideoId = $queryString['v'] ?? null;
|
$youtubeVideoId = $queryString['v'] ?? null;
|
||||||
|
@ -406,12 +311,13 @@ if($reqPath === '/metadata') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
http_response_code(404);
|
|
||||||
$resp->error = 'metadata:scheme';
|
$resp->error = 'metadata:scheme';
|
||||||
|
$response->setStatusCode(400);
|
||||||
|
return $resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((empty($resp->type) || isset($continueRaw)) && in_array($parsedUrl['scheme'], ['http', 'https'])) {
|
if((empty($resp->type) || isset($continueRaw)) && in_array($parsedUrl->getScheme(), ['http', 'https'])) {
|
||||||
$curl = curl_init(uih_build_url($parsedUrl));
|
$curl = curl_init((string)$parsedUrl);
|
||||||
curl_setopt_array($curl, [
|
curl_setopt_array($curl, [
|
||||||
CURLOPT_AUTOREFERER => true,
|
CURLOPT_AUTOREFERER => true,
|
||||||
CURLOPT_CERTINFO => false,
|
CURLOPT_CERTINFO => false,
|
||||||
|
@ -466,7 +372,7 @@ if($reqPath === '/metadata') {
|
||||||
$contentType = MediaType::parse('application/octet-stream');
|
$contentType = MediaType::parse('application/octet-stream');
|
||||||
}
|
}
|
||||||
|
|
||||||
$resp->content_type = uih_media_type_json($contentType);
|
$resp->content_type = MediaTypeExts::toV1($contentType);
|
||||||
|
|
||||||
$isHTML = $contentType->equals('text/html');
|
$isHTML = $contentType->equals('text/html');
|
||||||
$isXHTML = $contentType->equals('application/xhtml+xml');
|
$isXHTML = $contentType->equals('application/xhtml+xml');
|
||||||
|
@ -560,7 +466,7 @@ if($reqPath === '/metadata') {
|
||||||
if($isImage || $isAudio || $isVideo) {
|
if($isImage || $isAudio || $isVideo) {
|
||||||
curl_close($curl);
|
curl_close($curl);
|
||||||
$resp->media = new stdClass;
|
$resp->media = new stdClass;
|
||||||
$ffmpeg = json_decode(shell_exec(sprintf('ffprobe -show_streams -show_format -print_format json -v quiet -i %s', escapeshellarg(uih_build_url($parsedUrl)))));
|
$ffmpeg = json_decode(shell_exec(sprintf('ffprobe -show_streams -show_format -print_format json -v quiet -i %s', escapeshellarg((string)$parsedUrl))));
|
||||||
|
|
||||||
if(!empty($ffmpeg)) {
|
if(!empty($ffmpeg)) {
|
||||||
if(!empty($ffmpeg->format)) {
|
if(!empty($ffmpeg->format)) {
|
||||||
|
@ -639,7 +545,7 @@ if($reqPath === '/metadata') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(UIH_INCLUDE_RAW)
|
if($includeRawResult)
|
||||||
$resp->ffmpeg = $ffmpeg;
|
$resp->ffmpeg = $ffmpeg;
|
||||||
} else curl_close($curl);
|
} else curl_close($curl);
|
||||||
}
|
}
|
||||||
|
@ -654,30 +560,15 @@ if($reqPath === '/metadata') {
|
||||||
$replaceCache->addParameter(2, $respJson);
|
$replaceCache->addParameter(2, $respJson);
|
||||||
$replaceCache->execute();
|
$replaceCache->execute();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
if(!empty($semaphore))
|
|
||||||
sem_release($semaphore);
|
|
||||||
if(is_file($semPath))
|
|
||||||
unlink($semPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo $respJson ?? json_encode($resp);
|
if(!empty($respJson))
|
||||||
return;
|
$response->setContent($respJson);
|
||||||
}
|
else
|
||||||
|
return $resp;
|
||||||
|
};
|
||||||
|
|
||||||
if($reqPath === '/') {
|
// Allow using POST for ridiculous urls.
|
||||||
if($reqMethod !== 'GET') {
|
$router->get('/metadata', $metaDataHandlerV1);
|
||||||
http_response_code(405);
|
$router->post('/metadata', $metaDataHandlerV1);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: text/plain');
|
$router->dispatch();
|
||||||
|
|
||||||
if($reqHead)
|
|
||||||
return;
|
|
||||||
|
|
||||||
echo 'Metadata lookup service - OK';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_response_code(404);
|
|
||||||
|
|
22
src/MediaTypeExts.php
Normal file
22
src/MediaTypeExts.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
namespace Uiharu;
|
||||||
|
|
||||||
|
use Index\MediaType;
|
||||||
|
|
||||||
|
final class MediaTypeExts {
|
||||||
|
public static function toV1(MediaType $mediaType): array {
|
||||||
|
$parts = [
|
||||||
|
'string' => (string)$mediaType,
|
||||||
|
'type' => $mediaType->getCategory(),
|
||||||
|
'subtype' => $mediaType->getKind(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if(!empty($suffix = $mediaType->getSuffix()))
|
||||||
|
$parts['suffix'] = $suffix;
|
||||||
|
|
||||||
|
if(!empty($params = $mediaType->getParams()))
|
||||||
|
$parts['params'] = $params;
|
||||||
|
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
}
|
207
src/Url.php
Normal file
207
src/Url.php
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
<?php
|
||||||
|
namespace Uiharu;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
final class Url {
|
||||||
|
private string $scheme = '';
|
||||||
|
private string $host = '';
|
||||||
|
private int $port = 0;
|
||||||
|
private string $user = '';
|
||||||
|
private string $pass = '';
|
||||||
|
private string $path = '';
|
||||||
|
private string $query = '';
|
||||||
|
private string $fragment = '';
|
||||||
|
|
||||||
|
private ?string $formatted = null;
|
||||||
|
|
||||||
|
public function __construct(array $parts) {
|
||||||
|
if(isset($parts['scheme']))
|
||||||
|
$this->scheme = $parts['scheme'];
|
||||||
|
if(isset($parts['host']))
|
||||||
|
$this->host = $parts['host'];
|
||||||
|
if(isset($parts['port']))
|
||||||
|
$this->port = $parts['port'];
|
||||||
|
if(isset($parts['user']))
|
||||||
|
$this->user = $parts['user'];
|
||||||
|
if(isset($parts['pass']))
|
||||||
|
$this->pass = $parts['pass'];
|
||||||
|
if(isset($parts['path']))
|
||||||
|
$this->path = $parts['path'];
|
||||||
|
if(isset($parts['query']))
|
||||||
|
$this->query = $parts['query'];
|
||||||
|
if(isset($parts['fragment']))
|
||||||
|
$this->fragment = $parts['fragment'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parse(string $urlString): Url {
|
||||||
|
$parts = parse_url($urlString);
|
||||||
|
if($parts === false)
|
||||||
|
throw new InvalidArgumentException('Invalid URL provided.');
|
||||||
|
return new Url($parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetString(): void {
|
||||||
|
$this->formatted = null;
|
||||||
|
}
|
||||||
|
public function setScheme(string $scheme): void {
|
||||||
|
$this->scheme = $scheme;
|
||||||
|
$this->resetString();
|
||||||
|
}
|
||||||
|
public function discardFragment(): void {
|
||||||
|
$this->fragment = '';
|
||||||
|
$this->resetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasScheme(): bool {
|
||||||
|
return $this->scheme !== '';
|
||||||
|
}
|
||||||
|
public function hasHost(): bool {
|
||||||
|
return $this->host !== '';
|
||||||
|
}
|
||||||
|
public function hasPort(): bool {
|
||||||
|
return $this->port !== 0;
|
||||||
|
}
|
||||||
|
public function hasUser(): bool {
|
||||||
|
return $this->user !== '';
|
||||||
|
}
|
||||||
|
public function hasPassword(): bool {
|
||||||
|
return $this->pass !== '';
|
||||||
|
}
|
||||||
|
public function hasPath(): bool {
|
||||||
|
return $this->path !== '';
|
||||||
|
}
|
||||||
|
public function hasQuery(): bool {
|
||||||
|
return $this->query !== '';
|
||||||
|
}
|
||||||
|
public function hasFragment(): bool {
|
||||||
|
return $this->fragment !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScheme(): string {
|
||||||
|
return $this->scheme;
|
||||||
|
}
|
||||||
|
public function getHost(): string {
|
||||||
|
return $this->host;
|
||||||
|
}
|
||||||
|
public function getPort(): int {
|
||||||
|
return $this->port;
|
||||||
|
}
|
||||||
|
public function getUser(): string {
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
public function getPassword(): string {
|
||||||
|
return $this->pass;
|
||||||
|
}
|
||||||
|
public function getPath(): string {
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
public function getQuery(): string {
|
||||||
|
return $this->query;
|
||||||
|
}
|
||||||
|
public function getFragment(): string {
|
||||||
|
return $this->fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasUserInfo(): bool {
|
||||||
|
return $this->hasUser()
|
||||||
|
|| $this->hasPassword();
|
||||||
|
}
|
||||||
|
public function hasAuthority(): bool {
|
||||||
|
return $this->hasUserInfo()
|
||||||
|
|| $this->hasHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserInfo(): string {
|
||||||
|
$userInfo = $this->user;
|
||||||
|
if($this->pass !== '')
|
||||||
|
$userInfo .= ':' . $this->pass;
|
||||||
|
return $userInfo;
|
||||||
|
}
|
||||||
|
public function getAuthority(): string {
|
||||||
|
$authority = '//';
|
||||||
|
|
||||||
|
if($this->hasUserInfo())
|
||||||
|
$authority .= $this->getUserInfo() . '@';
|
||||||
|
|
||||||
|
$authority .= $this->host;
|
||||||
|
|
||||||
|
if($this->port !== 0)
|
||||||
|
$authority .= ':' . $this->port;
|
||||||
|
|
||||||
|
return $authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function calculateHash(bool $raw = true): string {
|
||||||
|
return hash('sha256', (string)$this, $raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string {
|
||||||
|
if($this->formatted === null) {
|
||||||
|
$string = '';
|
||||||
|
|
||||||
|
if($this->hasScheme())
|
||||||
|
$string .= $this->getScheme() . ':';
|
||||||
|
|
||||||
|
$hasAuthority = $this->hasAuthority();
|
||||||
|
if($hasAuthority)
|
||||||
|
$string .= $this->getAuthority();
|
||||||
|
|
||||||
|
$hasPath = $this->hasPath();
|
||||||
|
$path = $this->getPath();
|
||||||
|
|
||||||
|
if($hasAuthority && (!$hasPath || $path[0] !== '/'))
|
||||||
|
$string .= '/';
|
||||||
|
elseif(!$hasAuthority && $path[1] === '/')
|
||||||
|
$path = '/' . trim($path, '/');
|
||||||
|
|
||||||
|
$string .= $path;
|
||||||
|
|
||||||
|
// is all this necessary...?
|
||||||
|
if($this->hasQuery()) {
|
||||||
|
$string .= '?';
|
||||||
|
$parts = explode('&', $this->getQuery());
|
||||||
|
|
||||||
|
foreach($parts as $part) {
|
||||||
|
$param = explode('=', $part, 2);
|
||||||
|
$string .= rawurlencode($param[0]);
|
||||||
|
if(isset($param[1]))
|
||||||
|
$string .= '=' . rawurlencode($param[1]);
|
||||||
|
$string .= '&';
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = substr($string, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->hasFragment())
|
||||||
|
$string .= '#' . rawurlencode($this->getFragment());
|
||||||
|
|
||||||
|
$this->formatted = $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toV1(): array {
|
||||||
|
$parts = ['uri' => (string)$this];
|
||||||
|
|
||||||
|
if($this->hasScheme())
|
||||||
|
$parts['scheme'] = $this->getScheme();
|
||||||
|
if($this->hasHost())
|
||||||
|
$parts['host'] = $this->getHost();
|
||||||
|
if($this->hasPort())
|
||||||
|
$parts['port'] = $this->getPort();
|
||||||
|
if($this->hasUser())
|
||||||
|
$parts['user'] = $this->getUser();
|
||||||
|
if($this->hasPassword())
|
||||||
|
$parts['pass'] = $parts['password'] = $this->getPassword();
|
||||||
|
if($this->hasPath())
|
||||||
|
$parts['path'] = $this->getPath();
|
||||||
|
if($this->hasQuery())
|
||||||
|
$parts['query'] = $this->getQuery();
|
||||||
|
if($this->hasFragment())
|
||||||
|
$parts['fragment'] = $this->getFragment();
|
||||||
|
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,7 @@ define('UIH_DEBUG', is_file(UIH_ROOT . '/.debug'));
|
||||||
define('UIH_PUBLIC', UIH_ROOT . '/public');
|
define('UIH_PUBLIC', UIH_ROOT . '/public');
|
||||||
define('UIH_SOURCE', UIH_ROOT . '/src');
|
define('UIH_SOURCE', UIH_ROOT . '/src');
|
||||||
define('UIH_LIBRARY', UIH_ROOT . '/lib');
|
define('UIH_LIBRARY', UIH_ROOT . '/lib');
|
||||||
define('UIH_VERSION', '20220714');
|
define('UIH_VERSION', '20220715');
|
||||||
define('UIH_SEM_NAME', 'U');
|
|
||||||
define('UIH_SEM_PATH', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'uiharu');
|
|
||||||
|
|
||||||
require_once UIH_LIBRARY . '/index/index.php';
|
require_once UIH_LIBRARY . '/index/index.php';
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue