ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
LangCheck Class Reference

Class LangCheck. More...

+ Collaboration diagram for LangCheck:

Public Member Functions

 __construct ($file)
 LangCheck constructor. More...
 
 runChecks ()
 Run all the checks on the file. More...
 
 getIssues ()
 Get all found issues as (severity, message) tuple. More...
 
 getIssuesAsString ()
 Get all found issues as formatted list. More...
 
 strtolower (&$value)
 

Data Fields

const TYPE_NOTICE = 1
 
const TYPE_WARNING = 2
 
const TYPE_ERROR = 3
 
const TYPE_FATAL = 4
 

Protected Member Functions

 loadFile ()
 Load the file content. More...
 
 checkGeneral ()
 Check some general file properties. More...
 
 checkComment ()
 Check that the needed information is in the initial file comment. More...
 
 loadLanguageData ()
 Load the language data. More...
 
 ensureKeyType ($name, $type='array', $optional=false)
 Check that the given key exists and has the correct type. More...
 
 checkMainKeys ()
 Check the major keys in the language array. More...
 
 checkKeyContents ()
 Check the keywords are sane. More...
 
 issue ($type, $msg)
 log an issue More...
 

Protected Attributes

 $issues = array()
 
 $file
 
 $content
 
 $langdata
 
 $severityNames
 

Detailed Description

Class LangCheck.

Runs sanity checks on the given language file

Definition at line 9 of file LangCheck.php.

Constructor & Destructor Documentation

◆ __construct()

LangCheck::__construct (   $file)

LangCheck constructor.

Parameters
string$filethe file to check

Definition at line 42 of file LangCheck.php.

43 {
44 $this->file = $file;
45 }

References $file.

Member Function Documentation

◆ checkComment()

LangCheck::checkComment ( )
protected

Check that the needed information is in the initial file comment.

Definition at line 149 of file LangCheck.php.

150 {
151 if (!preg_match('/\/\*\*\**\s(.*?)(?:\s*\*\/)/s', $this->content, $m)) {
152 $this->issue(self::TYPE_ERROR, 'Language file does not have an initial comment block!');
153 return;
154 }
155 $comment = $m[1];
156
157 if (!preg_match('/Author: +\S+/', $comment)) {
158 $this->issue(self::TYPE_WARNING, 'Language file does not contain a specification of an author!');
159 }
160 if (!preg_match('/Copyright: +\S+/', $comment)) {
161 $this->issue(self::TYPE_WARNING, 'Language file does not contain a specification of the copyright!');
162 }
163 if (!preg_match('/Release Version: +\d+\.\d+\.\d+\.\d+/', $comment)) {
164 $this->issue(self::TYPE_WARNING, 'Language file does not contain a specification of the release version!');
165 }
166 if (!preg_match('/Date Started: +\S+/s', $comment)) {
167 $this->issue(self::TYPE_WARNING, 'Language file does not contain a specification of the date it was started!');
168 }
169 if (!preg_match('/This file is part of GeSHi\./', $comment)) {
170 $this->issue(self::TYPE_WARNING, 'Language file does not state that it belongs to GeSHi!');
171 }
172 if (!preg_match('/\S+ language file for GeSHi\./', $comment)) {
173 $this->issue(self::TYPE_WARNING, 'Language file does not state that it is a language file for GeSHi!');
174 }
175 if (!preg_match('/GNU General Public License/', $comment)) {
176 $this->issue(self::TYPE_WARNING, 'Language file does not state that it is provided under the terms of the GNU GPL!');
177 }
178 }
$comment
Definition: buildRTE.php:83
issue($type, $msg)
log an issue
Definition: LangCheck.php:567

References $comment, $m, and issue().

Referenced by runChecks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ checkGeneral()

LangCheck::checkGeneral ( )
protected

Check some general file properties.

Definition at line 116 of file LangCheck.php.

117 {
118 if (preg_match('/\?>(?:\r?\n|\r(?!\n)){2,}\Z/', $this->content)) {
119 $this->issue(self::TYPE_ERROR, 'Language file contains trailing empty lines at EOF!');
120 }
121 if (preg_match('/\?>(?:\r?\n|\r(?!\n))?\Z/', $this->content)) {
122 $this->issue(self::TYPE_ERROR, 'Language file contains an PHP end marker at EOF!');
123 }
124 if (!preg_match('/(?:\r?\n|\r(?!\n))\Z/', $this->content)) {
125 $this->issue(self::TYPE_ERROR, 'Language file contains no newline at EOF!');
126 }
127 if (preg_match('/(\r?\n|\r(?!\n))\\1\Z/', $this->content)) {
128 $this->issue(self::TYPE_ERROR, 'Language file contains trailing empty line before EOF!');
129 }
130 if (preg_match('/[\x20\t]$/m', $this->content)) {
131 $this->issue(self::TYPE_ERROR, 'Language file contains trailing whitespace at EOL!');
132 }
133 if (preg_match('/\t/', $this->content)) {
134 $this->issue(self::TYPE_NOTICE, 'Language file contains unescaped tabulator chars (probably for indentation)!');
135 }
136 if (preg_match('/^(?: )*(?! )(?! \*) /m', $this->content)) {
137 $this->issue(self::TYPE_NOTICE, 'Language file contains irregular indentation (other than 4 spaces per indentation level)!');
138 }
139 if (preg_match('/\015\012/s', $this->content)) {
140 $this->issue(self::TYPE_ERROR, 'Language file contains DOS line endings!');
141 } else if (preg_match('/\015/s', $this->content)) {
142 $this->issue(self::TYPE_ERROR, 'Language file contains MAC line endings!');
143 }
144 }

References issue().

Referenced by runChecks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ checkKeyContents()

LangCheck::checkKeyContents ( )
protected

Check the keywords are sane.

@fixme split this into some sane chunks, maybe generalize

Definition at line 358 of file LangCheck.php.

359 {
360 foreach ($this->langdata['KEYWORDS'] as $key => $keywords) {
361 if (!isset($this->langdata['CASE_SENSITIVE'][$key])) {
362 $this->issue(self::TYPE_ERROR, "Language file contains no \$language_data['CASE_SENSITIVE'] specification for keyword group $key!");
363 }
364 if (!isset($this->langdata['URLS'][$key])) {
365 $this->issue(self::TYPE_ERROR, "Language file contains no \$language_data['URLS'] specification for keyword group $key!");
366 }
367 if (empty($keywords)) {
368 $this->issue(self::TYPE_WARNING, "Language file contains an empty keyword list in \$language_data['KEYWORDS'] for group $key!");
369 }
370 foreach ($keywords as $id => $kw) {
371 if (!is_string($kw)) {
372 $this->issue(self::TYPE_WARNING, "Language file contains an non-string entry at \$language_data['KEYWORDS'][$key][$id]!");
373 } elseif (!strlen($kw)) {
374 $this->issue(self::TYPE_ERROR, "Language file contains an empty string entry at \$language_data['KEYWORDS'][$key][$id]!");
375 } elseif (preg_match('/^([\‍(\‍)\{\}\[\]\^=.,:;\-+\*\/%\$\"\'\?]|&[\w#]\w*;)+$/i', $kw)) {
376 $this->issue(self::TYPE_NOTICE, "Language file contains an keyword ('$kw') at \$language_data['KEYWORDS'][$key][$id] which seems to be better suited for the symbols section!");
377 }
378 }
379 if (isset($this->langdata['CASE_SENSITIVE'][$key]) && !$this->langdata['CASE_SENSITIVE'][$key]) {
380 array_walk($keywords, array($this, 'strtolower'));
381 }
382 if (count($keywords) != count(array_unique($keywords))) {
383 $kw_diffs = array_count_values($keywords);
384 foreach ($kw_diffs as $kw => $kw_count) {
385 if ($kw_count > 1) {
386 $this->issue(self::TYPE_WARNING, "Language file contains per-group duplicate keyword '$kw' in \$language_data['KEYWORDS'][$key]!");
387 }
388 }
389 }
390 }
391
392 $disallowed_before = '(?<![a-zA-Z0-9\$_\|\#;>|^&';
393 $disallowed_after = '(?![a-zA-Z0-9_\|%\\-&;';
394
395 foreach ($this->langdata['KEYWORDS'] as $key => $keywords) {
396 foreach ($this->langdata['KEYWORDS'] as $key2 => $keywords2) {
397 if ($key2 <= $key) {
398 continue;
399 }
400 $kw_diffs = array_intersect($keywords, $keywords2);
401 foreach ($kw_diffs as $kw) {
402 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS'])) {
403 //Check the precondition\post-cindition for the involved keyword groups
404 $g1_pre = $disallowed_before;
405 $g2_pre = $disallowed_before;
406 $g1_post = $disallowed_after;
407 $g2_post = $disallowed_after;
408 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'])) {
409 $g1_pre = $this->langdata['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'];
410 $g2_pre = $this->langdata['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'];
411 }
412 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'])) {
413 $g1_post = $this->langdata['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'];
414 $g2_post = $this->langdata['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'];
415 }
416
417 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_BEFORE'])) {
418 $g1_pre = $this->langdata['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_BEFORE'];
419 }
420 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_AFTER'])) {
421 $g1_post = $this->langdata['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_AFTER'];
422 }
423
424 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_BEFORE'])) {
425 $g2_pre = $this->langdata['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_BEFORE'];
426 }
427 if (isset($this->langdata['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_AFTER'])) {
428 $g2_post = $this->langdata['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_AFTER'];
429 }
430
431 if ($g1_pre != $g2_pre || $g1_post != $g2_post) {
432 continue;
433 }
434 }
435 $this->issue(self::TYPE_WARNING, "Language file contains cross-group duplicate keyword '$kw' in \$language_data['KEYWORDS'][$key] and \$language_data['KEYWORDS'][$key2]!");
436 }
437 }
438 }
439 foreach ($this->langdata['CASE_SENSITIVE'] as $key => $keywords) {
440 if (!isset($this->langdata['KEYWORDS'][$key]) && $key != GESHI_COMMENTS) {
441 $this->issue(self::TYPE_WARNING, "Language file contains an superfluous \$language_data['CASE_SENSITIVE'] specification for non-existing keyword group $key!");
442 }
443 }
444 foreach ($this->langdata['URLS'] as $key => $keywords) {
445 if (!isset($this->langdata['KEYWORDS'][$key])) {
446 $this->issue(self::TYPE_WARNING, "Language file contains an superfluous \$language_data['URLS'] specification for non-existing keyword group $key!");
447 }
448 }
449 foreach ($this->langdata['STYLES']['KEYWORDS'] as $key => $keywords) {
450 if (!isset($this->langdata['KEYWORDS'][$key])) {
451 $this->issue(self::TYPE_WARNING, "Language file contains an superfluous \$language_data['STYLES']['KEYWORDS'] specification for non-existing keyword group $key!");
452 }
453 }
454
455 foreach ($this->langdata['COMMENT_SINGLE'] as $ck => $cv) {
456 if (!is_int($ck)) {
457 $this->issue(self::TYPE_WARNING, "Language file contains an key '$ck' in \$language_data['COMMENT_SINGLE'] that is not integer!");
458 }
459 if (!is_string($cv)) {
460 $this->issue(self::TYPE_WARNING, "Language file contains an non-string entry at \$language_data['COMMENT_SINGLE'][$ck]!");
461 }
462 if (!isset($this->langdata['STYLES']['COMMENTS'][$ck])) {
463 $this->issue(self::TYPE_WARNING, "Language file contains no \$language_data['STYLES']['COMMENTS'] specification for comment group $ck!");
464 }
465 }
466 if (isset($this->langdata['COMMENT_REGEXP'])) {
467 foreach ($this->langdata['COMMENT_REGEXP'] as $ck => $cv) {
468 if (!is_int($ck)) {
469 $this->issue(self::TYPE_WARNING, "Language file contains an key '$ck' in \$language_data['COMMENT_REGEXP'] that is not integer!");
470 }
471 if (!is_string($cv)) {
472 $this->issue(self::TYPE_WARNING, "Language file contains an non-string entry at \$language_data['COMMENT_REGEXP'][$ck]!");
473 }
474 if (!isset($this->langdata['STYLES']['COMMENTS'][$ck])) {
475 $this->issue(self::TYPE_WARNING, "Language file contains no \$language_data['STYLES']['COMMENTS'] specification for comment group $ck!");
476 }
477 }
478 }
479 foreach ($this->langdata['STYLES']['COMMENTS'] as $ck => $cv) {
480 if ($ck != 'MULTI' && !isset($this->langdata['COMMENT_SINGLE'][$ck]) &&
481 !isset($this->langdata['COMMENT_REGEXP'][$ck])
482 ) {
483 $this->issue(self::TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['COMMENTS'] specification for Single Line or Regular-Expression Comment key $ck!");
484 }
485 }
486 if (isset($this->langdata['STYLES']['STRINGS']['HARD'])) {
487 if (empty($this->langdata['HARDQUOTE'])) {
488 $this->issue(self::TYPE_NOTICE, "Language file contains superfluous \$language_data['STYLES']['STRINGS'] specification for key 'HARD', but no 'HARDQUOTE's are defined!");
489 }
490 unset($this->langdata['STYLES']['STRINGS']['HARD']);
491 }
492 foreach ($this->langdata['STYLES']['STRINGS'] as $sk => $sv) {
493 if ($sk && !isset($this->langdata['QUOTEMARKS'][$sk])) {
494 $this->issue(self::TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['STRINGS'] specification for non-existing quotemark key $sk!");
495 }
496 }
497
498 foreach ($this->langdata['REGEXPS'] as $rk => $rv) {
499 if (!is_int($rk)) {
500 $this->issue(self::TYPE_WARNING, "Language file contains an key '$rk' in \$language_data['REGEXPS'] that is not integer!");
501 }
502 if (is_string($rv)) {
503 //Check for unmasked / in regular expressions ...
504 if (empty($rv)) {
505 $this->issue(self::TYPE_WARNING, "Language file contains an empty regular expression at \$language_data['REGEXPS'][$rk]!");
506 } else {
507 if (preg_match("/(?<!\\\\)\//s", $rv)) {
508 $this->issue(self::TYPE_WARNING, "Language file contains a regular expression with an unmasked / character at \$language_data['REGEXPS'][$rk]!");
509 } elseif (preg_match("/(?<!<)(\\\\\\\\)*\\\\\|(?!>)/s", $rv)) {
510 $this->issue(self::TYPE_WARNING, "Language file contains a regular expression with an unescaped match for a pipe character '|' which needs escaping as '&lt;PIPE&gt;' instead at \$language_data['REGEXPS'][$rk]!");
511 }
512 }
513 } elseif (is_array($rv)) {
514 if (!isset($rv[GESHI_SEARCH])) {
515 $this->issue(self::TYPE_ERROR, "Language file contains no GESHI_SEARCH entry in extended regular expression at \$language_data['REGEXPS'][$rk]!");
516 } elseif (!is_string($rv[GESHI_SEARCH])) {
517 $this->issue(self::TYPE_ERROR, "Language file contains a GESHI_SEARCH entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!");
518 } else {
519 if (preg_match("/(?<!\\\\)\//s", $rv[GESHI_SEARCH])) {
520 $this->issue(self::TYPE_WARNING, "Language file contains a regular expression with an unmasked / character at \$language_data['REGEXPS'][$rk]!");
521 } elseif (preg_match("/(?<!<)(\\\\\\\\)*\\\\\|(?!>)/s", $rv[GESHI_SEARCH])) {
522 $this->issue(self::TYPE_WARNING, "Language file contains a regular expression with an unescaped match for a pipe character '|' which needs escaping as '&lt;PIPE&gt;' instead at \$language_data['REGEXPS'][$rk]!");
523 }
524 }
525 if (!isset($rv[GESHI_REPLACE])) {
526 $this->issue(self::TYPE_WARNING, "Language file contains no GESHI_REPLACE entry in extended regular expression at \$language_data['REGEXPS'][$rk]!");
527 } elseif (!is_string($rv[GESHI_REPLACE])) {
528 $this->issue(self::TYPE_ERROR, "Language file contains a GESHI_REPLACE entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!");
529 }
530 if (!isset($rv[GESHI_MODIFIERS])) {
531 $this->issue(self::TYPE_WARNING, "Language file contains no GESHI_MODIFIERS entry in extended regular expression at \$language_data['REGEXPS'][$rk]!");
532 } elseif (!is_string($rv[GESHI_MODIFIERS])) {
533 $this->issue(self::TYPE_ERROR, "Language file contains a GESHI_MODIFIERS entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!");
534 }
535 if (!isset($rv[GESHI_BEFORE])) {
536 $this->issue(self::TYPE_WARNING, "Language file contains no GESHI_BEFORE entry in extended regular expression at \$language_data['REGEXPS'][$rk]!");
537 } elseif (!is_string($rv[GESHI_BEFORE])) {
538 $this->issue(self::TYPE_ERROR, "Language file contains a GESHI_BEFORE entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!");
539 }
540 if (!isset($rv[GESHI_AFTER])) {
541 $this->issue(self::TYPE_WARNING, "Language file contains no GESHI_AFTER entry in extended regular expression at \$language_data['REGEXPS'][$rk]!");
542 } elseif (!is_string($rv[GESHI_AFTER])) {
543 $this->issue(self::TYPE_ERROR, "Language file contains a GESHI_AFTER entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!");
544 }
545 } else {
546 $this->issue(self::TYPE_WARNING, "Language file contains an non-string and non-array entry at \$language_data['REGEXPS'][$rk]!");
547 }
548 if (!isset($this->langdata['STYLES']['REGEXPS'][$rk])) {
549 $this->issue(self::TYPE_WARNING, "Language file contains no \$language_data['STYLES']['REGEXPS'] specification for regexp group $rk!");
550 }
551 }
552 foreach ($this->langdata['STYLES']['REGEXPS'] as $rk => $rv) {
553 if (!isset($this->langdata['REGEXPS'][$rk])) {
554 $this->issue(self::TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['REGEXPS'] specification for regexp key $rk!");
555 }
556 }
557 }
$key
Definition: croninfo.php:18
if(!array_key_exists('StateId', $_REQUEST)) $id
const GESHI_BEFORE
The key of the regex array defining what bracket group in a matched search to put before the replacem...
Definition: geshi.php:140
const GESHI_SEARCH
The key of the regex array defining what to search for.
Definition: geshi.php:132
const GESHI_AFTER
The key of the regex array defining what bracket group in a matched search to put after the replaceme...
Definition: geshi.php:143
const GESHI_REPLACE
The key of the regex array defining what bracket group in a matched search to use as a replacement.
Definition: geshi.php:135
const GESHI_COMMENTS
Used in language files to mark comments.
Definition: geshi.php:149
const GESHI_MODIFIERS
The key of the regex array defining any modifiers to the regular expression.
Definition: geshi.php:137

References $id, $key, GESHI_AFTER, GESHI_BEFORE, GESHI_COMMENTS, GESHI_MODIFIERS, GESHI_REPLACE, GESHI_SEARCH, and issue().

Referenced by runChecks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ checkMainKeys()

LangCheck::checkMainKeys ( )
protected

Check the major keys in the language array.

Definition at line 241 of file LangCheck.php.

242 {
243 // these just need a type check:
244 $this->ensureKeyType('LANG_NAME', 'string');
245 $this->ensureKeyType('COMMENT_SINGLE');
246 $this->ensureKeyType('COMMENT_MULTI');
247 $this->ensureKeyType('COMMENT_REGEXP', 'array', true);
248 $this->ensureKeyType('QUOTEMARKS');
249 $this->ensureKeyType('HARDQUOTE', 'array', true);
250 $this->ensureKeyType('SYMBOLS');
251 $this->ensureKeyType('OBJECT_SPLITTERS');
252 $this->ensureKeyType('REGEXPS');
253 $this->ensureKeyType('SCRIPT_DELIMITERS');
254 $this->ensureKeyType('HIGHLIGHT_STRICT_BLOCK');
255 $this->ensureKeyType('PARSER_CONTROL', 'array', true);
256
257 // these need additional simple checks after the type checks out
258 if ($this->ensureKeyType('ESCAPE_CHAR', 'string')) {
259 if (1 < strlen($this->langdata['ESCAPE_CHAR'])) {
260 $this->issue(self::TYPE_ERROR, 'Language file contains a $language_data[\'ESCAPE_CHAR\'] specification is not empty or exactly one char!');
261 }
262 }
263
264 if ($this->ensureKeyType('CASE_KEYWORDS', 'integer')) {
265 if (GESHI_CAPS_NO_CHANGE != $this->langdata['CASE_KEYWORDS'] &&
266 GESHI_CAPS_LOWER != $this->langdata['CASE_KEYWORDS'] &&
267 GESHI_CAPS_UPPER != $this->langdata['CASE_KEYWORDS']
268 ) {
269 $this->issue(self::TYPE_ERROR, 'Language file contains a $language_data[\'CASE_KEYWORDS\'] specification which is neither of GESHI_CAPS_NO_CHANGE, GESHI_CAPS_LOWER nor GESHI_CAPS_UPPER!');
270 }
271 }
272
273 if ($this->ensureKeyType('KEYWORDS')) {
274 foreach ($this->langdata['KEYWORDS'] as $kw_key => $kw_value) {
275 if (!is_integer($kw_key)) {
276 $this->issue(self::TYPE_WARNING, "Language file contains an key '$kw_key' in \$language_data['KEYWORDS'] that is not integer!");
277 } elseif (!is_array($kw_value)) {
278 $this->issue(self::TYPE_ERROR, "Language file contains a \$language_data['KEYWORDS']['$kw_value'] structure which is not an array!");
279 }
280 }
281 }
282
283 if ($this->ensureKeyType('CASE_SENSITIVE')) {
284 foreach ($this->langdata['CASE_SENSITIVE'] as $cs_key => $cs_value) {
285 if (!is_integer($cs_key)) {
286 $this->issue(self::TYPE_WARNING, "Language file contains an key '$cs_key' in \$language_data['CASE_SENSITIVE'] that is not integer!");
287 } elseif (!is_bool($cs_value)) {
288 $this->issue(self::TYPE_ERROR, "Language file contains a Case Sensitivity specification for \$language_data['CASE_SENSITIVE']['$cs_value'] which is not a boolean!");
289 }
290 }
291 }
292
293 if ($this->ensureKeyType('URLS')) {
294 foreach ($this->langdata['URLS'] as $url_key => $url_value) {
295 if (!is_integer($url_key)) {
296 $this->issue(self::TYPE_WARNING, "Language file contains an key '$url_key' in \$language_data['URLS'] that is not integer!");
297 } elseif (!is_string($url_value)) {
298 $this->issue(self::TYPE_ERROR, "Language file contains a Documentation URL specification for \$language_data['URLS']['$url_value'] which is not a string!");
299 } elseif (preg_match('#&([^;]*(=|$))#U', $url_value)) {
300 $this->issue(self::TYPE_ERROR, "Language file contains unescaped ampersands (&amp;) in \$language_data['URLS']!");
301 }
302 }
303 }
304
305 if ($this->ensureKeyType('OOLANG', 'boolean|integer')) {
306 if (false !== $this->langdata['OOLANG'] &&
307 true !== $this->langdata['OOLANG'] &&
308 2 !== $this->langdata['OOLANG']
309 ) {
310 $this->issue(self::TYPE_ERROR, 'Language file contains a $language_data[\'OOLANG\'] specification which is neither of false, true or 2!');
311 }
312 }
313
314 if ($this->ensureKeyType('STRICT_MODE_APPLIES', 'integer')) {
315 if (GESHI_MAYBE != $this->langdata['STRICT_MODE_APPLIES'] &&
316 GESHI_ALWAYS != $this->langdata['STRICT_MODE_APPLIES'] &&
317 GESHI_NEVER != $this->langdata['STRICT_MODE_APPLIES']
318 ) {
319 $this->issue(self::TYPE_ERROR, 'Language file contains a $language_data[\'STRICT_MODE_APPLIES\'] specification which is neither of GESHI_MAYBE, GESHI_ALWAYS nor GESHI_NEVER!');
320 }
321 }
322
323 if ($this->ensureKeyType('TAB_WIDTH', 'integer', true)) {
324 if (1 > $this->langdata['TAB_WIDTH']) {
325 $this->issue(self::TYPE_ERROR, 'Language file contains a $language_data[\'TAB_WIDTH\'] specification which is less than 1!');
326 }
327 }
328
329 if ($this->ensureKeyType('STYLES')) {
330 $style_arrays = array('KEYWORDS', 'COMMENTS', 'ESCAPE_CHAR',
331 'BRACKETS', 'STRINGS', 'NUMBERS', 'METHODS', 'SYMBOLS',
332 'REGEXPS', 'SCRIPT');
333 foreach ($style_arrays as $style_kind) {
334 if (!isset($this->langdata['STYLES'][$style_kind])) {
335 $this->issue(self::TYPE_ERROR, "Language file contains no \$language_data['STYLES']['$style_kind'] structure to check!");
336 } elseif (!is_array($this->langdata['STYLES'][$style_kind])) {
337 $this->issue(self::TYPE_ERROR, "Language file contains a \$language_data['STYLES\']['$style_kind'] structure which is not an array!");
338 } else {
339 foreach ($this->langdata['STYLES'][$style_kind] as $sk_key => $sk_value) {
340 if (!is_int($sk_key) && ('COMMENTS' != $style_kind && 'MULTI' != $sk_key)
341 && !(('STRINGS' == $style_kind || 'ESCAPE_CHAR' == $style_kind) && 'HARD' == $sk_key)
342 ) {
343 $this->issue(self::TYPE_WARNING, "Language file contains an key '$sk_key' in \$language_data['STYLES']['$style_kind'] that is not integer!");
344 } elseif (!is_string($sk_value)) {
345 $this->issue(self::TYPE_WARNING, "Language file contains a CSS specification for \$language_data['STYLES']['$style_kind'][$key] which is not a string!");
346 }
347 }
348 }
349 }
350 }
351 }
ensureKeyType($name, $type='array', $optional=false)
Check that the given key exists and has the correct type.
Definition: LangCheck.php:218
const GESHI_MAYBE
Strict mode might apply, and can be enabled or disabled by GeSHi->enable_strict_mode().
Definition: geshi.php:126
const GESHI_CAPS_NO_CHANGE
Lowercase keywords found.
Definition: geshi.php:94
const GESHI_ALWAYS
Strict mode always applies.
Definition: geshi.php:128
const GESHI_CAPS_LOWER
Leave keywords found as the case that they are.
Definition: geshi.php:98
const GESHI_NEVER
#+ @access private
Definition: geshi.php:123
const GESHI_CAPS_UPPER
Uppercase keywords found.
Definition: geshi.php:96

References ensureKeyType(), GESHI_ALWAYS, GESHI_CAPS_LOWER, GESHI_CAPS_NO_CHANGE, GESHI_CAPS_UPPER, GESHI_MAYBE, GESHI_NEVER, and issue().

Referenced by runChecks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ensureKeyType()

LangCheck::ensureKeyType (   $name,
  $type = 'array',
  $optional = false 
)
protected

Check that the given key exists and has the correct type.

Logs errors and returns the result

Parameters
string$name
string$typethe type as understood by gettype(), multiple can be joined by '|'
bool$optionalis it okay when the key does not exist?
Returns
bool true if all is okay

Definition at line 218 of file LangCheck.php.

219 {
220 $types = explode('|', $type);
221
222 if (!isset($this->langdata[$name])) {
223 if ($optional) {
224 return false;
225 }
226 $this->issue(self::TYPE_ERROR, "Language file contains no \$language_data['$name'] specification!");
227 return false;
228 }
229
230 if (!in_array(gettype($this->langdata[$name]), $types)) {
231 $this->issue(self::TYPE_ERROR, "Language file contains a \$language_data['$name'] specification which is not a $type!");
232 return false;
233 }
234
235 return true;
236 }
if($format !==null) $name
Definition: metadata.php:146
$type

References $name, $type, and issue().

Referenced by checkMainKeys().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getIssues()

LangCheck::getIssues ( )

Get all found issues as (severity, message) tuple.

Returns
array

Definition at line 76 of file LangCheck.php.

77 {
78 return $this->issues;
79 }

References $issues.

◆ getIssuesAsString()

LangCheck::getIssuesAsString ( )

Get all found issues as formatted list.

Returns
string

Definition at line 86 of file LangCheck.php.

87 {
88 $string = '';
89 foreach ($this->issues as $issue) {
90 $string .= $this->severityNames[$issue[0]] . ' ' . $issue[1] . "\n";
91 }
92 return $string;
93 }

◆ issue()

LangCheck::issue (   $type,
  $msg 
)
protected

log an issue

Parameters
int$type
string$msg
Exceptions
Exception

Definition at line 567 of file LangCheck.php.

568 {
569 $this->issues[] = array($type, $msg);
570
571 // abort all processing on fatal errors
572 if ($type == self::TYPE_FATAL) {
573 throw new Exception($msg);
574 }
575 }

References $type.

Referenced by checkComment(), checkGeneral(), checkKeyContents(), checkMainKeys(), ensureKeyType(), loadFile(), and loadLanguageData().

+ Here is the caller graph for this function:

◆ loadFile()

LangCheck::loadFile ( )
protected

Load the file content.

Logs a fatal error if the file can't be read

Definition at line 100 of file LangCheck.php.

101 {
102 if (!is_file($this->file)) {
103 $this->issue(self::TYPE_FATAL, 'The path "' . $this->file . '" does not ressemble a regular file!');
104 }
105
106 if (!is_readable($this->file)) {
107 $this->issue(self::TYPE_FATAL, 'Cannot read file "' . $this->file . '"!');
108 }
109
110 $this->content = file_get_contents($this->file);
111 }

References issue().

Referenced by runChecks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loadLanguageData()

LangCheck::loadLanguageData ( )
protected

Load the language data.

Logs a fatal error if the file does not define it

Definition at line 185 of file LangCheck.php.

186 {
187 $language_data = array();
188
189 include $this->file;
190
191 if (!isset($language_data)) {
192 $this->issue(self::TYPE_FATAL, 'Language file does not contain a $language_data structure to check!');
193 }
194
195 if (!is_array($language_data)) {
196 $this->issue(self::TYPE_FATAL, 'Language file contains a $language_data structure which is not an array!');
197 }
198
199 $this->langdata = $language_data;
200 unset($language_data);
201
202 $defined = get_defined_vars();
203 if ($defined) {
204 $this->issue(self::TYPE_ERROR, 'Language file seems to define other variables than $language_data!');
205 }
206 }
$language_data
Definition: 4cs.php:40

References $file, $language_data, and issue().

Referenced by runChecks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ runChecks()

LangCheck::runChecks ( )

Run all the checks on the file.

Returns
bool true if all checks pass

Definition at line 52 of file LangCheck.php.

53 {
54 $this->issues = array();
55 $this->loadFile();
56 $this->checkGeneral();
57 $this->checkComment();
58 $this->loadLanguageData();
59 $this->checkMainKeys();
60 // additional checks only if no errors before
61 if (!$this->issues) {
62 $this->checkKeyContents();
63 }
64
65 if ($this->issues) {
66 return false;
67 }
68 return true;
69 }
checkMainKeys()
Check the major keys in the language array.
Definition: LangCheck.php:241
checkComment()
Check that the needed information is in the initial file comment.
Definition: LangCheck.php:149
checkGeneral()
Check some general file properties.
Definition: LangCheck.php:116
loadFile()
Load the file content.
Definition: LangCheck.php:100
checkKeyContents()
Check the keywords are sane.
Definition: LangCheck.php:358
loadLanguageData()
Load the language data.
Definition: LangCheck.php:185

References checkComment(), checkGeneral(), checkKeyContents(), checkMainKeys(), loadFile(), and loadLanguageData().

+ Here is the call graph for this function:

◆ strtolower()

LangCheck::strtolower ( $value)

Definition at line 577 of file LangCheck.php.

578 {
579 $value = strtolower($value);
580 }
strtolower(&$value)
Definition: LangCheck.php:577

References strtolower().

Referenced by strtolower().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Field Documentation

◆ $content

LangCheck::$content
protected

Definition at line 24 of file LangCheck.php.

◆ $file

LangCheck::$file
protected

Definition at line 21 of file LangCheck.php.

Referenced by __construct(), and loadLanguageData().

◆ $issues

LangCheck::$issues = array()
protected

Definition at line 18 of file LangCheck.php.

Referenced by getIssues().

◆ $langdata

LangCheck::$langdata
protected

Definition at line 27 of file LangCheck.php.

◆ $severityNames

LangCheck::$severityNames
protected
Initial value:
= array(
self::TYPE_NOTICE => '[NOTICE] ',
self::TYPE_WARNING => '[WARNING]',
self::TYPE_ERROR => '[ERROR] ',
self::TYPE_FATAL => '[FATAL] '
)

Definition at line 30 of file LangCheck.php.

◆ TYPE_ERROR

const LangCheck::TYPE_ERROR = 3

Definition at line 14 of file LangCheck.php.

◆ TYPE_FATAL

const LangCheck::TYPE_FATAL = 4

Definition at line 15 of file LangCheck.php.

◆ TYPE_NOTICE

const LangCheck::TYPE_NOTICE = 1

Definition at line 12 of file LangCheck.php.

◆ TYPE_WARNING

const LangCheck::TYPE_WARNING = 2

Definition at line 13 of file LangCheck.php.


The documentation for this class was generated from the following file: