1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Webino (http://webino.sk) |
4
|
|
|
* |
5
|
|
|
* @link https://github.com/webino/WebinoI18nSanitizeLib for the canonical source repository |
6
|
|
|
* @copyright Copyright (c) 2017 Webino, s. r. o. (http://webino.sk) |
7
|
|
|
* @author Peter Bačinský <[email protected]> |
8
|
|
|
* @license BSD-3-Clause |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace WebinoI18nSanitizeLib; |
12
|
|
|
|
13
|
|
|
use Zend\Filter; |
14
|
|
|
use Zend\Filter\Exception; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Class Sanitize |
18
|
|
|
* |
19
|
|
|
* @author Martin Hujer [email protected] |
20
|
|
|
*/ |
21
|
|
|
class Sanitize implements Filter\FilterInterface |
22
|
|
|
{ |
23
|
|
|
/** |
24
|
|
|
* Character(s) used to replace delimiters |
25
|
|
|
* |
26
|
|
|
* @var string |
27
|
|
|
*/ |
28
|
|
|
protected $delimiterReplacement; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Word delimiters which are replaced by spaceReplacement string |
32
|
|
|
* |
33
|
|
|
* @var array |
34
|
|
|
*/ |
35
|
|
|
protected $wordDelimiters = [' ', '.', '\\', '/', '-', '_']; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Which characters are not replaced |
39
|
|
|
* |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
protected $notReplacedChars = []; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var Transliteration |
46
|
|
|
*/ |
47
|
|
|
protected $transliteration; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var Filter\StringTrim |
51
|
|
|
*/ |
52
|
|
|
protected $stringTrim; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @var Filter\StringToLower |
56
|
|
|
*/ |
57
|
|
|
protected $stringToLower; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* |
61
|
|
|
* @param string $delimiterReplacement |
62
|
|
|
* @param string|array $wordDelimiters |
63
|
|
|
*/ |
64
|
|
|
public function __construct($delimiterReplacement = '-', $wordDelimiters = null) |
65
|
|
|
{ |
66
|
|
|
$this->setDelimiterReplacement($delimiterReplacement); |
67
|
|
|
if (null !== $wordDelimiters) { |
68
|
|
|
$this->addWordDelimiter($wordDelimiters); |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Returns $value filtered to valid URL |
74
|
|
|
* |
75
|
|
|
* @param string $s |
76
|
|
|
* @return string |
77
|
|
|
*/ |
78
|
|
|
public function filter($s) |
79
|
|
|
{ |
80
|
|
|
// convert to ascii -> translate strange chars |
81
|
|
|
$s = $this->getTransliteration()->filter($s); |
82
|
|
|
// trim spaces |
83
|
|
|
$s = $this->getStringTrim()->filter($s); |
84
|
|
|
// replace delimiters with another character |
85
|
|
|
$s = $this->replaceDelimiters($s); |
86
|
|
|
// lower chars |
87
|
|
|
$s = $this->getStringToLower()->filter($s); |
88
|
|
|
// delete chars except a-z0-9 |
89
|
|
|
$s = $this->trimSpecialsChars($s); |
90
|
|
|
// replace double dashes with single one |
91
|
|
|
$s = $this->replaceDoubleDelimiterReplacementWithSingle($s); |
92
|
|
|
// trim dashes on beginning/end of the string |
93
|
|
|
$s = $this->trimStartAndEndSpaceReplacement($s); |
94
|
|
|
return $s; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @return Transliteration |
99
|
|
|
*/ |
100
|
|
|
public function getTransliteration() |
101
|
|
|
{ |
102
|
|
|
if (null === $this->transliteration) { |
103
|
|
|
$this->transliteration = new Transliteration; |
104
|
|
|
} |
105
|
|
|
return $this->transliteration; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @param Transliteration $transliteration |
110
|
|
|
* @return $this |
111
|
|
|
*/ |
112
|
|
|
public function setTransliteration(Transliteration $transliteration) |
113
|
|
|
{ |
114
|
|
|
$this->transliteration = $transliteration; |
115
|
|
|
return $this; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @return Filter\StringTrim |
120
|
|
|
*/ |
121
|
|
|
public function getStringTrim() |
122
|
|
|
{ |
123
|
|
|
if (null === $this->stringTrim) { |
124
|
|
|
$this->stringTrim = new Filter\StringTrim; |
125
|
|
|
} |
126
|
|
|
return $this->stringTrim; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @param Filter\StringTrim $stringTrim |
131
|
|
|
* @return $this |
132
|
|
|
*/ |
133
|
|
|
public function setStringTrim(Filter\StringTrim $stringTrim) |
134
|
|
|
{ |
135
|
|
|
$this->stringTrim = $stringTrim; |
136
|
|
|
return $this; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @return Filter\StringToLower |
141
|
|
|
*/ |
142
|
|
|
public function getStringToLower() |
143
|
|
|
{ |
144
|
|
|
if (null === $this->stringToLower) { |
145
|
|
|
$this->stringToLower = new Filter\StringToLower; |
146
|
|
|
$this->stringToLower->setEncoding('utf-8'); |
147
|
|
|
} |
148
|
|
|
return $this->stringToLower; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @param Filter\StringToLower $stringToLower |
153
|
|
|
* @return $this |
154
|
|
|
*/ |
155
|
|
|
public function setStringToLower(Filter\StringToLower $stringToLower) |
156
|
|
|
{ |
157
|
|
|
$this->stringToLower = $stringToLower; |
158
|
|
|
return $this; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* @param string|array $notReplaced |
163
|
|
|
* @return $this |
164
|
|
|
* @throws Exception\RuntimeException |
165
|
|
|
*/ |
166
|
|
View Code Duplication |
public function addNotReplacedChars($notReplaced) |
|
|
|
|
167
|
|
|
{ |
168
|
|
|
if (in_array($notReplaced, $this->getNotReplacedChars())) { |
169
|
|
|
throw new Exception\RuntimeException("Not replaced characterr '$notReplaced' is already there."); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
if (empty($notReplaced)) { |
173
|
|
|
throw new Exception\RuntimeException('Not replaced character cannot be null.'); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if (is_array($notReplaced)) { |
177
|
|
|
$this->notReplacedChars = array_merge($this->getNotReplacedChars(), $notReplaced); |
178
|
|
|
} else { |
179
|
|
|
$this->notReplacedChars[] = $notReplaced; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
return $this; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Returns chars which are not replaced |
187
|
|
|
* |
188
|
|
|
* @return array |
189
|
|
|
*/ |
190
|
|
|
public function getNotReplacedChars() |
191
|
|
|
{ |
192
|
|
|
return $this->notReplacedChars; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Remove not replaced character |
197
|
|
|
* |
198
|
|
|
* @param string|array $notReplaced |
199
|
|
|
* @return $this |
200
|
|
|
* @throws Exception\RuntimeException |
201
|
|
|
*/ |
202
|
|
View Code Duplication |
public function removeNotReplacedChar($notReplaced) |
|
|
|
|
203
|
|
|
{ |
204
|
|
|
if (empty($notReplaced)) { |
205
|
|
|
throw new Exception\RuntimeException('Not replaced character cannot be null.'); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
if (is_array($notReplaced)) { |
209
|
|
|
foreach ($notReplaced as $n) { |
210
|
|
|
$this->removeNotReplacedChar($n); |
211
|
|
|
} |
212
|
|
|
} else { |
213
|
|
|
if (!in_array($notReplaced, $this->getNotReplacedChars())) { |
214
|
|
|
throw new Exception\RuntimeException("Not replaced character '$notReplaced' is not in array."); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$notReplacedChars = []; |
218
|
|
|
foreach ($this->notReplacedChars as $n) { |
219
|
|
|
if ($n != $notReplaced) { |
220
|
|
|
$notReplacedChars[] = $n; |
221
|
|
|
} |
222
|
|
|
$this->notReplacedChars = $notReplacedChars; |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
return $this; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Returns the delimiterReplacement option |
231
|
|
|
* |
232
|
|
|
* @return string |
233
|
|
|
*/ |
234
|
|
|
public function getDelimiterReplacement() |
235
|
|
|
{ |
236
|
|
|
return $this->delimiterReplacement; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* Sets the delimiterReplacement option |
241
|
|
|
* |
242
|
|
|
* @param string $delimiterReplacement |
243
|
|
|
* @return $this |
244
|
|
|
*/ |
245
|
|
|
public function setDelimiterReplacement($delimiterReplacement) |
246
|
|
|
{ |
247
|
|
|
$this->delimiterReplacement = $delimiterReplacement; |
248
|
|
|
return $this; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Returns word delimiters array |
253
|
|
|
* |
254
|
|
|
* @return array |
255
|
|
|
*/ |
256
|
|
|
public function getWordDelimiters() |
257
|
|
|
{ |
258
|
|
|
return $this->wordDelimiters; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Add word delimiter |
263
|
|
|
* |
264
|
|
|
* @param string|array $delimiter |
265
|
|
|
* @return $this |
266
|
|
|
* @throws Exception\RuntimeException |
267
|
|
|
*/ |
268
|
|
View Code Duplication |
public function addWordDelimiter($delimiter) |
|
|
|
|
269
|
|
|
{ |
270
|
|
|
if (in_array($delimiter, $this->getWordDelimiters())) { |
271
|
|
|
throw new Exception\RuntimeException("Word delimiter '$delimiter' is already there."); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
if (empty($delimiter)) { |
275
|
|
|
throw new Exception\RuntimeException('Word delimiter cannot be null.'); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
if (is_array($delimiter)) { |
279
|
|
|
$this->wordDelimiters = array_merge($this->getWordDelimiters(), $delimiter); |
280
|
|
|
} else { |
281
|
|
|
$this->wordDelimiters[] = $delimiter; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
return $this; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Remove word delimiter |
289
|
|
|
* |
290
|
|
|
* @param string|array $delimiters |
291
|
|
|
* @return $this |
292
|
|
|
* @throws Exception\RuntimeException |
293
|
|
|
*/ |
294
|
|
View Code Duplication |
public function removeWordDelimiter($delimiters) |
|
|
|
|
295
|
|
|
{ |
296
|
|
|
if (empty($delimiters)) { |
297
|
|
|
throw new Exception\RuntimeException('Word delimiter cannot be null.'); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
if (is_array($delimiters)) { |
301
|
|
|
foreach ($delimiters as $delimiter) { |
302
|
|
|
$this->removeWordDelimiter($delimiter); |
303
|
|
|
} |
304
|
|
|
} else { |
305
|
|
|
if (!in_array($delimiters, $this->getWordDelimiters())) { |
306
|
|
|
throw new Exception\RuntimeException("Word delimiter '$delimiters' is not in delimiters array."); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
$wordDelimiters = []; |
310
|
|
|
foreach ($this->wordDelimiters as $delimiter) { |
311
|
|
|
if ($delimiter != $delimiters) { |
312
|
|
|
$wordDelimiters[] = $delimiter; |
313
|
|
|
} |
314
|
|
|
$this->wordDelimiters = $wordDelimiters; |
315
|
|
|
} |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
return $this; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* Replace delimiters with another string |
323
|
|
|
* |
324
|
|
|
* @param string $s |
325
|
|
|
* @return string |
326
|
|
|
*/ |
327
|
|
|
private function replaceDelimiters($s) |
328
|
|
|
{ |
329
|
|
|
foreach ($this->getWordDelimiters() as $delimiter) { |
330
|
|
|
|
331
|
|
|
if ($delimiter == $this->getDelimiterReplacement()) { |
332
|
|
|
continue; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
if (in_array($delimiter, $this->getNotReplacedChars())) { |
336
|
|
|
continue; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
$s = str_replace($delimiter, $this->getDelimiterReplacement(), $s); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
return $s; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* To special chars |
347
|
|
|
* |
348
|
|
|
* @param string $s |
349
|
|
|
* @return string |
350
|
|
|
*/ |
351
|
|
|
private function trimSpecialsChars($s) |
352
|
|
|
{ |
353
|
|
|
if (count($this->getNotReplacedChars()) == 0) { |
354
|
|
|
$reg = '~[^-a-z0-9_]+~'; |
355
|
|
|
} else { |
356
|
|
|
$reg = '~[^-a-z0-9_' . implode('', $this->getNotReplacedChars()) . ']+~'; |
357
|
|
|
} |
358
|
|
|
return preg_replace($reg, '', $s); |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* Replace double delimiter with single one |
363
|
|
|
* |
364
|
|
|
* @param string $s |
365
|
|
|
* @return string |
366
|
|
|
*/ |
367
|
|
|
private function replaceDoubleDelimiterReplacementWithSingle($s) |
368
|
|
|
{ |
369
|
|
|
$doubleDelimiterReplacement = $this->getDelimiterReplacement() . $this->getDelimiterReplacement(); |
370
|
|
|
while (strpos($s, $doubleDelimiterReplacement) !== false) { |
371
|
|
|
$s = str_replace($doubleDelimiterReplacement, $this->getDelimiterReplacement(), $s); |
372
|
|
|
} |
373
|
|
|
return $s; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Trim dashes on beginning/end of the string |
378
|
|
|
* |
379
|
|
|
* @param string $s |
380
|
|
|
* @return string |
381
|
|
|
*/ |
382
|
|
|
private function trimStartAndEndSpaceReplacement($s) |
383
|
|
|
{ |
384
|
|
|
return trim($s, $this->getDelimiterReplacement()); |
385
|
|
|
} |
386
|
|
|
} |
387
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.