mirror of
https://github.com/YGGverse/next.git
synced 2026-04-01 02:05:29 +00:00
implement multi-protocol async server based on ratchet library #1
This commit is contained in:
parent
296525aac3
commit
ec60ef5e5b
8 changed files with 707 additions and 387 deletions
253
src/Model/Filesystem.php
Normal file
253
src/Model/Filesystem.php
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Next\Model;
|
||||
|
||||
class Filesystem
|
||||
{
|
||||
private string $_root;
|
||||
|
||||
public function __construct(?string $path)
|
||||
{
|
||||
// Require path value to continue
|
||||
if (empty($path))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('root path required!')
|
||||
);
|
||||
}
|
||||
|
||||
// Require absolute path
|
||||
if (!str_starts_with($path, DIRECTORY_SEPARATOR))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('root path not absolute!')
|
||||
);
|
||||
}
|
||||
|
||||
// Exclude symlinks and relative entities, append slash
|
||||
if (!$realpath = $this->_realpath($path))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('could not build root realpath!')
|
||||
);
|
||||
}
|
||||
|
||||
// Root must be directory
|
||||
if (!is_dir($realpath))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('root path is not directory!')
|
||||
);
|
||||
}
|
||||
|
||||
// Check root path does not contain hidden context
|
||||
if (str_contains($realpath, DIRECTORY_SEPARATOR . '.'))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('root path must not contain hidden context!')
|
||||
);
|
||||
}
|
||||
|
||||
// Done!
|
||||
$this->_root = $realpath;
|
||||
}
|
||||
|
||||
public function root(): string
|
||||
{
|
||||
return $this->_root;
|
||||
}
|
||||
|
||||
public function file(?string $realpath): ?string
|
||||
{
|
||||
if (!$this->valid($realpath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_file($realpath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return file_get_contents(
|
||||
$realpath
|
||||
);
|
||||
}
|
||||
|
||||
public function list(
|
||||
?string $realpath,
|
||||
string $sort = 'name',
|
||||
int $order = SORT_ASC,
|
||||
int $method = SORT_STRING | SORT_NATURAL | SORT_FLAG_CASE
|
||||
): ?array
|
||||
{
|
||||
// Validate requested path
|
||||
if (!$this->valid($realpath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make sure requested path is directory
|
||||
if (!is_dir($realpath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Begin list builder
|
||||
$directories = [];
|
||||
$files = [];
|
||||
|
||||
foreach ((array) scandir($realpath) as $name)
|
||||
{
|
||||
// Skip system locations
|
||||
if (empty($name) || $name == '.')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Build destination path
|
||||
if (!$path = $this->_realpath($realpath . $name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate destination path
|
||||
if (!$this->valid($path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Context
|
||||
switch (true)
|
||||
{
|
||||
case is_dir($path):
|
||||
|
||||
$directories[] =
|
||||
[
|
||||
'file' => false,
|
||||
'name' => $name,
|
||||
'path' => $path,
|
||||
'time' => filemtime(
|
||||
$path
|
||||
)
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case is_file($path):
|
||||
|
||||
$files[] =
|
||||
[
|
||||
'file' => true,
|
||||
'name' => $name,
|
||||
'path' => $path,
|
||||
'time' => filemtime(
|
||||
$path
|
||||
)
|
||||
];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort order
|
||||
array_multisort(
|
||||
array_column(
|
||||
$directories,
|
||||
$sort
|
||||
),
|
||||
$order,
|
||||
$method,
|
||||
$directories
|
||||
);
|
||||
|
||||
// Sort files by name ASC
|
||||
array_multisort(
|
||||
array_column(
|
||||
$directories,
|
||||
$sort
|
||||
),
|
||||
$order,
|
||||
$method,
|
||||
$directories
|
||||
);
|
||||
|
||||
// Merge list
|
||||
return array_merge(
|
||||
$directories,
|
||||
$files
|
||||
);
|
||||
}
|
||||
|
||||
public function valid(?string $realpath): bool
|
||||
{
|
||||
if (empty($realpath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($realpath != $this->_realpath($realpath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!str_starts_with($realpath, $this->_root))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (str_contains($realpath, DIRECTORY_SEPARATOR . '.'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_readable($realpath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return absolute realpath with root constructed
|
||||
public function absolute(?string $path): ?string
|
||||
{
|
||||
if (!$realpath = $this->_realpath($this->_root . $path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return $realpath;
|
||||
}
|
||||
|
||||
// PHP::realpath extension appending slash to dir paths
|
||||
private function _realpath(?string $path): ?string
|
||||
{
|
||||
if (empty($path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$realpath = realpath($path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_readable($realpath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_dir($realpath))
|
||||
{
|
||||
$realpath = rtrim(
|
||||
$realpath,
|
||||
DIRECTORY_SEPARATOR
|
||||
) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
return $realpath;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue