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.

References $file, and file.

43  {
44  $this->file = $file;
45  }
Reload workbook from saved 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.

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

Referenced by runChecks().

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  }
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
$comment
Definition: buildRTE.php:83
+ 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.

References issue().

Referenced by runChecks().

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  }
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
+ 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.

split this into some sane chunks, maybe generalize

Definition at line 358 of file LangCheck.php.

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

Referenced by runChecks().

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  }
const GESHI_MODIFIERS
The key of the regex array defining any modifiers to the regular expression.
Definition: geshi.php:137
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
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
const GESHI_COMMENTS
Used in language files to mark comments.
Definition: geshi.php:149
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_SEARCH
The key of the regex array defining what to search for.
Definition: geshi.php:132
Create styles array
The data for the language used.
$key
Definition: croninfo.php:18
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
+ 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.

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

Referenced by runChecks().

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  }
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
const GESHI_CAPS_UPPER
Uppercase keywords found.
Definition: geshi.php:96
ensureKeyType($name, $type='array', $optional=false)
Check that the given key exists and has the correct type.
Definition: LangCheck.php:218
Create styles array
The data for the language used.
const GESHI_CAPS_LOWER
Leave keywords found as the case that they are.
Definition: geshi.php:98
const GESHI_MAYBE
Strict mode might apply, and can be enabled or disabled by GeSHi->enable_strict_mode().
Definition: geshi.php:126
const GESHI_NEVER
#+ private
Definition: geshi.php:123
const GESHI_CAPS_NO_CHANGE
Lowercase keywords found.
Definition: geshi.php:94
const GESHI_ALWAYS
Strict mode always applies.
Definition: geshi.php:128
+ 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.

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

Referenced by checkMainKeys().

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  }
$type
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
if($format !==null) $name
Definition: metadata.php:146
+ 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.

References $issues.

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

◆ 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.

References $type, and array.

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

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  }
$type
Create styles array
The data for the language used.
+ 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.

References file, and issue().

Referenced by runChecks().

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  }
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
Reload workbook from saved file
+ 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.

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

Referenced by runChecks().

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  }
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
Create styles array
The data for the language used.
$language_data
Definition: 4cs.php:40
+ 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.

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

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  }
loadLanguageData()
Load the language data.
Definition: LangCheck.php:185
checkGeneral()
Check some general file properties.
Definition: LangCheck.php:116
checkMainKeys()
Check the major keys in the language array.
Definition: LangCheck.php:241
loadFile()
Load the file content.
Definition: LangCheck.php:100
checkKeyContents()
Check the keywords are sane.
Definition: LangCheck.php:358
Create styles array
The data for the language used.
checkComment()
Check that the needed information is in the initial file comment.
Definition: LangCheck.php:149
+ 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

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:
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: