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 | * This is an alternative implementation of the MessageCommand class, designed to work with CiiMS' modules and themes |
||
4 | */ |
||
5 | Yii::import('cii.commands.CiiConsoleCommand'); |
||
6 | class CiiMessageCommand extends CiiConsoleCommand |
||
0 ignored issues
–
show
|
|||
7 | { |
||
8 | |||
9 | /** |
||
10 | * The configuration object |
||
11 | * @var array _$config |
||
12 | */ |
||
13 | private $_config = array(); |
||
14 | |||
15 | /** |
||
16 | * The messages that should be translated |
||
17 | * @var array $_messages |
||
18 | */ |
||
19 | private $_messages = array(); |
||
20 | |||
21 | /** |
||
22 | * The stirng that should be used for translations |
||
23 | * @var string $_translator |
||
24 | */ |
||
25 | private $_translator = 'Yii::t'; |
||
26 | |||
27 | /** |
||
28 | * Default args |
||
29 | * @return array |
||
30 | */ |
||
31 | private function getArgs() |
||
32 | { |
||
33 | return array( |
||
34 | 'type' => 'core', |
||
35 | 'sourcePath' => Yii::getPathOfAlias('application').DS, |
||
36 | 'messagePath' => Yii::getPathOfAlias('application.messages').DS, |
||
37 | 'languages' => array('en_us'), |
||
38 | 'fileTypes' => array('php'), |
||
39 | 'overwrite' => true, |
||
40 | 'sort' => true, |
||
41 | 'removeOld' => false, |
||
42 | 'exclude' => array( |
||
43 | 'assets', |
||
44 | 'css', |
||
45 | 'js', |
||
46 | 'images', |
||
47 | '.svn', |
||
48 | '.gitignore', |
||
49 | '.git', |
||
50 | 'yiilite.php', |
||
51 | 'yiit.php', |
||
52 | 'i18n/data', |
||
53 | 'messages', |
||
54 | 'vendor', |
||
55 | 'tests', |
||
56 | 'runtime' |
||
57 | ) |
||
58 | ); |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Init method |
||
63 | */ |
||
64 | public function init() |
||
65 | { |
||
66 | $this->_config = $this->getArgs(); |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * Generates translation files for a given mtheme |
||
71 | * @param string $name The name of the theme to generate translations for |
||
72 | */ |
||
73 | public function actionThemes($name=NULL) |
||
74 | { |
||
75 | if ($name === NULL) |
||
76 | $this->usageError('A theme was not specified for translations'); |
||
77 | |||
78 | $this->_config['type'] = 'theme'; |
||
79 | array_push($this->_config['exclude'], 'modules'); |
||
80 | $this->_config['sourcePath'] .= '..'.DS.'themes' . DS . $name . DS; |
||
81 | $this->_config['messagePath'] = $this->_config['sourcePath'].'messages'; |
||
82 | $this->execute(); |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * Generates translation files for a given module |
||
87 | * @param string $name The name of the module to generate translations for |
||
88 | */ |
||
89 | public function actionModules($name=NULL) |
||
90 | { |
||
91 | if ($name === NULL) |
||
92 | $this->usageError('A module was not specified for translations'); |
||
93 | |||
94 | $this->_config['type'] = 'module'; |
||
95 | array_push($this->_config['exclude'], 'themes'); |
||
96 | unset($this->_config['exclude']['modules']); |
||
97 | $this->_config['sourcePath'] = Yii::getPathOfAlias('application.modules') . DS . $name . DS; |
||
98 | $this->_config['messagePath'] = $this->_config['sourcePath'].'messages'; |
||
99 | $this->execute($this->_config); |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * Defualt action |
||
104 | */ |
||
105 | public function actionIndex() |
||
106 | { |
||
107 | array_push($this->_config['exclude'], 'modules'); |
||
108 | array_push($this->_config['exclude'], 'themes'); |
||
109 | return $this->execute(); |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Execute the action. |
||
114 | */ |
||
115 | private function execute() |
||
116 | { |
||
117 | // Validate the configuration |
||
118 | extract($this->_config); |
||
119 | $this->validateConfig(); |
||
120 | |||
121 | // Determine the messages |
||
122 | foreach($this->getFiles() as $file) |
||
123 | $this->_messages = array_merge_recursive($this->_messages,$this->extractMessages($file,$this->_translator)); |
||
124 | |||
125 | foreach($languages as $language) |
||
126 | { |
||
127 | $dir = $messagePath.DS.$language; |
||
128 | |||
129 | $this->createDirectory($dir); |
||
130 | |||
131 | foreach ($this->_messages as $category=>$msgs) |
||
132 | { |
||
133 | $msgs = array_values(array_unique($msgs)); |
||
134 | |||
135 | $dir = $this->_config['messagePath'].DS.$language; |
||
136 | |||
137 | if ($this->_config['type'] == 'theme') |
||
138 | { |
||
139 | $data = explode('.', $category); |
||
140 | unset($data[0]); |
||
141 | $dirPath = implode(DS, $data); |
||
142 | } |
||
143 | else if ($this->_config['type'] == 'module') |
||
144 | { |
||
145 | $data = explode('.', $category); |
||
146 | unset($data[0]); |
||
147 | unset($data[1]); |
||
148 | $dirPath = implode(DS, $data); |
||
149 | } |
||
150 | else |
||
151 | $dirPath = implode(DS, explode('.', $category)); |
||
152 | |||
153 | if (empty($dirPath)) |
||
154 | continue; |
||
155 | |||
156 | $this->createDirectory($dir . DS . $dirPath); |
||
157 | $this->createDirectory($dir . DS . $language); |
||
158 | |||
159 | $this->generateMessageFile($msgs,$dir.DS.$dirPath.'.php',$overwrite,$removeOld,$sort); |
||
160 | } |
||
161 | } |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Creates a directory at the given path |
||
166 | * @param string $directory |
||
167 | * @return boolean |
||
168 | */ |
||
169 | private function createDirectory($directory) |
||
170 | { |
||
171 | if (!is_dir($directory)) |
||
172 | { |
||
173 | if (!mkdir($directory, 0777, true)) |
||
174 | $this->usageError('The directory ' . $directory .' could not be created. Please make sure this process has write access to this directory.'); |
||
175 | } |
||
176 | |||
177 | return true; |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Retrieves the files that should be translated |
||
182 | * @return array $files |
||
183 | */ |
||
184 | private function getFiles() |
||
185 | { |
||
186 | extract($this->_config); |
||
187 | $files = CFileHelper::findFiles(realpath($sourcePath),array( |
||
188 | 'fileTypes' => $fileTypes, |
||
189 | 'exclude' => $exclude |
||
190 | )); |
||
191 | |||
192 | // Strip out all extensions |
||
193 | foreach ($files as $k=>$file) |
||
194 | { |
||
195 | if (strpos($file, 'extensions') !== false) |
||
196 | unset($files[$k]); |
||
197 | } |
||
198 | |||
199 | reset($files); |
||
200 | |||
201 | return $files; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Does basic validation on the configuration options |
||
206 | */ |
||
207 | private function validateConfig() |
||
208 | { |
||
209 | extract($this->_config); |
||
210 | |||
211 | if(!isset($sourcePath,$messagePath,$languages)) |
||
212 | $this->usageError('The configuration file must specify "sourcePath", "messagePath" and "languages".'); |
||
213 | |||
214 | if(!is_dir($sourcePath)) |
||
215 | $this->usageError("The source path $sourcePath is not a valid directory."); |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $sourcePath instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
216 | |||
217 | if(!is_dir($messagePath)) |
||
218 | $this->usageError("The message path $messagePath is not a valid directory."); |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $messagePath instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
219 | |||
220 | if(empty($languages)) |
||
221 | $this->usageError("Languages cannot be empty."); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
Languages cannot be empty. does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
222 | } |
||
223 | |||
224 | /** |
||
225 | * @param string $translator |
||
226 | */ |
||
227 | protected function extractMessages($fileName,$translator) |
||
228 | { |
||
229 | $subject=file_get_contents($fileName); |
||
230 | $messages=array(); |
||
231 | if(!is_array($translator)) |
||
232 | $translator=array($translator); |
||
233 | |||
234 | foreach ($translator as $currentTranslator) |
||
235 | { |
||
236 | $n=preg_match_all('/\b'.$currentTranslator.'\s*\(\s*(\'[\w.\/]*?(?<!\.)\'|"[\w.]*?(?<!\.)")\s*,\s*(\'.*?(?<!\\\\)\'|".*?(?<!\\\\)")\s*[,\)]/s',$subject,$matches,PREG_SET_ORDER); |
||
237 | |||
238 | for($i=0; $i<$n; ++$i) |
||
239 | { |
||
240 | if(($pos=strpos($matches[$i][1],'.'))!==false) |
||
241 | { |
||
242 | if (strpos($matches[$i][1],'Dashboard')!==false || strpos($matches[$i][1],'Hybridauth')!==false || strpos($matches[$i][1],'Install')!==false) |
||
243 | $category='module.'.substr($matches[$i][1],1,-1); |
||
244 | else if (strpos($matches[$i][1],'Theme')!==false) |
||
245 | $category=$matches[$i][1]; |
||
246 | else |
||
247 | $category=substr($matches[$i][1],$pos+1,-1); |
||
248 | } |
||
249 | else |
||
250 | $category=substr($matches[$i][1],1,-1); |
||
251 | |||
252 | |||
253 | $message=$matches[$i][2]; |
||
254 | |||
255 | $category = str_replace("'", '', $category); |
||
256 | |||
257 | // This is how Yii does it |
||
258 | $messages[$category][]=eval("return $message;"); // use eval to eliminate quote escape |
||
0 ignored issues
–
show
It is generally not recommended to use
eval unless absolutely required.
On one hand, ![]() As per coding-style, please use concatenation or
sprintf for the variable $message instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
259 | } |
||
260 | } |
||
261 | |||
262 | return $messages; |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * @param string $fileName |
||
267 | * @param boolean $overwrite |
||
268 | * @param boolean $removeOld |
||
269 | * @param boolean $sort |
||
270 | */ |
||
271 | protected function generateMessageFile($messages,$fileName,$overwrite,$removeOld,$sort) |
||
272 | { |
||
273 | echo "Saving messages to $fileName..."; |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $fileName instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
274 | if(is_file($fileName)) |
||
275 | { |
||
276 | $translated=require($fileName); |
||
277 | sort($messages); |
||
278 | ksort($translated); |
||
279 | if(array_keys($translated)==$messages) |
||
280 | { |
||
281 | echo "nothing new...skipped.\n"; |
||
282 | return; |
||
283 | } |
||
284 | |||
285 | $merged=array(); |
||
286 | $untranslated=array(); |
||
287 | |||
288 | foreach($messages as $message) |
||
289 | { |
||
290 | if(array_key_exists($message,$translated) && strlen($translated[$message])>0) |
||
291 | $merged[$message]=$translated[$message]; |
||
292 | else |
||
293 | $untranslated[]=$message; |
||
294 | } |
||
295 | |||
296 | ksort($merged); |
||
297 | sort($untranslated); |
||
298 | $todo=array(); |
||
299 | |||
300 | foreach($untranslated as $message) |
||
301 | $todo[$message]=''; |
||
302 | |||
303 | ksort($translated); |
||
304 | |||
305 | foreach($translated as $message=>$translation) |
||
306 | { |
||
307 | if(!isset($merged[$message]) && !isset($todo[$message]) && !$removeOld) |
||
308 | { |
||
309 | if(substr($translation,0,2)==='@@' && substr($translation,-2)==='@@') |
||
310 | $todo[$message]=$translation; |
||
311 | else if ($translation == '') |
||
312 | $todo[$message] = ''; |
||
313 | else |
||
314 | $todo[$message]='@@'.$translation.'@@'; |
||
315 | } |
||
316 | } |
||
317 | |||
318 | $merged=array_merge($todo,$merged); |
||
319 | |||
320 | if($sort) |
||
321 | ksort($merged); |
||
322 | |||
323 | if($overwrite === false) |
||
324 | $fileName.='.merged'; |
||
325 | |||
326 | echo "translation merged.\n"; |
||
327 | } |
||
328 | else |
||
329 | { |
||
330 | $merged=array(); |
||
331 | foreach($messages as $message) |
||
332 | $merged[$message]=''; |
||
333 | |||
334 | ksort($merged); |
||
335 | echo "saved.\n"; |
||
336 | } |
||
337 | $array=str_replace("\r",'',var_export($merged,true)); |
||
338 | $content=<<<EOD |
||
339 | <?php |
||
340 | /** |
||
341 | * Message translations. |
||
342 | * |
||
343 | * This file is automatically generated by 'yiic ciimessage' command. |
||
344 | * It contains the localizable messages extracted from source code. |
||
345 | * You may modify this file by translating the extracted messages. |
||
346 | * |
||
347 | * Each array element represents the translation (value) of a message (key). |
||
348 | * If the value is empty, the message is considered as not translated. |
||
349 | * Messages that no longer need translation will have their translations |
||
350 | * enclosed between a pair of '@@' marks. |
||
351 | * |
||
352 | * Message string can be used with plural forms format. Check i18n section |
||
353 | * of the guide for details. |
||
354 | * |
||
355 | * NOTE, this file must be saved in UTF-8 encoding. |
||
356 | */ |
||
357 | return $array; |
||
358 | |||
359 | EOD; |
||
360 | file_put_contents($fileName, $content); |
||
361 | } |
||
362 | } |
||
363 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.