Added join_path to cleanly join paths.

Added sanitize_path to normalize and deduplicate directory separators.
Changed warehouse_path to be able to scale up the number of octect pairs as much as desired.
This commit is contained in:
matthew 2019-07-04 22:28:39 -05:00 committed by Shish
parent ac1196dee1
commit 639c896a16
2 changed files with 210 additions and 13 deletions

139
core/tests/util.test.php Normal file
View file

@ -0,0 +1,139 @@
<?php
require_once "core/util.php";
class UtilTest extends \PHPUnit\Framework\TestCase
{
public function test_sanitize_path()
{
$this->assertEquals(
"one",
sanitize_path("one")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
sanitize_path("one\\two")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
sanitize_path("one/two")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
sanitize_path("one\\\\two")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
sanitize_path("one//two")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
sanitize_path("one\\\\\\two")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
sanitize_path("one///two")
);
$this->assertEquals(
DIRECTORY_SEPARATOR."one".DIRECTORY_SEPARATOR."two".DIRECTORY_SEPARATOR,
sanitize_path("\\/one/\\/\\/two\\/")
);
}
public function test_join_path()
{
$this->assertEquals(
"one",
join_path("one")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two",
join_path("one","two")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two".DIRECTORY_SEPARATOR."three",
join_path("one","two","three")
);
$this->assertEquals(
"one".DIRECTORY_SEPARATOR."two".DIRECTORY_SEPARATOR."three",
join_path("one/two","three")
);
$this->assertEquals(
DIRECTORY_SEPARATOR."one".DIRECTORY_SEPARATOR."two".DIRECTORY_SEPARATOR."three".DIRECTORY_SEPARATOR,
join_path("\\/////\\\\one/\///"."\\//two\/\\//\\//","//\/\\\/three/\\/\/")
);
}
public function test_warehouse_path()
{
$hash = "7ac19c10d6859415";
$this->assertEquals(
join_path(DATA_DIR,"base",$hash),
warehouse_path("base",$hash,false, 0)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a",$hash),
warehouse_path("base",$hash,false, 1)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1",$hash),
warehouse_path("base",$hash,false, 2)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c",$hash),
warehouse_path("base",$hash,false, 3)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10",$hash),
warehouse_path("base",$hash,false, 4)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10","d6",$hash),
warehouse_path("base",$hash,false, 5)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10","d6","85",$hash),
warehouse_path("base",$hash,false, 6)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10","d6","85","94",$hash),
warehouse_path("base",$hash,false, 7)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10","d6","85","94","15",$hash),
warehouse_path("base",$hash,false, 8)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10","d6","85","94","15",$hash),
warehouse_path("base",$hash,false, 9)
);
$this->assertEquals(
join_path(DATA_DIR,"base","7a","c1","9c","10","d6","85","94","15",$hash),
warehouse_path("base",$hash,false, 10)
);
}
}

View file

@ -5,6 +5,9 @@ require_once "vendor/shish/libcontext-php/context.php";
* Misc *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const DATA_DIR = "data";
function mtimefile(string $file): string
{
$data_href = get_base_href();
@ -159,28 +162,40 @@ function format_text(string $string): string
return $tfe->formatted;
}
function warehouse_path(string $base, string $hash, bool $create=true): string
/**
* Generates the path to a file under the data folder based on the file's hash.
* This process creates subfolders based on octet pairs from the file's hash.
* The calculated folder follows this pattern data/$base/octet_pairs/$hash
* @param string $base
* @param string $hash
* @param bool $create
* @param int $splits The number of octet pairs to split the hash into. Caps out at strlen($hash)/2.
* @return string
*/
function warehouse_path(string $base, string $hash, bool $create=true, int $splits = WH_SPLITS): string
{
$ab = substr($hash, 0, 2);
$cd = substr($hash, 2, 2);
$pa = Image::DATA_DIR.'/'.$base.'/';
if (WH_SPLITS == 2) {
$pa .= $ab.'/'.$cd.'/'.$hash;
} else {
$pa .= $ab.'/'.$hash;
$dirs =[DATA_DIR, $base];
$splits = min($splits, strlen($hash) / 2);
for($i = 0; $i < $splits; $i++) {
$dirs[] = substr($hash, $i * 2, 2);
}
$dirs[] = $hash;
$pa = join_path(...$dirs);
if ($create && !file_exists(dirname($pa))) {
mkdir(dirname($pa), 0755, true);
}
return $pa;
}
function data_path(string $filename): string
/**
* Determines the path to the specified file in the data folder.
*/
function data_path(string $filename, bool $create = true): string
{
$filename = "data/" . $filename;
if (!file_exists(dirname($filename))) {
$filename = join_path("data", $filename);
if ($create&&!file_exists(dirname($filename))) {
mkdir(dirname($filename), 0755, true);
}
return $filename;
@ -325,6 +340,49 @@ function path_to_tags(string $path): string
return implode(" ", $tags);
}
/**
* Translates all possible directory separators to the appropriate one for the current system,
* and removes any duplicate separators.
*/
function sanitize_path(string $path): string
{
return preg_replace('|[\\\\/]+|S',DIRECTORY_SEPARATOR,$path);
}
/**
* Combines all path segments specified, ensuring no duplicate separators occur,
* as well as converting all possible separators to the one appropriate for the current system.
*/
function join_path(string ...$paths): string
{
$output = "";
foreach ($paths as $path) {
if(empty($path)) {
continue;
}
$path = sanitize_path($path);
if(empty($output)) {
$output = $path;
} else {
$output = rtrim($output, DIRECTORY_SEPARATOR);
$path = ltrim($path, DIRECTORY_SEPARATOR);
$output .= DIRECTORY_SEPARATOR . $path;
}
}
return $output;
}
function join_url(string $base, string ...$paths)
{
$output = $base;
foreach ($paths as $path) {
$output = rtrim($output,"/");
$path = ltrim($path, "/");
$output .= "/".$path;
}
return $output;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Debugging functions *