Browse Source

update realpath builder

nex-php
yggverse 7 months ago
parent
commit
a22529a1a8
  1. 4
      README.md
  2. 78
      src/nex.php

4
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 * `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 * `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 * `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 * `{time}` - event time in `c` format
* `{code}` - formal response code: `1` - found, `0` - not found * `{code}` - formal response code: `1` - found, `0` - not found
* `{host}` - peer host * `{host}` - peer host
* `{port}` - peer port * `{port}` - peer port
* `{path}` - path requested * `{path}` - path requested
* `{goal}` - goal destination returned * `{real}` - **realpath** returned
### Autostart ### Autostart

78
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_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 // Init server
$server = new \Yggverse\Nex\Server( $server = new \Yggverse\Nex\Server(
@ -182,15 +182,11 @@ $server->start(
string $connect string $connect
): ?string ): ?string
{ {
// Filter goal request // Define response
$goal = preg_replace( $response = null;
[
'/\\\/', // unify separators // Build realpath
'/(^|\/)[\.]+/', // hidden items started with dot $realpath = realpath(
'/[\.]+\//', // relative directory paths
'/[\/]+\//', // remove extra slashes
],
DIRECTORY_SEPARATOR,
NEXT_PATH . filter_var( NEXT_PATH . filter_var(
urldecode( urldecode(
$request $request
@ -199,49 +195,60 @@ $server->start(
) )
); );
// Define response // Make sure directory path ending with slash
$response = null; if (is_dir($realpath))
{
$realpath = rtrim(
$realpath,
DIRECTORY_SEPARATOR
) . DIRECTORY_SEPARATOR;
}
// Directory request // Validate realpath exists, started with path defined and destination resource is not hidden
if (is_dir($goal)) if ($realpath && str_starts_with($realpath, NEXT_PATH) && !str_starts_with(basename($realpath), '.'))
{
// Try directory
if (is_dir($realpath))
{ {
// Try index file first on enabled // Try index file first on enabled
if (NEXT_FILE && is_readable($goal . NEXT_FILE)) if (NEXT_FILE && file_exists($realpath . NEXT_FILE) && is_readable($realpath . NEXT_FILE))
{ {
$response = file_get_contents( $response = file_get_contents(
$goal . NEXT_FILE $realpath . NEXT_FILE
); );
} }
// Try directory listing on enabled // Try build directory listing on enabled
else if (NEXT_LIST && is_readable($goal)) else if (NEXT_LIST)
{ {
$links = []; $links = [];
foreach ((array) scandir($goal) as $link) foreach ((array) scandir($realpath) as $link)
{ {
// Skip system entities // Process system entities
if (str_starts_with($link, '.')) if (str_starts_with($link, '.'))
{ {
// Keep parent navigation entities only // Parent navigation
if ($link == '..' && $parent = realpath($goal . $link)) if ($link == '..' && $parent = realpath($realpath . $link))
{
if (str_starts_with($parent . DIRECTORY_SEPARATOR, NEXT_PATH))
{ {
if (is_readable($parent)) $parent = rtrim(
$parent,
DIRECTORY_SEPARATOR
) . DIRECTORY_SEPARATOR;
if (str_starts_with($parent, NEXT_PATH))
{ {
$links[] = '=> ../'; $links[] = '=> ../';
} }
} }
}
continue; continue; // skip everything else
} }
// Directory // Directory
if (is_dir($goal . $link)) if (is_dir($realpath . $link))
{ {
if (is_readable($goal . $link)) if (is_readable($realpath . $link))
{ {
$links[] = sprintf( $links[] = sprintf(
'=> %s/', '=> %s/',
@ -255,7 +262,7 @@ $server->start(
} }
// File // File
if (is_readable($goal . $link)) if (is_readable($realpath . $link))
{ {
$links[] = sprintf( $links[] = sprintf(
'=> %s', '=> %s',
@ -274,12 +281,13 @@ $server->start(
} }
// Try file // Try file
else if (is_readable($goal)) else
{ {
$response = file_get_contents( $response = file_get_contents(
$goal $realpath
); );
} }
}
// Dump request on enabled // Dump request on enabled
if (NEXT_DUMP) if (NEXT_DUMP)
@ -292,7 +300,7 @@ $server->start(
'{host}', '{host}',
'{port}', '{port}',
'{path}', '{path}',
'{goal}', '{real}',
], ],
[ [
(string) date('c'), (string) date('c'),
@ -300,7 +308,7 @@ $server->start(
(string) parse_url($connect, PHP_URL_HOST), (string) parse_url($connect, PHP_URL_HOST),
(string) parse_url($connect, PHP_URL_PORT), (string) parse_url($connect, PHP_URL_PORT),
(string) str_replace('%', '%%', empty($request) ? '/' : trim($request)), (string) str_replace('%', '%%', empty($request) ? '/' : trim($request)),
(string) str_replace('%', '%%', $goal) (string) str_replace('%', '%%', $realpath)
], ],
NEXT_DUMP NEXT_DUMP
) . PHP_EOL ) . PHP_EOL
@ -308,6 +316,6 @@ $server->start(
} }
// Send response // Send response
return empty($response) ? NEXT_FAIL : $response; return is_null($response) ? NEXT_FAIL : $response;
} }
); );
Loading…
Cancel
Save