ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
LangCheck.php
Go to the documentation of this file.
1<?php
2require_once __DIR__ . '/../src/geshi.php';
3
10{
11
12 const TYPE_NOTICE = 1;
13 const TYPE_WARNING = 2;
14 const TYPE_ERROR = 3;
15 const TYPE_FATAL = 4;
16
18 protected $issues = array();
19
21 protected $file;
22
24 protected $content;
25
27 protected $langdata;
28
30 protected $severityNames = array(
31 self::TYPE_NOTICE => '[NOTICE] ',
32 self::TYPE_WARNING => '[WARNING]',
33 self::TYPE_ERROR => '[ERROR] ',
34 self::TYPE_FATAL => '[FATAL] '
35 );
36
42 public function __construct($file)
43 {
44 $this->file = $file;
45 }
46
52 public function runChecks()
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 }
70
76 public function getIssues()
77 {
78 return $this->issues;
79 }
80
86 public function getIssuesAsString()
87 {
88 $string = '';
89 foreach ($this->issues as $issue) {
90 $string .= $this->severityNames[$issue[0]] . ' ' . $issue[1] . "\n";
91 }
92 return $string;
93 }
94
100 protected function loadFile()
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 }
112
116 protected function checkGeneral()
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 }
145
149 protected function checkComment()
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 }
179
185 protected function loadLanguageData()
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 }
207
218 protected function ensureKeyType($name, $type = 'array', $optional = false)
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 }
237
241 protected function checkMainKeys()
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 }
352
358 protected function checkKeyContents()
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 }
558
559
567 protected function issue($type, $msg)
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 }
576
577 public function strtolower(&$value)
578 {
579 $value = strtolower($value);
580 }
581}
$language_data
Definition: 4cs.php:40
$comment
Definition: buildRTE.php:83
An exception for terminatinating execution or to throw for unit testing.
Class LangCheck.
Definition: LangCheck.php:10
const TYPE_FATAL
Definition: LangCheck.php:15
__construct($file)
LangCheck constructor.
Definition: LangCheck.php:42
const TYPE_ERROR
Definition: LangCheck.php:14
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
const TYPE_WARNING
Definition: LangCheck.php:13
checkGeneral()
Check some general file properties.
Definition: LangCheck.php:116
getIssuesAsString()
Get all found issues as formatted list.
Definition: LangCheck.php:86
runChecks()
Run all the checks on the file.
Definition: LangCheck.php:52
issue($type, $msg)
log an issue
Definition: LangCheck.php:567
strtolower(&$value)
Definition: LangCheck.php:577
loadFile()
Load the file content.
Definition: LangCheck.php:100
ensureKeyType($name, $type='array', $optional=false)
Check that the given key exists and has the correct type.
Definition: LangCheck.php:218
const TYPE_NOTICE
Definition: LangCheck.php:12
getIssues()
Get all found issues as (severity, message) tuple.
Definition: LangCheck.php:76
checkKeyContents()
Check the keywords are sane.
Definition: LangCheck.php:358
loadLanguageData()
Load the language data.
Definition: LangCheck.php:185
$key
Definition: croninfo.php:18
if(!array_key_exists('StateId', $_REQUEST)) $id
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_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_ALWAYS
Strict mode always applies.
Definition: geshi.php:128
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_CAPS_LOWER
Leave keywords found as the case that they are.
Definition: geshi.php:98
const GESHI_COMMENTS
Used in language files to mark comments.
Definition: geshi.php:149
const GESHI_NEVER
#+ @access private
Definition: geshi.php:123
const GESHI_MODIFIERS
The key of the regex array defining any modifiers to the regular expression.
Definition: geshi.php:137
const GESHI_CAPS_UPPER
Uppercase keywords found.
Definition: geshi.php:96
if($format !==null) $name
Definition: metadata.php:146
$type