-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHelpers.php
More file actions
105 lines (88 loc) · 3.14 KB
/
Copy pathHelpers.php
File metadata and controls
105 lines (88 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?php
declare(strict_types=1);
namespace ADT\Files;
use Nette\Utils\Random;
use Nette\Utils\Strings;
class Helpers
{
/* Maximální délka sloupce originalName */
const int ORIGINAL_NAME_LEN = 255;
/* Maximální délka sloupce name */
const int NAME_LEN = 255;
/* Délka hashe, který se přidá k názvu souboru, aby nebyl název souboru uhodnutelný */
const int HASH_LEN = 5;
/*
* Po kolika znacích bude IDčko rozděleno na stromovou strukturu složek.
* Maximální počet záznamů (souborů + složek) M v jedné složce je dán vztahem
* M = 2 * 10^(ID_SPLIT_LEN)
*/
const int ID_SPLIT_LEN = 3;
/**
* Zadané jméno souboru zkrátí na maximální délku tak, že pokud je $name
* kratší, vrátí ho nezměněné. Pokud je delší, nejprve zkrátí extension na
* maximálně $maxExtLen znaků a zkracuje řetězec $name od konce před
* extension. Název souboru $name nemusí mít příponu. Předpokládá, že $name
* neobsahuje žádnou cestu, pouze název souboru.
*/
public static function resizeName($name, int $maxLen = self::ORIGINAL_NAME_LEN, int $maxExtLen = 10): string
{
if (mb_strlen($name) < $maxLen) {
return $name;
}
$pathinfo = pathinfo($name);
if (!isset($pathinfo['extension'])) {
return mb_substr($name, 0, $maxLen);
}
// omezení extension
$pathinfo['extension'] = mb_substr($pathinfo['extension'], 0, $maxExtLen);
return mb_substr(
$pathinfo['filename'],
0,
$maxLen - mb_strlen($pathinfo['extension']) - 1
) . '.' . $pathinfo['extension'];
}
/**
* Pro daný ActiveRow (id, originalName) vrátí název a cestu k souboru.
* Adresářová struktura je vytvářena tak, aby nebylo v jednom adresáři přiliš
* mnoho záznamů (souborů a složek). Pokud je místo $id zadán callback, je
* použit způsob generování id náhodně. Tento callback pak ověřuje, zda je
* náhodně vygenerované id již použito nebo ne.
* @param string $originalName
* @param callable|integer $id Id, které se má použít a nebo callback
* ověřující, zda je náhodně vygenerované id již použité:
* function(array $id) {}. Id je pole - číslo rozdělené po ID_SPLIT_LEN
* dekadických číslicích. Vrací boolean.
* @return string
*/
public static function getName(string $originalName, callable|int $id): string
{
if (is_scalar($id)) {
$id = str_split((string)$id, static::ID_SPLIT_LEN);
} else {
if (is_callable($id)) {
$isIdUsedCallback = $id;
unset($id);
$length = 0;
do {
$length++;
$id = [];
for ($i = 0; $i < $length; $i++) {
$id[] = rand(0, pow(10, static::ID_SPLIT_LEN) - 1);
}
} while ($isIdUsedCallback($id));
}
}
$pathinfo = pathinfo($originalName);
$originalName = Strings::webalize($pathinfo['filename']);
if (isset($pathinfo['extension'])) {
$originalName .= '.' . $pathinfo['extension'];
}
$idPart = implode(DIRECTORY_SEPARATOR, $id);
$namePart = static::resizeName(
$originalName,
static::NAME_LEN - strlen($idPart) - static::HASH_LEN - 2
);
$hashPart = Random::generate(self::HASH_LEN);
return $idPart . '_' . $hashPart . '_' . $namePart;
}
}