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 | namespace mindplay; |
||
4 | |||
5 | use Closure; |
||
6 | use ComposerLocator; |
||
7 | use ReflectionFunction; |
||
8 | |||
9 | /** |
||
10 | * This class acts as a pseudo-namespace for translation functions |
||
11 | * |
||
12 | * Language codes are two-letter ISO-639-1 language codes, such as "en", "da", "es", etc. |
||
13 | * |
||
14 | * Translation domain names take the form "{vendor}/{package}", where the package name |
||
15 | * may contain several names separated by slashes. |
||
16 | * |
||
17 | * @link https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes |
||
18 | */ |
||
19 | abstract class lang |
||
20 | { |
||
21 | /** |
||
22 | * @var string default language code |
||
23 | */ |
||
24 | const DEFAULT_LANGUAGE = "en"; |
||
25 | |||
26 | /** |
||
27 | * Use this property to set an error callback - you can use this for error reporting in test-suites. |
||
28 | * |
||
29 | * @var callable function ($message) : void |
||
30 | */ |
||
31 | public static $on_error; |
||
32 | |||
33 | /** |
||
34 | * @var string active language code |
||
35 | */ |
||
36 | protected static $code = self::DEFAULT_LANGUAGE; |
||
37 | |||
38 | /** |
||
39 | * @var (string|callable)[][] map where "{domain}/{code}" => translation strings or callables |
||
40 | */ |
||
41 | protected static $lang = []; |
||
42 | |||
43 | /** |
||
44 | * @var string[] map where "{domain}" or "{domain}/{code}" => absolute path to language file |
||
45 | */ |
||
46 | protected static $paths = []; |
||
47 | |||
48 | /** |
||
49 | * Change the current active language code. |
||
50 | * |
||
51 | * @param string $code two-letter ISO-639-1 language code (such as "en", "da", "es", etc.) |
||
52 | * |
||
53 | * @link https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes |
||
54 | */ |
||
55 | 1 | public static function set($code) |
|
56 | { |
||
57 | 1 | self::$code = $code; |
|
58 | 1 | } |
|
59 | |||
60 | /** |
||
61 | * Get the current active language code. |
||
62 | * |
||
63 | * @see set() |
||
64 | */ |
||
65 | 1 | public static function get() |
|
66 | { |
||
67 | 1 | return self::$code; |
|
68 | } |
||
69 | |||
70 | /** |
||
71 | * Register the physical base path of language files for a given translation domain name. |
||
72 | * |
||
73 | * @param string $domain translation domain name |
||
74 | * @param string $path absolute path to language directory (or base filename, without ".php") |
||
75 | */ |
||
76 | 1 | public static function register($domain, $path) |
|
77 | { |
||
78 | 1 | self::$paths[$domain] = $path; |
|
79 | 1 | } |
|
80 | |||
81 | /** |
||
82 | * Translate the given text in the given domain and substitute the given tokens. |
||
83 | * |
||
84 | * @param string $domain translation domain name |
||
85 | * @param string $text english text |
||
86 | * @param array|null $tokens map where token name => replacement string |
||
87 | * |
||
88 | * @return string |
||
89 | */ |
||
90 | 1 | public static function text($domain, $text, array $tokens = null) |
|
91 | { |
||
92 | 1 | return self::translate(self::$code, $domain, $text, $tokens); |
|
93 | } |
||
94 | |||
95 | /** |
||
96 | * Obtain a translation callback for a given domain, optionally for a specific language. |
||
97 | * |
||
98 | * The returned function has the following signature: |
||
99 | * |
||
100 | * function (string $text, array $tokens) : string |
||
101 | * |
||
102 | * This may be useful in a view/template, for example, so you don't have to repeat the |
||
103 | * domain name for every call. It may also be useful to inject this function as a dependency. |
||
104 | * |
||
105 | * @param string $domain translation domain name |
||
106 | * @param string|null $code optional language code (defaults to the current language) |
||
107 | * |
||
108 | * @return callable function ($text, array $tokens) : string |
||
109 | */ |
||
110 | 1 | public static function domain($domain, $code = null) |
|
111 | { |
||
112 | return function ($text, array $tokens = null) use ($domain, $code) { |
||
113 | 1 | return self::translate($code ?: self::$code, $domain, $text, $tokens); |
|
114 | 1 | }; |
|
115 | } |
||
116 | |||
117 | /** |
||
118 | * This is the lowest-level function, which requires every parameter to be given explicitly. |
||
119 | * |
||
120 | * @param string $code two-letter ISO-639-1 language code |
||
121 | * @param string $domain translation domain name |
||
122 | * @param string $text english text |
||
123 | * @param array $tokens map where token name => replacement string |
||
124 | * |
||
125 | * @return string |
||
126 | */ |
||
127 | 1 | public static function translate($code, $domain, $text, array $tokens = null) |
|
128 | { |
||
129 | 1 | $name = "{$domain}/{$code}"; |
|
130 | |||
131 | 1 | if (! isset(self::$lang[$name])) { |
|
132 | 1 | self::load($name); |
|
133 | } |
||
134 | |||
135 | 1 | $has_template = isset(self::$lang[$name][$text]); |
|
136 | |||
137 | 1 | if (self::$on_error && !$has_template) { |
|
138 | 1 | call_user_func(self::$on_error, "missing translation of '{$text}' for: {$name}"); |
|
139 | } |
||
140 | |||
141 | 1 | $template = $has_template |
|
142 | 1 | ? self::$lang[$name][$text] |
|
143 | 1 | : $text; |
|
144 | |||
145 | 1 | if ($template instanceof Closure) { |
|
146 | // perform translation with a user-defined function: |
||
147 | |||
148 | 1 | $args = []; |
|
149 | |||
150 | 1 | if ($tokens) { |
|
151 | 1 | $func = new ReflectionFunction($template); |
|
152 | |||
153 | 1 | foreach ($func->getParameters() as $param) { |
|
154 | 1 | $args[] = isset($tokens[$param->name]) |
|
155 | 1 | ? $tokens[$param->name] |
|
156 | 1 | : "{{$param->name}}"; // ignore missing tokens |
|
157 | } |
||
158 | } |
||
159 | |||
160 | 1 | return call_user_func_array($template, $args); |
|
161 | } else { |
||
162 | 1 | if ($tokens) { |
|
163 | // perform translation using simple string substitution: |
||
164 | |||
165 | 1 | return strtr( |
|
166 | 1 | $template, |
|
0 ignored issues
–
show
|
|||
167 | 1 | array_combine( |
|
168 | 1 | array_map( |
|
169 | 1 | function ($key) { |
|
170 | 1 | return "{{$key}}"; |
|
171 | 1 | }, |
|
172 | 1 | array_keys($tokens) |
|
173 | ), |
||
174 | 1 | $tokens |
|
175 | ) |
||
176 | ); |
||
177 | } else { |
||
178 | // no token substitution required: |
||
179 | |||
180 | 1 | return $template; |
|
0 ignored issues
–
show
The return type of
return $template; (callable ) is incompatible with the return type documented by mindplay\lang::translate of type string .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
181 | } |
||
182 | } |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Reset the internal state of the language registry. |
||
187 | * |
||
188 | * This may be useful for unit-testing or other special situations. |
||
189 | */ |
||
190 | 1 | public static function reset() |
|
191 | { |
||
192 | 1 | self::$code = lang::DEFAULT_LANGUAGE; |
|
193 | 1 | self::$lang = []; |
|
194 | 1 | self::$paths = []; |
|
195 | 1 | } |
|
196 | |||
197 | /** |
||
198 | * Internally find and load a given language file. |
||
199 | * |
||
200 | * @param string $name full language file base name, e.g. "{domain}/{code}" |
||
201 | */ |
||
202 | 1 | protected static function load($name) |
|
203 | { |
||
204 | 1 | $domain_names = explode('/', $name); |
|
205 | |||
206 | 1 | while (count($domain_names)) { |
|
207 | 1 | $parent_domain = implode('/', $domain_names); |
|
208 | |||
209 | 1 | if (isset(self::$paths[$parent_domain])) { |
|
210 | 1 | $path = self::$paths[$parent_domain] . substr($name, strlen($parent_domain)) . '.php'; |
|
211 | |||
212 | 1 | if (file_exists($path)) { |
|
213 | 1 | self::$lang[$name] = require $path; |
|
214 | |||
215 | 1 | break; |
|
216 | } |
||
217 | } |
||
218 | |||
219 | 1 | if (count($domain_names) === 2 && ComposerLocator::isInstalled($parent_domain)) { |
|
0 ignored issues
–
show
The method
isInstalled() does not seem to exist on object<ComposerLocator> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
220 | // attempt mapping by convention |
||
221 | |||
222 | 1 | $path = ComposerLocator::getPath($parent_domain) |
|
0 ignored issues
–
show
The method
getPath() does not seem to exist on object<ComposerLocator> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
223 | 1 | . "/lang" . substr($name, strlen($parent_domain)) . '.php'; |
|
224 | |||
225 | 1 | if (file_exists($path)) { |
|
226 | 1 | self::$lang[$name] = require $path; |
|
227 | |||
228 | 1 | break; |
|
229 | } |
||
230 | } |
||
231 | |||
232 | 1 | array_pop($domain_names); |
|
233 | } |
||
234 | |||
235 | 1 | if (! isset(self::$lang[$name])) { |
|
236 | 1 | self::$lang[$name] = []; // no translation file available |
|
237 | |||
238 | 1 | if (self::$on_error) { |
|
239 | 1 | call_user_func(self::$on_error, "no translation file found for: {$name}"); |
|
240 | } |
||
241 | } |
||
242 | 1 | } |
|
243 | } |
||
244 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: