1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Copyright (c) STMicroelectronics, 2007. All Rights Reserved. |
4
|
|
|
* |
5
|
|
|
* Originally written by Manuel VACELET, 2007. |
6
|
|
|
* |
7
|
|
|
* This file is a part of Codendi. |
8
|
|
|
* |
9
|
|
|
* Codendi is free software; you can redistribute it and/or modify |
10
|
|
|
* it under the terms of the GNU General Public License as published by |
11
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
12
|
|
|
* (at your option) any later version. |
13
|
|
|
* |
14
|
|
|
* Codendi is distributed in the hope that it will be useful, |
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17
|
|
|
* GNU General Public License for more details. |
18
|
|
|
* |
19
|
|
|
* You should have received a copy of the GNU General Public License |
20
|
|
|
* along with Codendi. If not, see <http://www.gnu.org/licenses/>. |
21
|
|
|
*/ |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @package Codendi |
25
|
|
|
*/ |
26
|
|
|
abstract class Rule { |
27
|
|
|
/** |
28
|
|
|
* @access private |
29
|
|
|
*/ |
30
|
|
|
var $error; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Constructor |
34
|
|
|
*/ |
35
|
|
|
public function __construct() { |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Check if $val is a valid not. |
40
|
|
|
* |
41
|
|
|
* @param String $val Value to check. |
42
|
|
|
* @return Boolean |
43
|
|
|
*/ |
44
|
|
|
abstract function isValid($val); |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Default error message if rule is not apply on value. |
48
|
|
|
* |
49
|
|
|
* @param String $val Value to check. |
|
|
|
|
50
|
|
|
* @return Boolean |
51
|
|
|
*/ |
52
|
|
|
function getErrorMessage($key='') { |
53
|
|
|
return $this->error; |
54
|
|
|
} |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Validate date provided by Codendi calendar. |
59
|
|
|
* |
60
|
|
|
* Note: this date format is more restrictive than php check date because in |
61
|
|
|
* this case, 2007-01-01 format (with zero in month or day) is not allowed. |
62
|
|
|
*/ |
63
|
|
|
class Rule_Date extends Rule { |
64
|
|
|
const DAY_REGEX = '/^(\d{1,4})-(\d{1,2})-(\d{1,2}?)$/'; |
65
|
|
|
|
66
|
|
|
function isValid($val) { |
67
|
|
|
if (preg_match(self::DAY_REGEX, $val, $m)) { |
68
|
|
|
return checkdate($m[2], $m[3], $m[1]); |
69
|
|
|
} else { |
70
|
|
|
return false; |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
class Rule_Date_Time extends Rule { |
76
|
|
|
const DAYTIME_REGEX = '/^(\d{1,4})-(\d{1,2})-(\d{1,2}?) (\d{2}):(\d{2})(?::\d{2})?$/'; |
77
|
|
|
|
78
|
|
|
function isValid($val) { |
79
|
|
|
if (! preg_match(self::DAYTIME_REGEX, $val, $m)) { |
80
|
|
|
return false; |
81
|
|
|
} |
82
|
|
|
return (bool)strtotime($val); |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
class Rule_Timestamp extends Rule { |
87
|
|
|
const TIMESTAMP_REGEX = '/^[0-9]+$/'; |
88
|
|
|
|
89
|
|
|
function isValid($val) { |
90
|
|
|
return preg_match(self::TIMESTAMP_REGEX, $val); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Abstract class that define left-hand operand for a comparison. |
96
|
|
|
*/ |
97
|
|
|
abstract class Rule_Comparator |
98
|
|
|
extends Rule { |
99
|
|
|
/** |
100
|
|
|
* @access private |
101
|
|
|
*/ |
102
|
|
|
var $ref; |
103
|
|
|
function Rule_Comparator($ref) { |
104
|
|
|
$this->ref = $ref; |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Check that given value is strictly greater than the one defined in |
110
|
|
|
* constructor. |
111
|
|
|
*/ |
112
|
|
|
class Rule_GreaterThan |
113
|
|
|
extends Rule_Comparator { |
114
|
|
|
function isValid($val) { |
115
|
|
|
if(is_numeric($val) && $val > $this->ref) { |
116
|
|
|
return true; |
117
|
|
|
} |
118
|
|
|
return false; |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Check that given value is strictly less than the one defined in constructor. |
124
|
|
|
*/ |
125
|
|
|
class Rule_LessThan |
126
|
|
|
extends Rule_Comparator { |
127
|
|
|
function isValid($val) { |
128
|
|
|
if(is_numeric($val) && $val < $this->ref) { |
129
|
|
|
return true; |
130
|
|
|
} |
131
|
|
|
return false; |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Check that given value is greater or equal to the one defined in |
137
|
|
|
* constructor. |
138
|
|
|
*/ |
139
|
|
|
class Rule_GreaterOrEqual |
140
|
|
|
extends Rule_Comparator { |
141
|
|
|
function isValid($val) { |
142
|
|
|
if(is_numeric($val) && $val >= $this->ref) { |
143
|
|
|
return true; |
144
|
|
|
} |
145
|
|
|
return false; |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Check that given value is strictly less or equal to the one defined in |
151
|
|
|
* constructor. |
152
|
|
|
*/ |
153
|
|
|
class Rule_lessOrEqual |
154
|
|
|
extends Rule_Comparator { |
155
|
|
|
function isValid($val) { |
156
|
|
|
if(is_numeric($val) && $val <= $this->ref) { |
157
|
|
|
return true; |
158
|
|
|
} |
159
|
|
|
return false; |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Check that given value belong to the array defined in constructor. |
165
|
|
|
* |
166
|
|
|
* There is no type check. |
167
|
|
|
*/ |
168
|
|
|
class Rule_WhiteList |
169
|
|
|
extends Rule_Comparator { |
170
|
|
|
function isValid($val) { |
171
|
|
|
if(is_array($this->ref) |
172
|
|
|
&& count($this->ref) > 0 |
173
|
|
|
&& in_array($val, $this->ref)) { |
174
|
|
|
return true; |
175
|
|
|
} |
176
|
|
|
return false; |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Check that given value is a valid signed 32 bits decimal integer. |
182
|
|
|
*/ |
183
|
|
|
class Rule_Int |
184
|
|
|
extends Rule { |
185
|
|
|
/** |
186
|
|
|
* Check the format according to PHP definition of a decimal integer. |
187
|
|
|
* @see http://php.net/int |
188
|
|
|
* @access private |
189
|
|
|
*/ |
190
|
|
|
function checkFormat($val) { |
191
|
|
|
if(preg_match('/^([+-]?[1-9][0-9]*|[+-]?0)$/', $val)) { |
192
|
|
|
return true; |
193
|
|
|
} else { |
194
|
|
|
return false; |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
function isValid($val) { |
199
|
|
|
// Need to check with the regexp because of octal form '0123' that is |
200
|
|
|
// equal to '123' with string '==' comparison. |
201
|
|
|
if($this->checkFormat($val)) { |
202
|
|
|
// Check (-2^31;2^31-1) range |
203
|
|
|
if(strval(intval($val)) == $val) { |
204
|
|
|
return true; |
205
|
|
|
} else { |
206
|
|
|
return false; |
207
|
|
|
} |
208
|
|
|
} else { |
209
|
|
|
return false; |
210
|
|
|
} |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Check that given value is a string. |
216
|
|
|
*/ |
217
|
|
|
class Rule_String |
218
|
|
|
extends Rule { |
219
|
|
|
function isValid($val) { |
220
|
|
|
return is_string($val); |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Check that given value is an array. |
226
|
|
|
*/ |
227
|
|
|
class Rule_Array |
228
|
|
|
extends Rule { |
229
|
|
|
function isValid($val) { |
230
|
|
|
return is_array($val); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Check if given string contains neither a carrige return nor a null char. |
236
|
|
|
*/ |
237
|
|
|
class Rule_NoCr |
238
|
|
|
extends Rule { |
239
|
|
|
function isValid($val) { |
240
|
|
|
if(is_string($val) && strpos($val, 0x0A) === false && strpos($val, 0x0D) === false |
241
|
|
|
&& strpos($val, 0x00) === false) { |
242
|
|
|
return true; |
243
|
|
|
} |
244
|
|
|
return false; |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* Check if given string match a pattern |
250
|
|
|
*/ |
251
|
|
|
class Rule_Regexp extends Rule { |
252
|
|
|
protected $pattern; |
253
|
|
|
|
254
|
|
|
public function __construct($pattern) { |
255
|
|
|
parent::__construct(); |
256
|
|
|
$this->pattern = $pattern; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
function isValid($val) { |
260
|
|
|
return preg_match($this->pattern, $val); |
261
|
|
|
} |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Check if an email address is valid or not in Codendi context. |
266
|
|
|
* |
267
|
|
|
* This rule is influenced by a global variable 'sys_disable_subdomain'. If |
268
|
|
|
* this variable is set (no subdomain for codendi) and only in this case, emails |
269
|
|
|
* like 'user@codendi' are allowed. |
270
|
|
|
* |
271
|
|
|
* The faulty email address is available with $this->getErrorMessage(); |
272
|
|
|
*/ |
273
|
|
|
class Rule_Email |
274
|
|
|
extends Rule { |
275
|
|
|
var $separator; |
276
|
|
|
|
277
|
|
|
function Rule_Email($separator = null) { |
278
|
|
|
$this->separator = $separator; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
function isValid($val) { |
282
|
|
|
if($this->separator !== null) { |
283
|
|
|
// If separator is defined, split the string and check each email. |
284
|
|
|
$emails = split($this->separator, $val); |
285
|
|
|
$valid = true; |
286
|
|
|
while((list($key,$email) = each($emails)) && $valid) { |
287
|
|
|
$valid = $valid & $this->validEmail(trim(rtrim($email))); |
288
|
|
|
} |
289
|
|
|
} else { |
290
|
|
|
// $val must contains only one email address |
291
|
|
|
$valid = $this->validEmail($val); |
292
|
|
|
} |
293
|
|
|
return $valid; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* Check email validity |
298
|
|
|
* |
299
|
|
|
* Important note: this is very important to keep the 'D' regexp modifier |
300
|
|
|
* as this is the only way not to be bothered by injections of \n into the |
301
|
|
|
* email address. |
302
|
|
|
* |
303
|
|
|
* Spaces are allowed at the beginning and the end of the address. |
304
|
|
|
*/ |
305
|
|
|
function validEmail($email) { |
306
|
|
|
$valid_chars='-!#$%&\'*+0-9=?A-Z^_`a-z{|}~\.'; |
307
|
|
|
if (array_key_exists('sys_disable_subdomains', $GLOBALS) |
308
|
|
|
&& $GLOBALS['sys_disable_subdomains']) { |
309
|
|
|
$valid_domain='['.$valid_chars.']+'; |
310
|
|
|
} else { |
311
|
|
|
$valid_domain='['.$valid_chars.']+\.['.$valid_chars.']+'; |
312
|
|
|
} |
313
|
|
|
$regexp = '/^['.$valid_chars.']+'.'@'.$valid_domain.'$/D'; |
314
|
|
|
return preg_match($regexp, $email); |
315
|
|
|
} |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Check if value match Codendi user names format. |
321
|
|
|
* |
322
|
|
|
* This rule doesn't check that user actually exists. |
323
|
|
|
*/ |
324
|
|
|
class Rule_UserName |
325
|
|
|
extends Rule { |
326
|
|
|
|
327
|
|
|
const RESERVED_PREFIX = 'forge__'; |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* Test if value is a name on underlying OS. |
331
|
|
|
* |
332
|
|
|
* @param String $val Value to test |
333
|
|
|
* |
334
|
|
|
* @return Boolean |
335
|
|
|
*/ |
336
|
|
|
public function isSystemName($val) { |
337
|
|
|
$backend = $this->_getBackend(); |
338
|
|
|
if ($backend->unixUserExists($val) || $backend->unixGroupExists($val)) { |
339
|
|
|
$this->error = $this->_getErrorExists(); |
340
|
|
|
return true; |
341
|
|
|
} |
342
|
|
|
return false; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Test is the value is Codendi username |
347
|
|
|
* |
348
|
|
|
* @param String $val Value to test |
349
|
|
|
* |
350
|
|
|
* @return Boolean |
351
|
|
|
*/ |
352
|
|
|
public function isAlreadyUserName($val) { |
353
|
|
|
$um = $this->_getUserManager(); |
354
|
|
|
if ($um->getUserByUserName($val) !== null) { |
355
|
|
|
$this->error = $this->_getErrorExists(); |
356
|
|
|
return true; |
357
|
|
|
} |
358
|
|
|
return false; |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* Test if the value is a project name |
363
|
|
|
* |
364
|
|
|
* @param String $val Value to test |
365
|
|
|
* |
366
|
|
|
* @return Boolean |
367
|
|
|
*/ |
368
|
|
|
public function isAlreadyProjectName($val) { |
369
|
|
|
$pm = $this->_getProjectManager(); |
370
|
|
|
if ($pm->getProjectByUnixName($val) !== null) { |
371
|
|
|
$this->error = $this->_getErrorExists(); |
372
|
|
|
return true; |
373
|
|
|
} |
374
|
|
|
return false; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Test if the value contains spaces |
379
|
|
|
* |
380
|
|
|
* @param String $val Value to test |
381
|
|
|
* |
382
|
|
|
* @return Boolean |
383
|
|
|
*/ |
384
|
|
|
public function noSpaces($val) { |
385
|
|
|
if (strrpos($val,' ') !== false) { |
386
|
|
|
$this->error = $this->_getErrorNoSpaces(); |
387
|
|
|
return false; |
388
|
|
|
} |
389
|
|
|
return true; |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* Needs to check the name start by a char |
394
|
|
|
* |
395
|
|
|
* @param String $val |
396
|
|
|
* |
397
|
|
|
* @return Boolean |
398
|
|
|
*/ |
399
|
|
|
public function atLeastOneChar($val) { |
400
|
|
|
if (strspn($val,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == 0) { |
401
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','char_err'); |
402
|
|
|
return false; |
403
|
|
|
} |
404
|
|
|
return true; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Test if the name contains illegal chars |
409
|
|
|
* |
410
|
|
|
* @param String $val Value to test |
411
|
|
|
* |
412
|
|
|
* @return Boolean |
413
|
|
|
*/ |
414
|
|
|
public function containsIllegalChars($val) { |
415
|
|
|
if (strspn($val,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.") != strlen($val)) { |
416
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','illegal_char'); |
417
|
|
|
return true; |
418
|
|
|
} |
419
|
|
|
return false; |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* Test if the name is already reserved |
424
|
|
|
* |
425
|
|
|
* @param String $val Value to test |
426
|
|
|
* |
427
|
|
|
* @return Boolean |
428
|
|
|
*/ |
429
|
|
|
public function isReservedName($val) { |
430
|
|
|
$is_reserved_name = preg_match('/^('. |
431
|
|
|
'(www[0-9]?)|(cvs[0-9]?)|(shell[0-9]?)|(ftp[0-9]?)|(irc[0-9]?)|(news[0-9]?)'. |
432
|
|
|
'|(mail[0-9]?)|(ns[0-9]?)|(download[0-9]?)|(pub)|(users)|(compile)|(lists)'. |
433
|
|
|
'|(slayer)|(orbital)|(tokyojoe)|(webdev)|(projects)|(cvs)|(monitor)|(mirrors?)'. |
434
|
|
|
'|(root)|(bin)|(daemon)|(adm)|(lp)|(sync)|(shutdown)|(halt)|(mail)'. |
435
|
|
|
'|(uucp)|(operator)|(games)|(mysql)|(httpd)|(nobody)|(dummy)|(debian)'. |
436
|
|
|
'|(munin)|(mailman)|(ftpadmin)|(codendiadm)|(imadmin-bot)|(apache)|(nscd)'. |
437
|
|
|
'|(git)|(gitolite)'. |
438
|
|
|
')$/i', $val); |
439
|
|
|
$is_reserved_prefix = $this->isReservedPrefix($val); |
440
|
|
|
|
441
|
|
|
if ($is_reserved_name || $is_reserved_prefix) { |
442
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','reserved'); |
443
|
|
|
return true; |
444
|
|
|
} |
445
|
|
|
return false; |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
/** |
449
|
|
|
* Test if the name begins with a reserved prefix |
450
|
|
|
* |
451
|
|
|
* @param string $val Value to test |
452
|
|
|
* |
453
|
|
|
* @return bool |
454
|
|
|
*/ |
455
|
|
|
private function isReservedPrefix($val) { |
456
|
|
|
if (strpos($val, self::RESERVED_PREFIX) === 0) { |
457
|
|
|
return true; |
458
|
|
|
} |
459
|
|
|
return false; |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Test if the name corresponds to a CVS user account |
464
|
|
|
* |
465
|
|
|
* @param String $val Value to test |
466
|
|
|
* |
467
|
|
|
* @return Boolean |
468
|
|
|
*/ |
469
|
|
|
public function isCvsAccount($val) { |
470
|
|
|
if (preg_match('/^anoncvs_/i', $val)) { |
471
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','reserved_cvs'); |
472
|
|
|
return true; |
473
|
|
|
} |
474
|
|
|
return false; |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
/** |
478
|
|
|
* Test minimal length of name |
479
|
|
|
* |
480
|
|
|
* @param String $val Value to test |
481
|
|
|
* |
482
|
|
|
* @return Boolean |
483
|
|
|
*/ |
484
|
|
|
public function lessThanMin($val) { |
485
|
|
|
if (strlen($val) < 3) { |
486
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','name_too_short'); |
487
|
|
|
return true; |
488
|
|
|
} |
489
|
|
|
return false; |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* Test maximal length of name |
494
|
|
|
* |
495
|
|
|
* @param String $val Value to test |
496
|
|
|
* @param Integer $max maximal length (default = 30) |
497
|
|
|
* |
498
|
|
|
* @return Boolean |
499
|
|
|
*/ |
500
|
|
|
public function greaterThanMax($val, $max = 30) { |
501
|
|
|
if (strlen($val) > $max) { |
502
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','name_too_long', $max); |
503
|
|
|
return true; |
504
|
|
|
} |
505
|
|
|
return false; |
506
|
|
|
} |
507
|
|
|
/** |
508
|
|
|
* Prevent from renaming two users on the same name |
509
|
|
|
* before that the rename is performed by the system |
510
|
|
|
* |
511
|
|
|
* @param String $val |
512
|
|
|
*/ |
513
|
|
|
public function getPendingUserRename($val) { |
514
|
|
|
$sm = $this->_getSystemEventManager(); |
515
|
|
|
if (!$sm->isUserNameAvailable($val)) { |
516
|
|
|
$this->error = $GLOBALS['Language']->getText('rule_user_name', 'error_event_reserved', array($val)); |
517
|
|
|
return false; |
518
|
|
|
} |
519
|
|
|
return true; |
520
|
|
|
} |
521
|
|
|
/** |
522
|
|
|
* Test if name is valid |
523
|
|
|
* |
524
|
|
|
* @param String $val Value to test |
525
|
|
|
* |
526
|
|
|
* @return Boolean |
527
|
|
|
*/ |
528
|
|
|
public function isValid($val) { |
529
|
|
|
return $this->noSpaces($val) |
530
|
|
|
&& $this->atLeastOneChar($val) |
531
|
|
|
&& !$this->isReservedName($val) |
532
|
|
|
&& !$this->isCvsAccount($val) |
533
|
|
|
&& !$this->lessThanMin($val) |
534
|
|
|
&& !$this->greaterThanMax($val) |
535
|
|
|
&& !$this->containsIllegalChars($val) |
536
|
|
|
&& !$this->isAlreadyUserName($val) |
537
|
|
|
&& !$this->isAlreadyProjectName($val) |
538
|
|
|
&& !$this->isSystemName($val) |
539
|
|
|
&& $this->getPendingUserRename($val); |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
/** |
543
|
|
|
* Error message |
544
|
|
|
* |
545
|
|
|
* @return String |
546
|
|
|
*/ |
547
|
|
|
public function getErrorMessage() { |
548
|
|
|
return $this->error; |
549
|
|
|
} |
550
|
|
|
|
551
|
|
|
/** |
552
|
|
|
* Returns error message when the username already exists |
553
|
|
|
* |
554
|
|
|
* Dedicate a method to be able to override it in descendent classes |
555
|
|
|
* |
556
|
|
|
* @param String $val Value to test |
|
|
|
|
557
|
|
|
* |
558
|
|
|
* @return Boolean |
559
|
|
|
*/ |
560
|
|
|
protected function _getErrorExists() { |
561
|
|
|
return $GLOBALS['Language']->getText('rule_user_name', 'error_exists'); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Returns error message when name contains a space |
566
|
|
|
* |
567
|
|
|
* Dedicate a method to be able to override it in descendent classes |
568
|
|
|
* |
569
|
|
|
* @param String $val Value to test |
|
|
|
|
570
|
|
|
* |
571
|
|
|
* @return Boolean |
572
|
|
|
*/ |
573
|
|
|
protected function _getErrorNoSpaces() { |
574
|
|
|
return $GLOBALS['Language']->getText('include_account', 'login_err'); |
575
|
|
|
} |
576
|
|
|
|
577
|
|
|
/** |
578
|
|
|
* Wrapper |
579
|
|
|
* |
580
|
|
|
* @return ProjectManager |
581
|
|
|
*/ |
582
|
|
|
protected function _getProjectManager() { |
583
|
|
|
return ProjectManager::instance(); |
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
/** |
587
|
|
|
* Wrapper |
588
|
|
|
* |
589
|
|
|
* @return UserManager |
590
|
|
|
*/ |
591
|
|
|
protected function _getUserManager() { |
592
|
|
|
return UserManager::instance(); |
593
|
|
|
} |
594
|
|
|
|
595
|
|
|
/** |
596
|
|
|
* Wrapper |
597
|
|
|
* |
598
|
|
|
* @return Backend |
599
|
|
|
*/ |
600
|
|
|
protected function _getBackend($type='') { |
601
|
|
|
return Backend::instance($type); |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
/** |
605
|
|
|
* Wrapper |
606
|
|
|
* |
607
|
|
|
* @return SystemEventManager |
608
|
|
|
*/ |
609
|
|
|
protected function _getSystemEventManager() { |
610
|
|
|
return SystemEventManager::instance(); |
611
|
|
|
} |
612
|
|
|
} |
613
|
|
|
|
614
|
|
|
/** |
615
|
|
|
* Check if a project name is valid |
616
|
|
|
* |
617
|
|
|
* This extends the user name validation |
618
|
|
|
*/ |
619
|
|
|
class Rule_ProjectName |
620
|
|
|
extends Rule_UserName { |
621
|
|
|
|
622
|
|
|
/** |
623
|
|
|
* Group name cannot contain underscore or dots for DNS reasons. |
624
|
|
|
* |
625
|
|
|
* @param String $val |
626
|
|
|
* |
627
|
|
|
* @return Boolean |
628
|
|
|
*/ |
629
|
|
|
public function isDNSCompliant($val) { |
630
|
|
|
if (strpos($val, '_') === false && strpos($val, '.') === false) { |
631
|
|
|
return true; |
632
|
|
|
} |
633
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','dns_error'); |
634
|
|
|
return false; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
/** |
638
|
|
|
* Verify group name availability in the FS |
639
|
|
|
* |
640
|
|
|
* @param String $val |
641
|
|
|
* |
642
|
|
|
* @return Boolean |
643
|
|
|
*/ |
644
|
|
|
public function isNameAvailable($val) { |
645
|
|
|
|
646
|
|
|
$backendSVN = $this->_getBackend('SVN'); |
647
|
|
|
if (!$backendSVN->isNameAvailable($val)){ |
648
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','used_by_svn'); |
649
|
|
|
return false; |
650
|
|
|
} else { |
651
|
|
|
$backendCVS = $this->_getBackend('CVS'); |
652
|
|
|
if (!$backendCVS->isNameAvailable($val)) { |
653
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','used_by_cvs'); |
654
|
|
|
return false; |
655
|
|
|
} else { |
656
|
|
|
$backendSystem = $this->_getBackend('System'); |
657
|
|
|
if (!$backendSystem->isProjectNameAvailable($val)){ |
658
|
|
|
$this->error = $GLOBALS['Language']->getText('include_account','used_by_sys'); |
659
|
|
|
return false; |
660
|
|
|
} else { |
661
|
|
|
$result = true; |
662
|
|
|
// Add Hook for plugins to check the name validity under plugins directories |
663
|
|
|
$this->getEventManager()->processEvent('file_exists_in_data_dir', |
664
|
|
|
array('new_name' => $val, |
665
|
|
|
'result' => &$result, |
666
|
|
|
'error' => &$error) |
|
|
|
|
667
|
|
|
|
668
|
|
|
); |
669
|
|
|
if ($result == false){ |
|
|
|
|
670
|
|
|
$this->error = $error; |
671
|
|
|
return false; |
672
|
|
|
} |
673
|
|
|
} |
674
|
|
|
} |
675
|
|
|
} |
676
|
|
|
return true; |
677
|
|
|
} |
678
|
|
|
|
679
|
|
|
/** |
680
|
|
|
* Prevent from renaming two projects on the same name |
681
|
|
|
* before that the rename is performed by the system |
682
|
|
|
* |
683
|
|
|
* @param String $val |
684
|
|
|
*/ |
685
|
|
|
public function getPendingProjectRename($val) { |
686
|
|
|
$sm = $this->_getSystemEventManager(); |
687
|
|
|
if (!$sm->isProjectNameAvailable($val)) { |
688
|
|
|
$this->error = $GLOBALS['Language']->getText('rule_user_name', 'error_event_reserved', array($val)); |
689
|
|
|
return false; |
690
|
|
|
} |
691
|
|
|
return true; |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
|
695
|
|
|
/** |
696
|
|
|
* Wrapper for event manager |
697
|
|
|
* |
698
|
|
|
* @return EventManager |
699
|
|
|
*/ |
700
|
|
|
protected function getEventManager() { |
701
|
|
|
return EventManager::instance(); |
702
|
|
|
} |
703
|
|
|
/** |
704
|
|
|
* Check validity |
705
|
|
|
* |
706
|
|
|
* @param String $val |
707
|
|
|
* |
708
|
|
|
* @return Boolean |
709
|
|
|
*/ |
710
|
|
|
public function isValid($val) { |
711
|
|
|
return $this->isDNSCompliant($val) && parent::isValid($val) && $this->isNameAvailable($val) |
712
|
|
|
&& $this->getPendingProjectRename($val); |
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
protected function _getErrorExists() { |
716
|
|
|
return $GLOBALS['Language']->getText('rule_group_name', 'error_exists'); |
717
|
|
|
} |
718
|
|
|
|
719
|
|
|
protected function _getErrorNoSpaces() { |
720
|
|
|
return $GLOBALS['Language']->getText('include_account', 'project_spaces'); |
721
|
|
|
} |
722
|
|
|
} |
723
|
|
|
|
724
|
|
|
/** |
725
|
|
|
* Check if a project full name is valid |
726
|
|
|
* |
727
|
|
|
* This extends the user name validation |
728
|
|
|
*/ |
729
|
|
|
class Rule_ProjectFullName extends Rule_UserName { |
730
|
|
|
|
731
|
|
|
/** |
732
|
|
|
* Check validity |
733
|
|
|
* |
734
|
|
|
* @param String $val |
735
|
|
|
* |
736
|
|
|
* @return Boolean |
737
|
|
|
*/ |
738
|
|
|
public function isValid($val) { |
739
|
|
|
$val = trim($val); |
740
|
|
|
return !$this->lessThanMin($val) && !$this->greaterThanMax($val, 40); |
741
|
|
|
} |
742
|
|
|
|
743
|
|
|
/** |
744
|
|
|
* Error message |
745
|
|
|
* |
746
|
|
|
* @return String |
747
|
|
|
*/ |
748
|
|
|
public function getErrorMessage() { |
749
|
|
|
return $this->error; |
750
|
|
|
} |
751
|
|
|
|
752
|
|
|
} |
753
|
|
|
|
754
|
|
|
/** |
755
|
|
|
* Check that file was correctly uploaded doesn't by pass Codendi limits. |
756
|
|
|
* |
757
|
|
|
* Tests mainly rely on PHP $_FILES error code but add a double check of file |
758
|
|
|
* size because MAX_FILE_SIZE (used by PHP to check allowed size) is submitted |
759
|
|
|
* by the client. |
760
|
|
|
* |
761
|
|
|
* By default the maxSize is defined by 'sys_max_size_upload' Codendi |
762
|
|
|
* variable but may be customized with setMaxSize. |
763
|
|
|
*/ |
764
|
|
|
require_once("www/file/file_utils.php"); // Needed for 2 GB workaround |
765
|
|
|
class Rule_File |
766
|
|
|
extends Rule { |
767
|
|
|
var $maxSize; |
768
|
|
|
var $i18nPageName; |
769
|
|
|
|
770
|
|
|
function Rule_File() { |
771
|
|
|
$this->maxSize = $GLOBALS['sys_max_size_upload']; |
772
|
|
|
$this->i18nPageName = 'rule_file'; |
773
|
|
|
} |
774
|
|
|
|
775
|
|
|
function setMaxSize($max) { |
776
|
|
|
$this->maxSize = $max; |
777
|
|
|
} |
778
|
|
|
|
779
|
|
|
function geti18nError($key, $params="") { |
780
|
|
|
return $GLOBALS['Language']->getText($this->i18nPageName, $key, $params); |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
/** |
784
|
|
|
* Check file upload validity |
785
|
|
|
* |
786
|
|
|
* @param Array One entry in $_FILES superarray (e.g. $_FILES['test']) |
787
|
|
|
* @return Boolean Is file upload valid or not. |
788
|
|
|
*/ |
789
|
|
|
function isValid($file) { |
790
|
|
|
$ok = false; |
791
|
|
|
if(is_array($file)) { |
792
|
|
|
switch($file['error']) { |
793
|
|
|
case UPLOAD_ERR_OK: |
794
|
|
|
// all is OK |
795
|
|
|
$ok = true; |
796
|
|
|
break; |
797
|
|
|
case UPLOAD_ERR_INI_SIZE: |
798
|
|
|
case UPLOAD_ERR_FORM_SIZE: |
799
|
|
|
$this->error = $this->geti18nError('error_upload_size', $file['error']); |
800
|
|
|
break; |
801
|
|
|
case UPLOAD_ERR_PARTIAL: |
802
|
|
|
$this->error = $this->geti18nError('error_upload_partial', $file['error']); |
803
|
|
|
break; |
804
|
|
|
case UPLOAD_ERR_NO_FILE: |
805
|
|
|
$this->error = $this->geti18nError('error_upload_nofile', $file['error']); |
806
|
|
|
break; |
807
|
|
|
//case UPLOAD_ERR_NO_TMP_DIR: PHP 5.0.3 |
808
|
|
|
//case UPLOAD_ERR_CANT_WRITE: PHP 5.1.0 |
809
|
|
|
//case UPLOAD_ERR_EXTENSION: PHP 5.2.0 |
810
|
|
|
default: |
811
|
|
|
$this->error = $this->geti18nError('error_upload_unknown', $file['error']); |
812
|
|
|
} |
813
|
|
|
if($ok && $file['name'] == '') { |
814
|
|
|
$ok = false; |
815
|
|
|
$this->error = $this->geti18nError('error_upload'); |
816
|
|
|
} |
817
|
|
|
if($ok) { |
818
|
|
|
// Re-check filesize (do not trust uploaded MAX_FILE_SIZE) |
819
|
|
|
if(file_utils_get_size($file['tmp_name']) > $this->maxSize) { |
820
|
|
|
$ok = false; |
821
|
|
|
$this->error = $this->geti18nError('error_upload_size', 1); |
822
|
|
|
} |
823
|
|
|
} |
824
|
|
|
} |
825
|
|
|
return $ok; |
826
|
|
|
} |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
class Rule_FRSFileName |
830
|
|
|
extends Rule { |
831
|
|
|
function isValid($val) { |
832
|
|
|
if (preg_match("/[]`!\"$%^,&*();=|[{}<>?\/]/", $val)) { |
833
|
|
|
return false; |
834
|
|
|
} |
835
|
|
|
if (strpos($val, '@') === 0) { // Starts with at sign |
836
|
|
|
return false; |
837
|
|
|
} |
838
|
|
|
if (strpos($val, '~') === 0) { // Starts with at sign |
839
|
|
|
return false; |
840
|
|
|
} |
841
|
|
|
if (strstr($val,'..')) { |
842
|
|
|
return false; |
843
|
|
|
} else { |
844
|
|
|
return true; |
845
|
|
|
} |
846
|
|
|
} |
847
|
|
|
} |
848
|
|
|
|
849
|
|
|
class Rule_RealName extends Rule { |
850
|
|
|
|
851
|
|
|
public function isValid($string) { |
852
|
|
|
if ($this->containsBackslashCharacter($string) || $this->containsNonPrintingCharacter($string)) { |
853
|
|
|
return false; |
854
|
|
|
} |
855
|
|
|
return true; |
856
|
|
|
} |
857
|
|
|
|
858
|
|
|
private function containsBackslashCharacter($string) { |
859
|
|
|
return strpos($string, "\\") !== false; |
860
|
|
|
} |
861
|
|
|
|
862
|
|
|
private function containsNonPrintingCharacter($string) { |
863
|
|
|
for ($i = 0; $i < strlen($string); $i++) { |
864
|
|
|
if ($this->isNonPrintingCharacter($string[$i])) { |
865
|
|
|
return true; |
866
|
|
|
} |
867
|
|
|
} |
868
|
|
|
return false; |
869
|
|
|
} |
870
|
|
|
|
871
|
|
|
private function isNonPrintingCharacter($char) { |
872
|
|
|
return hexdec(bin2hex($char)) < 32; |
873
|
|
|
} |
874
|
|
|
} |
875
|
|
|
|
876
|
|
|
?> |
877
|
|
|
|
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.