This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Console application, which extracts or replaces strings for |
||
4 | * translation, which cannot be gettexted |
||
5 | * |
||
6 | * @package wordpress-i18n |
||
7 | * @subpackage tools |
||
8 | */ |
||
9 | // see: https://secure.php.net/tokenizer |
||
10 | if ( ! defined( 'T_ML_COMMENT' ) ) |
||
11 | define( 'T_ML_COMMENT', T_COMMENT ); |
||
12 | else |
||
13 | define( 'T_DOC_COMMENT', T_ML_COMMENT ); |
||
14 | |||
15 | $pomo = dirname( dirname( dirname( __FILE__ ) ) ) . '/src/wp-includes/pomo'; |
||
16 | require_once "$pomo/po.php"; |
||
17 | require_once "$pomo/mo.php"; |
||
18 | |||
19 | class NotGettexted { |
||
20 | var $enable_logging = false; |
||
21 | |||
22 | var $STAGE_OUTSIDE = 0; |
||
23 | var $STAGE_START_COMMENT = 1; |
||
24 | var $STAGE_WHITESPACE_BEFORE = 2; |
||
25 | var $STAGE_STRING = 3; |
||
26 | var $STAGE_WHITESPACE_AFTER = 4; |
||
27 | var $STAGE_END_COMMENT = 4; |
||
28 | |||
29 | var $commands = array('extract' => 'command_extract', 'replace' => 'command_replace' ); |
||
30 | |||
31 | |||
32 | function logmsg() { |
||
33 | $args = func_get_args(); |
||
34 | if ($this->enable_logging) error_log(implode(' ', $args)); |
||
35 | } |
||
36 | |||
37 | function stderr($msg, $nl=true) { |
||
38 | fwrite(STDERR, $msg.($nl? "\n" : "")); |
||
39 | } |
||
40 | |||
41 | function cli_die($msg) { |
||
42 | $this->stderr($msg); |
||
43 | exit(1); |
||
0 ignored issues
–
show
|
|||
44 | } |
||
45 | |||
46 | function unchanged_token($token, $s='') { |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
47 | return is_array($token)? $token[1] : $token; |
||
48 | } |
||
49 | |||
50 | function ignore_token($token, $s='') { |
||
0 ignored issues
–
show
|
|||
51 | return ''; |
||
52 | } |
||
53 | |||
54 | function list_php_files($dir) { |
||
55 | $files = array(); |
||
56 | $items = scandir( $dir ); |
||
57 | foreach ( (array) $items as $item ) { |
||
58 | $full_item = $dir . '/' . $item; |
||
59 | if ('.' == $item || '..' == $item) |
||
60 | continue; |
||
61 | if ('.php' == substr($item, -4)) |
||
62 | $files[] = $full_item; |
||
63 | if (is_dir($full_item)) |
||
64 | $files += array_merge($files, NotGettexted::list_php_files($full_item, $files)); |
||
65 | } |
||
66 | return $files; |
||
67 | } |
||
68 | |||
69 | |||
70 | function make_string_aggregator($global_array_name, $filename) { |
||
71 | $a = $global_array_name; |
||
72 | return create_function('$string, $comment_id, $line_number', 'global $'.$a.'; $'.$a.'[] = array($string, $comment_id, '.var_export($filename, true).', $line_number);'); |
||
73 | } |
||
74 | |||
75 | function make_mo_replacer($global_mo_name) { |
||
76 | $m = $global_mo_name; |
||
77 | return create_function('$token, $string', 'global $'.$m.'; return var_export($'.$m.'->translate($string), true);'); |
||
78 | } |
||
79 | |||
80 | function walk_tokens(&$tokens, $string_action, $other_action, $register_action=null) { |
||
81 | |||
82 | $current_comment_id = ''; |
||
83 | $current_string = ''; |
||
84 | $current_string_line = 0; |
||
85 | |||
86 | $result = ''; |
||
87 | $line = 1; |
||
88 | |||
89 | foreach($tokens as $token) { |
||
90 | if (is_array($token)) { |
||
91 | list($id, $text) = $token; |
||
92 | $line += substr_count($text, "\n"); |
||
93 | if ((T_ML_COMMENT == $id || T_COMMENT == $id) && preg_match('|/\*\s*(/?WP_I18N_[a-z_]+)\s*\*/|i', $text, $matches)) { |
||
94 | if ($this->STAGE_OUTSIDE == $stage) { |
||
0 ignored issues
–
show
The variable
$stage does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
95 | $stage = $this->STAGE_START_COMMENT; |
||
96 | $current_comment_id = $matches[1]; |
||
97 | $this->logmsg('start comment', $current_comment_id); |
||
98 | $result .= call_user_func($other_action, $token); |
||
99 | continue; |
||
100 | } |
||
101 | if ($this->STAGE_START_COMMENT <= $stage && $stage <= $this->STAGE_WHITESPACE_AFTER && '/'.$current_comment_id == $matches[1]) { |
||
102 | $stage = $this->STAGE_END_COMMENT; |
||
103 | $this->logmsg('end comment', $current_comment_id); |
||
104 | $result .= call_user_func($other_action, $token); |
||
105 | if (!is_null($register_action)) call_user_func($register_action, $current_string, $current_comment_id, $current_string_line); |
||
106 | continue; |
||
107 | } |
||
108 | } else if (T_CONSTANT_ENCAPSED_STRING == $id) { |
||
109 | if ($this->STAGE_START_COMMENT <= $stage && $stage < $this->STAGE_WHITESPACE_AFTER) { |
||
110 | eval('$current_string='.$text.';'); |
||
0 ignored issues
–
show
It is generally not recommended to use
eval unless absolutely required.
On one hand, ![]() |
|||
111 | $this->logmsg('string', $current_string); |
||
112 | $current_string_line = $line; |
||
113 | $result .= call_user_func($string_action, $token, $current_string); |
||
114 | continue; |
||
115 | } |
||
116 | } else if (T_WHITESPACE == $id) { |
||
117 | View Code Duplication | if ($this->STAGE_START_COMMENT <= $stage && $stage < $this->STAGE_STRING) { |
|
118 | $stage = $this->STAGE_WHITESPACE_BEFORE; |
||
119 | $this->logmsg('whitespace before'); |
||
120 | $result .= call_user_func($other_action, $token); |
||
121 | continue; |
||
122 | } |
||
123 | View Code Duplication | if ($this->STAGE_STRING < $stage && $stage < $this->STAGE_END_COMMENT) { |
|
124 | $stage = $this->STAGE_WHITESPACE_AFTER; |
||
125 | $this->logmsg('whitespace after'); |
||
126 | $result .= call_user_func($other_action, $token); |
||
127 | continue; |
||
128 | } |
||
129 | } |
||
130 | } |
||
131 | $result .= call_user_func($other_action, $token); |
||
132 | $stage = $this->STAGE_OUTSIDE; |
||
133 | $current_comment_id = ''; |
||
134 | $current_string = ''; |
||
135 | $current_string_line = 0; |
||
136 | } |
||
137 | return $result; |
||
138 | } |
||
139 | |||
140 | |||
141 | function command_extract() { |
||
142 | $args = func_get_args(); |
||
143 | $pot_filename = $args[0]; |
||
144 | View Code Duplication | if (isset($args[1]) && is_array($args[1])) |
|
145 | $filenames = $args[1]; |
||
146 | else |
||
147 | $filenames = array_slice($args, 1); |
||
148 | |||
149 | $global_name = '__entries_'.mt_rand(1, 1000); |
||
150 | $GLOBALS[$global_name] = array(); |
||
151 | |||
152 | foreach($filenames as $filename) { |
||
153 | $tokens = token_get_all(file_get_contents($filename)); |
||
154 | $aggregator = $this->make_string_aggregator($global_name, $filename); |
||
155 | $this->walk_tokens($tokens, array($this, 'ignore_token'), array($this, 'ignore_token'), $aggregator); |
||
156 | } |
||
157 | |||
158 | $potf = '-' == $pot_filename? STDOUT : @fopen($pot_filename, 'a'); |
||
159 | if (false === $potf) { |
||
160 | $this->cli_die("Couldn't open pot file: $pot_filename"); |
||
161 | } |
||
162 | |||
163 | foreach($GLOBALS[$global_name] as $item) { |
||
164 | @list($string, $comment_id, $filename, $line_number) = $item; |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
165 | $filename = isset($filename)? preg_replace('|^\./|', '', $filename) : ''; |
||
166 | $ref_line_number = isset($line_number)? ":$line_number" : ''; |
||
167 | $args = array( |
||
168 | 'singular' => $string, |
||
169 | 'extracted_comments' => "Not gettexted string $comment_id", |
||
170 | 'references' => array("$filename$ref_line_number"), |
||
171 | ); |
||
172 | $entry = new Translation_Entry($args); |
||
173 | fwrite($potf, "\n".PO::export_entry($entry)."\n"); |
||
174 | } |
||
175 | if ('-' != $pot_filename) fclose($potf); |
||
176 | return true; |
||
177 | } |
||
178 | |||
179 | function command_replace() { |
||
180 | $args = func_get_args(); |
||
181 | $mo_filename = $args[0]; |
||
182 | View Code Duplication | if (isset($args[1]) && is_array($args[1])) |
|
183 | $filenames = $args[1]; |
||
184 | else |
||
185 | $filenames = array_slice($args, 1); |
||
186 | |||
187 | $global_name = '__mo_'.mt_rand(1, 1000); |
||
188 | $GLOBALS[$global_name] = new MO(); |
||
189 | $replacer = $this->make_mo_replacer($global_name); |
||
190 | |||
191 | $res = $GLOBALS[$global_name]->import_from_file($mo_filename); |
||
192 | if (false === $res) { |
||
193 | $this->cli_die("Couldn't read MO file '$mo_filename'!"); |
||
194 | } |
||
195 | foreach($filenames as $filename) { |
||
196 | $source = file_get_contents($filename); |
||
197 | if ( strlen($source) > 150000 ) continue; |
||
198 | $tokens = token_get_all($source); |
||
199 | $new_file = $this->walk_tokens($tokens, $replacer, array($this, 'unchanged_token')); |
||
200 | $f = fopen($filename, 'w'); |
||
201 | fwrite($f, $new_file); |
||
202 | fclose($f); |
||
203 | } |
||
204 | return true; |
||
205 | } |
||
206 | |||
207 | function usage() { |
||
208 | $this->stderr('php i18n-comments.php COMMAND OUTPUTFILE INPUTFILES'); |
||
209 | $this->stderr('Extracts and replaces strings, which cannot be gettexted'); |
||
210 | $this->stderr('Commands:'); |
||
211 | $this->stderr(' extract POTFILE PHPFILES appends the strings to POTFILE'); |
||
212 | $this->stderr(' replace MOFILE PHPFILES replaces strings in PHPFILES with translations from MOFILE'); |
||
213 | } |
||
214 | |||
215 | function cli() { |
||
216 | global $argv, $commands; |
||
217 | if (count($argv) < 4 || !in_array($argv[1], array_keys($this->commands))) { |
||
218 | $this->usage(); |
||
219 | exit(1); |
||
0 ignored issues
–
show
The method
cli() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
220 | } |
||
221 | call_user_func_array(array($this, $this->commands[$argv[1]]), array_slice($argv, 2)); |
||
222 | } |
||
223 | } |
||
224 | |||
225 | // run the CLI only if the file |
||
226 | // wasn't included |
||
227 | $included_files = get_included_files(); |
||
228 | if ($included_files[0] == __FILE__) { |
||
229 | error_reporting(E_ALL); |
||
230 | $not_gettexted = new NotGettexted; |
||
231 | $not_gettexted->cli(); |
||
232 | } |
||
233 | |||
234 | ?> |
||
0 ignored issues
–
show
It is not recommended to use PHP's closing tag
?> in files other than templates.
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore. A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever. ![]() |
|||
235 |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.