-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathFileNameFilter.php
145 lines (129 loc) · 4.29 KB
/
FileNameFilter.php
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<?php
namespace SilverStripe\Assets;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\View\Parsers\Transliterator;
/**
* Filter certain characters from file name, for nicer (more SEO-friendly) URLs
* as well as better filesystem compatibility.
*
* Caution: Does not take care of full filename sanitization in regards to directory traversal etc.,
* please use PHP's built-in basename() for this purpose.
*
* For file name filtering see {@link FileNameFilter}.
*
* The default sanitizer is quite conservative regarding non-ASCII characters,
* in order to achieve maximum filesystem compatibility.
* In case your filesystem supports a wider character set,
* or is case sensitive, you might want to relax these rules
* via overriding {@link FileNameFilter_DefaultFilter::$default_replacements}.
*
* To leave uploaded filenames as they are (being aware of filesystem restrictions),
* add the following code to your YAML config:
* <code>
* SilverStripe\Assets\FileNameFilter:
* default_use_transliterator: false
* default_replacements:
* </code>
*
* See {@link URLSegmentFilter} for a more generic implementation.
*/
class FileNameFilter
{
use Configurable;
use Injectable;
/**
* @config
* @var Boolean
*/
private static $default_use_transliterator = true;
/**
* @config
* @var array See {@link setReplacements()}.
*/
private static $default_replacements = [
'/\s/' => '-', // remove whitespace
'/[^-_A-Za-z0-9+.]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash, dot, and underscore
'/_{2,}/' => '_', // remove duplicate underscores (since `__` is variant separator)
'/-{2,}/' => '-', // remove duplicate dashes
'/^[-_\.]+/' => '', // Remove all leading dots, dashes or underscores
];
/**
* @var array See {@link setReplacements()}
*/
public $replacements = [];
/**
* Depending on the applied replacement rules, this method
* might result in an empty string. In this case, {@link getDefaultName()}
* will be used to return a randomly generated file name, while retaining its extension.
*
* @param string $name including extension (not path).
* @return string A filtered filename
*/
public function filter($name)
{
$ext = pathinfo($name ?? '', PATHINFO_EXTENSION);
$transliterator = $this->getTransliterator();
if ($transliterator) {
$name = $transliterator->toASCII($name);
}
foreach ($this->getReplacements() as $regex => $replace) {
$name = preg_replace($regex ?? '', $replace ?? '', $name ?? '');
}
// Safeguard against empty file names
$nameWithoutExt = pathinfo($name ?? '', PATHINFO_FILENAME);
if ($name === $ext || empty($nameWithoutExt)) {
$name = $this->getDefaultName();
$name .= $ext ? '.' . $ext : '';
}
return $name;
}
/**
* Take care not to add replacements which might invalidate the file structure,
* e.g. removing dots will remove file extension information.
*
* @param array $replacements Map of find/replace used for preg_replace().
*/
public function setReplacements($replacements)
{
$this->replacements = $replacements;
}
/**
* @return array
*/
public function getReplacements()
{
return $this->replacements ?: (array)$this->config()->get('default_replacements');
}
/**
* Transliterator instance, or false to disable.
* If null will use default.
*
* @var Transliterator|false
*/
protected $transliterator;
/**
* @return Transliterator
*/
public function getTransliterator()
{
if ($this->transliterator === null && $this->config()->default_use_transliterator) {
$this->transliterator = Transliterator::create();
}
return $this->transliterator;
}
/**
* @param Transliterator|false $transliterator
*/
public function setTransliterator($transliterator)
{
$this->transliterator = $transliterator;
}
/**
* @return string File name without extension
*/
public function getDefaultName()
{
return (string)uniqid();
}
}