GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (4873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/common/language/BaseLanguage.class.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * SourceForge: Breaking Down the Barriers to Open Source Development
4
 * Copyright 1999-2000 (c) The SourceForge Crew
5
 * http://sourceforge.net
6
 * 
7
 * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
8
 *
9
 * This file is a part of Codendi.
10
 *
11
 * Codendi is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 2 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * Codendi is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with Codendi. If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
/**
26
 *
27
 *  Tim Perdue, September 7, 2000
28
 *  Laurent Julliard, Jan 14, 2004
29
 *  Manuel Vacelet, July 22, 2008 (nice, every 4 years !)
30
 *
31
 *  Base class for adding multilingual support to Codendi
32
 *
33
 *  Contains variables which can be overridden optionally by other
34
 *  language files.
35
 *
36
 *  Base language is english - an english class will extend this one,
37
 *  but won't override anything
38
 *
39
 *  As new languages are added, they can override what they wish, and
40
 *  as we extend our class, other languages can follow suit
41
 *  as they are translated without holding up our progress
42
 *
43
 *  A global language file is loaded first and then each php script
44
 *  loads its won scripts (site-local customized versions are also
45
 *  loaded if they do exist)
46
 *
47
 */
48
class BaseLanguage {
49
50
    const DEFAULT_LANG = 'en_US';
51
52
    //array to hold the string values
53
    var $text_array ;
54
    var $lang, $name, $id, $code ;
55
    var $file_array = array();
56
57
    /**
58
     * Supported languages
59
     */
60
    public $allLanguages;
61
    
62
    /**
63
     * Default languages
64
     */
65
    public $defaultLanguage;
66
    
67
    /**
68
     * Constructor
69
     * @param $supported_languages string 'en_US,fr_FR'
70
     * @param $default_language string 'en_US'
71
     */
72
    function __construct($supported_languages, $default_language) {
73
        $this->allLanguages = array();
74
        $supported_languages = explode(',', $supported_languages);
75
        foreach($supported_languages as $v) {
76
            if (trim($v) !== '') {
77
                $this->allLanguages[] = trim($v);
78
            }
79
        }
80
        if (count($this->allLanguages)) {
81
            if (in_array($default_language, $this->allLanguages)) {
82
                $this->defaultLanguage = $default_language;
83
            } else {
84
                throw new Exception('The default language must be part of supported languages');
85
            }
86
        } else {
87
            throw new Exception('You must provide supported languages (see local.inc)');
88
        }
89
    }
90
91
    /**
92
     * "compile" all available language definitions.
93
     */
94
    function compileAllLanguageFiles() {
95
        foreach($this->allLanguages as $code) {
96
            $this->compileLanguage($code);
97
        }
98
    }
99
100
    /**
101
     * Load all generated php files to verify if the syntax is correct.
102
     */
103
    function testLanguageFiles() {
104
        if(is_dir($this->getCacheDirectory())) {
105
            $fd = opendir($this->getCacheDirectory());
106
            // Browse all generated php files
107
            while(false !== ($file = readdir($fd))) {
108
                if(is_file($this->getCacheDirectory().DIRECTORY_SEPARATOR.$file)
109
                   && preg_match('/\.php$/', $file)) {
110
                    echo "Test $file\n";
111
                    include($this->getCacheDirectory().DIRECTORY_SEPARATOR.$file);
112
                    unset($this->text_array);
113
                }
114
            }
115
            closedir($fd);
116
        }
117
    }
118
119
    /**
120
     * "compile" string definitions for one language.
121
     */
122
    function compileLanguage($lang) {
123
        $text_array = array();
124
        $this->loadAllLanguageFiles($lang, $text_array);
125
126
        // Dump the result into the cached files
127
        $this->dumpLanguageFile($lang, $text_array);
128
129
        return $text_array;
130
    }
131
132
    /**
133
     * Load all tab files to build the internal string array.
134
     *
135
     * Here the order is important: First load the default definition and than
136
     * load the custom (site wide) defs in order to override the default one,
137
     * and so on.
138
     */
139
    function loadAllLanguageFiles($lang, &$text_array) {
140
        // The order is important!
141
142
        // 1) load all the en_US for official code (core + plugins) in order
143
        // to define all the default values (all other language load while
144
        // override existing values. If no overriding: the en_US value appears.
145
        if($lang != self::DEFAULT_LANG) {
146
            $this->loadCoreSiteContent(self::DEFAULT_LANG, $text_array);
147
            $this->loadPluginsSiteContent(self::DEFAULT_LANG, $text_array);
148
        }
149
150
        // 2) load the language for official code
151
        $this->loadCoreSiteContent($lang, $text_array);
152
        $this->loadCustomSiteContent($lang, $text_array);
153
        $this->loadPluginsSiteContent($lang, $text_array);
154
        $this->loadPluginsCustomSiteContent($lang, $text_array);
155
    }
156
157
    /**
158
     * Load tab files in /usr/share/codendi/site-content for given language
159
     */
160
    function loadCoreSiteContent($lang, &$text_array) {
161
        $this->loadAllTabFiles($GLOBALS['sys_incdir'].'/'.$lang, $text_array);
162
    }
163
164
    /**
165
     * Load tab files in /etc/codendi/site-content for given language
166
     */
167
    function loadCustomSiteContent($lang, &$text_array) {
168
        $this->loadAllTabFiles($GLOBALS['sys_custom_incdir'].'/'.$lang, $text_array);
169
    }
170
171
    /**
172
     * Load all tab files in /usr/share/codendi/plugins/.../site-content for
173
     * given language
174
     */
175
    function loadPluginsSiteContent($lang, &$text_array) {
176
        $directories = array_merge(
177
            array_map('trim', explode(',', ForgeConfig::get('sys_extra_plugin_path'))),
178
            array(ForgeConfig::get('sys_pluginsroot'))
179
        );
180
        foreach ($directories as $dir) {
181
            $this->_loadPluginsSiteContent($dir, $lang, $text_array);
182
        }
183
    }
184
185
    /**
186
     * Load all tab files in /etc/codendi/plugins/.../site-content for
187
     * given language
188
     */
189
    function loadPluginsCustomSiteContent($lang, &$text_array) {
190
        $this->_loadPluginsSiteContent($GLOBALS['sys_custompluginsroot'], $lang, $text_array);
191
    }
192
    
193
    /**
194
     * This method walk through all the plugins and load all .tab files for
195
     * each plugin found.
196
     */
197
    function _loadPluginsSiteContent($basedir, $lang, &$text_array) {
198
        if(is_dir($basedir)) {
199
            $fd = opendir($basedir);
200
            while(false !== ($file = readdir($fd))) {
201
                if(is_dir($basedir.'/'.$file)
202
                   && $file != '.'
203
                   && $file != '..'
204
                   && $file != '.svn'
205
                   && $file != 'CVS') {
206
                    $location = $basedir.'/'.$file.'/site-content/'.$lang;
207
                    if(is_dir($location)) {
208
                        $this->loadAllTabFiles($location, $text_array);
209
                    }
210
                }
211
            }
212
            closedir($fd);
213
        }
214
    }
215
216
    /**
217
     * Look for all ".tab" files in the given path recursively.
218
     */
219
    function loadAllTabFiles($basedir, &$text_array) {
220
        if(is_dir($basedir)) {
221
            $fd = opendir($basedir);
222
            while(false !== ($file = readdir($fd))) {
223
                if(preg_match('/\.tab$/', $file)) {
224
                    $this->parseLanguageFile($basedir.'/'.$file, $text_array);
225
                }
226
                elseif(is_dir($basedir.'/'.$file)
227
                       && $file != '.'
228
                       && $file != '..'
229
                       && $file != '.svn'
230
                       && $file != 'CVS') {
231
                    $this->loadAllTabFiles($basedir.'/'.$file, $text_array);
232
                }
233
            }
234
            closedir($fd);
235
        }
236
    }
237
238
    /**
239
     * Create a PHP file that contains all the strings loaded in this object.
240
     */
241
    function dumpLanguageFile($lang, $text_array) {
242
        // Create language cache directory if needed
243
        if (!file_exists($this->getCacheDirectory())) {
244
            // This directory must be world reachable, but writable only by the web-server
245
            mkdir($this->getCacheDirectory(), 0755);
246
        }
247
        $fd = @fopen($this->getCacheDirectory().DIRECTORY_SEPARATOR.$lang.'.php', 'w');
248
        if($fd !== false) {
249
            fwrite($fd, '<?php'."\n");
250
            foreach($text_array as $key1 => $level2) {
251
                foreach($level2 as $key2 => $value) {
252
                    $str = str_replace("'", "\'", $value);
253
                    fwrite($fd, '$this->text_array[\''.$key1.'\'][\''.$key2.'\'] = \''.$str.'\';'."\n");
254
                }
255
            }
256
            fwrite($fd, '?>');
257
            fclose($fd);
258
        }
259
    }
260
261
    function loadLanguageFile($fname) {
262
        if (array_key_exists($fname, $this->file_array)) { 
263
            return; 
264
        }
265
        $this->file_array[$fname] = 1;
266
        $this->parseLanguageFile($fname, $this->text_array);
267
    }
268
269
    /**
270
     * Parse given .tab file and store the result into $text_array
271
     */
272
    function parseLanguageFile($fname, &$text_array) {
273
        $ary = @file($fname,1);
274
        for( $i=0; $i<sizeof($ary); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
275
            if (substr($ary[$i], 0, 1) == '#' ||  //ignore comments...
276
                strlen(trim($ary[$i])) == 0) {    //...or empty lines
277
                continue;
278
            }
279
            // Language files can include others for defaults.
280
            // e.g. an English-Canada.tab file might "include English" first,
281
            // then override all those whacky American spellings.
282
            if (preg_match("/^include ([a-zA-Z]+)/", $ary[$i], $matches)) {
283
                $dir = dirname($fname);
284
                $this->parseLanguageFile($dir."/".$matches[1].".tab", $text_array);
285
            } else {
286
                $line = explode("\t", $ary[$i], 3);
287
                if (count($line) === 3) {
288
                    $text_array[$line[0]][$line[1]] = chop(str_replace('\n', "\n", ($line[2])));
289
                } else {
290
                    echo '* Error in '.$fname.' line '.$i.' string "'.trim($ary[$i]).'" (length: '.strlen(trim($ary[$i])).') : ';
291
                    if (!isset($line[0])) {
292
                        echo "no index 0: empty line ? ";
293
                    } elseif (!isset($line[1])) {
294
                        echo "no index 1: did you use tabs to separate elements ? ";
295
                    } elseif (!isset($line[2])) {
296
                        echo "no index 2: keys present but string is missing ";
297
                    }
298
                    echo "<br>".PHP_EOL;
299
                }
300
            }
301
        }
302
    }
303
304
    // Load the global language file (this is a global message catalog
305
    // that is loaded for all scripts from pre.php
306
    function loadLanguage($lang) {
307
        if($this->lang != $lang) {
308
            $this->lang = $lang;
309
            setlocale (LC_TIME, $lang);
310
            $langFile = $this->getCacheDirectory().DIRECTORY_SEPARATOR.$this->lang.'.php';
311
            if(file_exists($langFile)) {
312
                include($langFile);
313
            } else {
314
                // If language is supported, the compiled file should exists, try
315
                // to create it
316
                $this->text_array = $this->compileLanguage($lang);
317
            }
318
        }
319
    }
320
321
    function getText($pagename, $category, $args="") {
322
        // If the language files were modified by an update, the compiled version might not have been generated, 
323
        // and the message not present.
324
        if (! $this->hasText($pagename, $category)) {
325
            // Force compile (only once)
326
            $this->text_array = $this->compileLanguage($this->lang);
327
        }
328
        /*
329
            args is an array which will replace the $1, $2, etc
330
            in the text_array string before it is returned
331
        */
332
        if ($args || $args == 0) {
333
            //$tstring = sprintf($this->text_array[$pagename][$category],$args);
334
            for ($i=1; $i<=sizeof($args)+1; $i++) {
335
                $patterns[] = '/\$'.$i.'/';
336
            }
337
            $tstring = preg_replace($patterns, $args, $this->text_array[$pagename][$category]);
338
        } else {
339
                    // Remove $1, $2 etc. even if the given arguments are empty
340
                    $pattern = '/\$\d+/';
341
                    $tstring = preg_replace($pattern, '', $this->text_array[$pagename][$category]);
342
                    //$tstring = $this->text_array[$pagename][$category];
343
        }
344
        if (!$tstring) {
345
            $tstring = "*** Unkown msg $pagename - $category ***";
346
        }
347
        return "$tstring";
348
    }
349
350
    /**
351
     * @return bool
352
     */
353
    public function hasText($pagename, $category) {
354
        $this->ensureLanguageFilesAreLoaded();
355
        return isset($this->text_array[$pagename][$category]);
356
    }
357
358
    private function ensureLanguageFilesAreLoaded() {
359
        if (! isset($this->lang)) {
360
            $this->loadLanguage(UserManager::instance()->getCurrentUser()->getLocale());
361
        }
362
    }
363
364
    // This is a legacy piece of code that used to be utils_get_content
365
    // and is used either to include long piece of text that are inconvenient
366
    // to format on one line as the .tab file does or because there is some
367
    // PHP code that can be cutomized
368
    function getContent($file, $lang_code = null, $plugin_name = null, $ext = '.txt'){
369
370
        // Language for current user unless it is specified in the param list
371
        if (!isset($lang_code)) { 
372
            $lang_code = $this->lang;
373
        }
374
375
        if (is_null($plugin_name)) {
376
            // Test first the custom directory
377
            $custom_fn = $GLOBALS['sys_custom_incdir']."/".$lang_code."/".$file.$ext;
378
        } else {
379
            $custom_fn = $GLOBALS['sys_custompluginsroot'].'/'.$plugin_name.'/site-content/'.$lang_code.'/'.$file.$ext ;
380
        }
381
        if ( file_exists($custom_fn) ) {
382
            // The custom file exists. 
383
            return $custom_fn;
384
        } else {
385
            // Use the default file
386
            // Check first if exist
387
            if (is_null($plugin_name)) {
388
                $fn = $GLOBALS['sys_incdir']."/".$lang_code."/".$file.$ext;
389
            } else {
390
                $fn = $GLOBALS['sys_pluginsroot'].'/'.$plugin_name.'/site-content/'.$lang_code.'/'.$file.$ext;
391
            }
392
            if ( file_exists($fn) ) {
393
                // The custom file exists. 
394
                return $fn;
395
            } else {
396
                if ($lang_code == self::DEFAULT_LANG) {
397
                    // return empty content to avoid include error
398
                    return $GLOBALS['sys_incdir']."/".$lang_code."/others/empty.txt";
399
                } else {
400
                    // else try to find the file in the en_US directory
401
                    return $this->getContent($file, "en_US", $plugin_name, $ext);
402
                }
403
            }
404
        }
405
    }
406
407
    //result set handle for supported langauges
408
    var $language_res;
409
410
    /**
411
     * @return array pairs of language_code => Language
412
     */
413
    public function getLanguages() {
414
        $ret = array();
415
        foreach($this->allLanguages as $lang) {
416
            $text_array = $this->compileLanguage($lang);
417
            $ret[$lang] = $text_array['system']['locale_label'];
418
        }
419
        return $ret;
420
    }
421
422
    function getEncoding() {
423
        return $this->text_array['conf']['content_encoding'];
424
    }
425
426
    function getFont() {
427
        return $this->text_array['conf']['default_font'];
428
    }
429
430
    /** Returns list of loaded language files (for debugging) */
431
    function getLoadedLangageFiles() {
432
        return array_keys($this->file_array);
433
    }
434
    
435
    /**
436
     * Parse the Accept-Language header according to RFC 2616
437
     * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
438
     * @see RFC 1766
439
     *
440
     * Based on Jesse Skinner work
441
     * @see http://www.thefutureoftheweb.com/blog/use-accept-language-header#comment1
442
     * 
443
     * @param $accept_language string "en-us,en;q=0.8,fr;q=0.5,fr-fr;q=0.3"
444
     * @return array ('en-us' => 1, 'en' => 0.8, 'fr' => 0.5, 'fr-fr' => 0.3) ordered by score
445
     */
446
    function parseAcceptLanguage($accept_language) {
447
        $langs      = array();
448
        $lang_parse = array();
449
        
450
        // break up string into pieces (languages and q factors)
451
        preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', 
452
                       $accept_language,
453
                       $lang_parse);
454
        
455
        if (count($lang_parse[1])) {
456
            // create a list like "en" => 0.8
457
            $langs = array_combine($lang_parse[1], $lang_parse[4]);
458
            
459
            // set default to 1 for any without q factor
460
            foreach ($langs as $lang => $val) {
461
                if ($val === '') {
462
                    $langs[$lang] = 1;
463
                }
464
            }
465
            
466
            // sort list based on value
467
            arsort($langs, SORT_NUMERIC);
468
        }
469
        
470
        return $langs;
471
    }
472
    
473
    /**
474
     * Get the relevant language code "en_US" provided by Codendi 
475
     * depending on the Accept-Language header
476
     * 
477
     * According to RFC 2616, the separator between language abbreviation and 
478
     * country code is a dash (-) for Accept-Language header.
479
     * In Codendi, we use underscore (_).
480
     * 
481
     * @param $accept_language string "en-us,en;q=0.8,fr;q=0.5,fr-fr;q=0.3"
482
     * @return string en_US
483
     */
484
    function getLanguageFromAcceptLanguage($accept_language) {
485
        $relevant_language = $this->defaultLanguage;
486
        
487
        //extract language abbr and country codes from Codendi languages
488
        $provided_languages = array();
489
        foreach($this->allLanguages as $lang) {
490
            list($l,$c) = explode('_', $lang);
491
            $provided_languages[strtolower($l)][strtolower($c)] = $lang;
492
        }
493
        
494
        //Now do the same thing for accept_language, 
495
        $parse_accept_lang = $this->parseAcceptLanguage($accept_language);
496
        foreach($parse_accept_lang as $lang => $score) {
497
            $lang = explode('-', $lang);
498
            $l = strtolower($lang[0]);
499
            if (isset($provided_languages[$l])) {
500
                
501
                //We've just found a matching languages
502
                //check now for the country code
503
                if (isset($lang[1]) && isset($provided_languages[$l][strtolower($lang[1])])) {
504
                    
505
                    $relevant_language = $provided_languages[$l][strtolower($lang[1])];
506
                } else {
507
                    
508
                    //If there is no country code, then take the first one 
509
                    //provided by Codendi
510
                    $relevant_language = array_shift($provided_languages[strtolower($lang[0])]);
511
                }
512
                
513
                //We have our relevant language. We can go out
514
                break;
515
            }
516
        }
517
        
518
        return $relevant_language;
519
    }
520
    
521
    /**
522
     * @param $language string 'en_US'
523
     * @return bool true if the $language is supported
524
     */
525
    function isLanguageSupported($language) {
526
        return in_array($language, $this->allLanguages);
527
    }
528
529
    public function invalidateCache() {
530
        foreach(glob($this->getCacheDirectory().DIRECTORY_SEPARATOR.'*.php') as $file) {
531
            unlink($file);
532
        }
533
    }
534
535
    public function getCacheDirectory() {
536
        return ForgeConfig::get('codendi_cache_dir').DIRECTORY_SEPARATOR.'lang';
537
    }
538
}
539