From a22529a1a8b657db6bab1b89f3b080c47f1d9c5b Mon Sep 17 00:00:00 2001 From: yggverse Date: Sat, 27 Apr 2024 21:10:28 +0300 Subject: [PATCH] update realpath builder --- README.md | 4 +- src/nex.php | 138 +++++++++++++++++++++++++++------------------------- 2 files changed, 75 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 7bce880..e94ebe9 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,13 @@ php src/nex.php host=127.0.0.1 port=1900 path=/target/dir * `list` - show content listing in the requested directory (when index file not found), `yes` by default * `fail` - **filepath** that contain failure text or template (e.g. `error.gmi`), `fail` text by default * `size` - limit request length in bytes, `1024` by default -* `dump` - dump queries or set blank to disable, default: `[{time}] [{code}] {host}:{port} {path} {goal}` +* `dump` - dump queries or set blank to disable, default: `[{time}] [{code}] {host}:{port} {path} {real}` * `{time}` - event time in `c` format * `{code}` - formal response code: `1` - found, `0` - not found * `{host}` - peer host * `{port}` - peer port * `{path}` - path requested - * `{goal}` - goal destination returned + * `{real}` - **realpath** returned ### Autostart diff --git a/src/nex.php b/src/nex.php index 2cb0419..c4e3f81 100644 --- a/src/nex.php +++ b/src/nex.php @@ -167,7 +167,7 @@ if (!defined('NEXT_SIZE')) define('NEXT_SIZE', 1024); if (!defined('NEXT_FAIL')) define('NEXT_FAIL', 'fail'); -if (!defined('NEXT_DUMP')) define('NEXT_DUMP', '[{time}] [{code}] {host}:{port} {path} {goal}'); +if (!defined('NEXT_DUMP')) define('NEXT_DUMP', '[{time}] [{code}] {host}:{port} {path} {real}'); // Init server $server = new \Yggverse\Nex\Server( @@ -182,15 +182,11 @@ $server->start( string $connect ): ?string { - // Filter goal request - $goal = preg_replace( - [ - '/\\\/', // unify separators - '/(^|\/)[\.]+/', // hidden items started with dot - '/[\.]+\//', // relative directory paths - '/[\/]+\//', // remove extra slashes - ], - DIRECTORY_SEPARATOR, + // Define response + $response = null; + + // Build realpath + $realpath = realpath( NEXT_PATH . filter_var( urldecode( $request @@ -199,88 +195,100 @@ $server->start( ) ); - // Define response - $response = null; - - // Directory request - if (is_dir($goal)) + // Make sure directory path ending with slash + if (is_dir($realpath)) { - // Try index file first on enabled - if (NEXT_FILE && is_readable($goal . NEXT_FILE)) - { - $response = file_get_contents( - $goal . NEXT_FILE - ); - } + $realpath = rtrim( + $realpath, + DIRECTORY_SEPARATOR + ) . DIRECTORY_SEPARATOR; + } - // Try directory listing on enabled - else if (NEXT_LIST && is_readable($goal)) + // Validate realpath exists, started with path defined and destination resource is not hidden + if ($realpath && str_starts_with($realpath, NEXT_PATH) && !str_starts_with(basename($realpath), '.')) + { + // Try directory + if (is_dir($realpath)) { - $links = []; + // Try index file first on enabled + if (NEXT_FILE && file_exists($realpath . NEXT_FILE) && is_readable($realpath . NEXT_FILE)) + { + $response = file_get_contents( + $realpath . NEXT_FILE + ); + } - foreach ((array) scandir($goal) as $link) + // Try build directory listing on enabled + else if (NEXT_LIST) { - // Skip system entities - if (str_starts_with($link, '.')) + $links = []; + + foreach ((array) scandir($realpath) as $link) { - // Keep parent navigation entities only - if ($link == '..' && $parent = realpath($goal . $link)) + // Process system entities + if (str_starts_with($link, '.')) { - if (str_starts_with($parent . DIRECTORY_SEPARATOR, NEXT_PATH)) + // Parent navigation + if ($link == '..' && $parent = realpath($realpath . $link)) { - if (is_readable($parent)) + $parent = rtrim( + $parent, + DIRECTORY_SEPARATOR + ) . DIRECTORY_SEPARATOR; + + if (str_starts_with($parent, NEXT_PATH)) { $links[] = '=> ../'; } } + + continue; // skip everything else } - continue; - } + // Directory + if (is_dir($realpath . $link)) + { + if (is_readable($realpath . $link)) + { + $links[] = sprintf( + '=> %s/', + urlencode( + $link + ) + ); + } - // Directory - if (is_dir($goal . $link)) - { - if (is_readable($goal . $link)) + continue; + } + + // File + if (is_readable($realpath . $link)) { $links[] = sprintf( - '=> %s/', + '=> %s', urlencode( $link ) ); } - - continue; } - // File - if (is_readable($goal . $link)) - { - $links[] = sprintf( - '=> %s', - urlencode( - $link - ) - ); - } + $response = implode( + PHP_EOL, + $links + ); } + } - $response = implode( - PHP_EOL, - $links + // Try file + else + { + $response = file_get_contents( + $realpath ); } } - // Try file - else if (is_readable($goal)) - { - $response = file_get_contents( - $goal - ); - } - // Dump request on enabled if (NEXT_DUMP) { @@ -292,7 +300,7 @@ $server->start( '{host}', '{port}', '{path}', - '{goal}', + '{real}', ], [ (string) date('c'), @@ -300,7 +308,7 @@ $server->start( (string) parse_url($connect, PHP_URL_HOST), (string) parse_url($connect, PHP_URL_PORT), (string) str_replace('%', '%%', empty($request) ? '/' : trim($request)), - (string) str_replace('%', '%%', $goal) + (string) str_replace('%', '%%', $realpath) ], NEXT_DUMP ) . PHP_EOL @@ -308,6 +316,6 @@ $server->start( } // Send response - return empty($response) ? NEXT_FAIL : $response; + return is_null($response) ? NEXT_FAIL : $response; } ); \ No newline at end of file