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 |
||
0 ignored issues
–
show
|
|||
2 | /** |
||
3 | * @package Freemius |
||
4 | * @copyright Copyright (c) 2015, Freemius, Inc. |
||
5 | * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 |
||
6 | * @since 1.2.3 |
||
7 | */ |
||
8 | |||
9 | if ( ! defined( 'ABSPATH' ) ) { |
||
10 | exit; |
||
11 | } |
||
12 | |||
13 | /** |
||
14 | * Class FS_Options |
||
15 | * |
||
16 | * A wrapper class for handling network level and single site level options. |
||
17 | */ |
||
18 | class FS_Options { |
||
0 ignored issues
–
show
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.
You can fix this by adding a namespace to your class: namespace YourVendor;
class YourClass { }
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries. ![]() |
|||
19 | /** |
||
20 | * @var string |
||
21 | */ |
||
22 | private $_id; |
||
23 | |||
24 | /** |
||
25 | * @var array[string]FS_Options { |
||
26 | * @key string |
||
27 | * @value FS_Options |
||
28 | * } |
||
29 | */ |
||
30 | private static $_instances; |
||
31 | |||
32 | /** |
||
33 | * @var FS_Option_Manager Site level options. |
||
34 | */ |
||
35 | private $_options; |
||
36 | |||
37 | /** |
||
38 | * @var FS_Option_Manager Network level options. |
||
39 | */ |
||
40 | private $_network_options; |
||
41 | |||
42 | /** |
||
43 | * @var int The ID of the blog that is associated with the current site level options. |
||
44 | */ |
||
45 | private $_blog_id = 0; |
||
46 | |||
47 | /** |
||
48 | * @var bool |
||
49 | */ |
||
50 | private $_is_multisite; |
||
51 | |||
52 | /** |
||
53 | * @var string[] Lazy collection of params on the site level. |
||
54 | */ |
||
55 | private static $_SITE_OPTIONS_MAP; |
||
56 | |||
57 | /** |
||
58 | * @author Leo Fajardo (@leorw) |
||
59 | * @since 2.0.0 |
||
60 | * |
||
61 | * @param string $id |
||
62 | * @param bool $load |
||
63 | * |
||
64 | * @return FS_Options |
||
65 | */ |
||
66 | static function instance( $id, $load = false ) { |
||
0 ignored issues
–
show
|
|||
67 | if ( ! isset( self::$_instances[ $id ] ) ) { |
||
68 | self::$_instances[ $id ] = new FS_Options( $id, $load ); |
||
69 | } |
||
70 | |||
71 | return self::$_instances[ $id ]; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * @author Leo Fajardo (@leorw) |
||
76 | * @since 2.0.0 |
||
77 | * |
||
78 | * @param string $id |
||
79 | * @param bool $load |
||
80 | */ |
||
81 | private function __construct( $id, $load = false ) { |
||
82 | $this->_id = $id; |
||
83 | $this->_is_multisite = is_multisite(); |
||
84 | |||
85 | if ( $this->_is_multisite ) { |
||
86 | $this->_blog_id = get_current_blog_id(); |
||
87 | $this->_network_options = FS_Option_Manager::get_manager( $id, $load, true ); |
||
88 | } |
||
89 | |||
90 | $this->_options = FS_Option_Manager::get_manager( $id, $load, $this->_blog_id ); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Switch the context of the site level options manager. |
||
95 | * |
||
96 | * @author Vova Feldman (@svovaf) |
||
97 | * @since 2.0.0 |
||
98 | * |
||
99 | * @param $blog_id |
||
100 | */ |
||
101 | function set_site_blog_context( $blog_id ) { |
||
0 ignored issues
–
show
|
|||
102 | $this->_blog_id = $blog_id; |
||
103 | |||
104 | $this->_options = FS_Option_Manager::get_manager( $this->_id, false, $this->_blog_id ); |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * @author Leo Fajardo (@leorw) |
||
109 | * |
||
110 | * @param string $option |
||
111 | * @param mixed $default |
||
112 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
113 | * |
||
114 | * @return mixed |
||
115 | */ |
||
116 | function get_option( $option, $default = null, $network_level_or_blog_id = null ) { |
||
0 ignored issues
–
show
|
|||
117 | if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) { |
||
118 | return $this->_network_options->get_option( $option, $default ); |
||
119 | } |
||
120 | |||
121 | $site_options = $this->get_site_options( $network_level_or_blog_id ); |
||
0 ignored issues
–
show
It seems like
$network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 116 can also be of type boolean or null ; however, FS_Options::get_site_options() does only seem to accept integer , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
122 | |||
123 | return $site_options->get_option( $option, $default ); |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * @author Leo Fajardo (@leorw) |
||
128 | * @since 2.0.0 |
||
129 | * |
||
130 | * @param string $option |
||
131 | * @param mixed $value |
||
132 | * @param bool $flush |
||
133 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
134 | */ |
||
135 | function set_option( $option, $value, $flush = false, $network_level_or_blog_id = null ) { |
||
0 ignored issues
–
show
|
|||
136 | if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) { |
||
137 | $this->_network_options->set_option( $option, $value, $flush ); |
||
138 | } else { |
||
139 | $site_options = $this->get_site_options( $network_level_or_blog_id ); |
||
0 ignored issues
–
show
It seems like
$network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 135 can also be of type boolean or null ; however, FS_Options::get_site_options() does only seem to accept integer , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
140 | $site_options->set_option( $option, $value, $flush ); |
||
141 | } |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * @author Vova Feldman (@svovaf) |
||
146 | * @since 2.0.0 |
||
147 | * |
||
148 | * @param string $option |
||
149 | * @param bool $flush |
||
150 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
151 | */ |
||
152 | function unset_option( $option, $flush = false, $network_level_or_blog_id = null ) { |
||
0 ignored issues
–
show
|
|||
153 | if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) { |
||
154 | $this->_network_options->unset_option( $option, $flush ); |
||
155 | } else { |
||
156 | $site_options = $this->get_site_options( $network_level_or_blog_id ); |
||
0 ignored issues
–
show
It seems like
$network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 152 can also be of type boolean or null ; however, FS_Options::get_site_options() does only seem to accept integer , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
157 | $site_options->unset_option( $option, $flush ); |
||
158 | } |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * @author Leo Fajardo (@leorw) |
||
163 | * @since 2.0.0 |
||
164 | * |
||
165 | * @param bool $flush |
||
166 | * @param bool $network_level |
||
167 | */ |
||
168 | function load( $flush = false, $network_level = true ) { |
||
0 ignored issues
–
show
|
|||
169 | if ( $this->_is_multisite && $network_level ) { |
||
170 | $this->_network_options->load( $flush ); |
||
171 | } else { |
||
172 | $this->_options->load( $flush ); |
||
173 | } |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * @author Leo Fajardo (@leorw) |
||
178 | * @since 2.0.0 |
||
179 | * |
||
180 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, store both network storage and the current context blog storage. |
||
181 | */ |
||
182 | function store( $network_level_or_blog_id = null ) { |
||
0 ignored issues
–
show
|
|||
183 | if ( ! $this->_is_multisite || |
||
184 | false === $network_level_or_blog_id || |
||
185 | 0 == $network_level_or_blog_id || |
||
186 | is_null( $network_level_or_blog_id ) |
||
187 | ) { |
||
188 | $site_options = $this->get_site_options( $network_level_or_blog_id ); |
||
0 ignored issues
–
show
It seems like
$network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 182 can also be of type boolean or null ; however, FS_Options::get_site_options() does only seem to accept integer , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
189 | $site_options->store(); |
||
190 | } |
||
191 | |||
192 | if ( $this->_is_multisite && |
||
193 | ( is_null( $network_level_or_blog_id ) || true === $network_level_or_blog_id ) |
||
194 | ) { |
||
195 | $this->_network_options->store(); |
||
196 | } |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * @author Vova Feldman (@svovaf) |
||
201 | * @since 2.0.0 |
||
202 | * |
||
203 | * @param int|null|bool $network_level_or_blog_id |
||
204 | * @param bool $flush |
||
205 | */ |
||
206 | function clear( $network_level_or_blog_id = null, $flush = false ) { |
||
0 ignored issues
–
show
|
|||
207 | if ( ! $this->_is_multisite || |
||
208 | false === $network_level_or_blog_id || |
||
209 | is_null( $network_level_or_blog_id ) || |
||
210 | is_numeric( $network_level_or_blog_id ) |
||
211 | ) { |
||
212 | $site_options = $this->get_site_options( $network_level_or_blog_id ); |
||
0 ignored issues
–
show
It seems like
$network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 206 can also be of type boolean or null ; however, FS_Options::get_site_options() does only seem to accept integer , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
213 | $site_options->clear( $flush ); |
||
214 | } |
||
215 | |||
216 | if ( $this->_is_multisite && |
||
217 | ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) ) |
||
218 | ) { |
||
219 | $this->_network_options->clear( $flush ); |
||
220 | } |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * Migration script to the new storage data structure that is network compatible. |
||
225 | * |
||
226 | * IMPORTANT: |
||
227 | * This method should be executed only after it is determined if this is a network |
||
228 | * level compatible product activation. |
||
229 | * |
||
230 | * @author Vova Feldman (@svovaf) |
||
231 | * @since 2.0.0 |
||
232 | * |
||
233 | * @param int $blog_id |
||
234 | */ |
||
235 | function migrate_to_network( $blog_id = 0 ) { |
||
0 ignored issues
–
show
|
|||
236 | if ( ! $this->_is_multisite ) { |
||
237 | return; |
||
238 | } |
||
239 | |||
240 | $updated = false; |
||
241 | |||
242 | $site_options = $this->get_site_options( $blog_id ); |
||
243 | |||
244 | $keys = $site_options->get_options_keys(); |
||
245 | |||
246 | foreach ( $keys as $option ) { |
||
247 | if ( $this->is_site_option( $option ) || |
||
248 | // Don't move admin notices to the network storage. |
||
249 | in_array($option, array( |
||
250 | // Don't move admin notices to the network storage. |
||
251 | 'admin_notices', |
||
252 | // Don't migrate the module specific data, it will be migrated by the FS_Storage. |
||
253 | 'plugin_data', |
||
254 | 'theme_data', |
||
255 | )) |
||
256 | ) { |
||
257 | continue; |
||
258 | } |
||
259 | |||
260 | $option_updated = false; |
||
261 | |||
262 | // Migrate option to the network storage. |
||
263 | $site_option = $site_options->get_option( $option ); |
||
264 | |||
265 | if ( ! $this->_network_options->has_option( $option ) ) { |
||
266 | // Option not set on the network level, so just set it. |
||
267 | $this->_network_options->set_option( $option, $site_option, false ); |
||
268 | |||
269 | $option_updated = true; |
||
270 | } else { |
||
271 | // Option already set on the network level, so we need to merge it inelegantly. |
||
272 | $network_option = $this->_network_options->get_option( $option ); |
||
273 | |||
274 | if ( is_array( $network_option ) && is_array( $site_option ) ) { |
||
275 | // Option is an array. |
||
276 | foreach ( $site_option as $key => $value ) { |
||
277 | if ( ! isset( $network_option[ $key ] ) ) { |
||
278 | $network_option[ $key ] = $value; |
||
279 | |||
280 | $option_updated = true; |
||
281 | } else if ( is_array( $network_option[ $key ] ) && is_array( $value ) ) { |
||
282 | if ( empty( $network_option[ $key ] ) ) { |
||
283 | $network_option[ $key ] = $value; |
||
284 | |||
285 | $option_updated = true; |
||
286 | } else if ( empty( $value ) ) { |
||
0 ignored issues
–
show
This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. ![]() |
|||
287 | // Do nothing. |
||
288 | } else { |
||
289 | reset($value); |
||
290 | $first_key = key($value); |
||
291 | if ( $value[$first_key] instanceof FS_Entity ) { |
||
292 | // Merge entities by IDs. |
||
293 | $network_entities_ids = array(); |
||
294 | foreach ( $network_option[ $key ] as $entity ) { |
||
295 | $network_entities_ids[ $entity->id ] = true; |
||
296 | } |
||
297 | |||
298 | foreach ( $value as $entity ) { |
||
299 | if ( ! isset( $network_entities_ids[ $entity->id ] ) ) { |
||
300 | $network_option[ $key ][] = $entity; |
||
301 | |||
302 | $option_updated = true; |
||
303 | } |
||
304 | } |
||
305 | } |
||
306 | } |
||
307 | } |
||
308 | } |
||
309 | } |
||
310 | |||
311 | if ( $option_updated ) { |
||
312 | $this->_network_options->set_option( $option, $network_option, false ); |
||
313 | } |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * Remove the option from site level storage. |
||
318 | * |
||
319 | * IMPORTANT: |
||
320 | * The line below is intentionally commented since we want to preserve the option |
||
321 | * on the site storage level for "downgrade compatibility". Basically, if the user |
||
322 | * will downgrade to an older version of the plugin with the prev storage structure, |
||
323 | * it will continue working. |
||
324 | * |
||
325 | * @todo After a few releases we can remove this. |
||
326 | */ |
||
327 | // $site_options->unset_option($option, false); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
73% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
328 | |||
329 | if ( $option_updated ) { |
||
330 | $updated = true; |
||
331 | } |
||
332 | } |
||
333 | |||
334 | if ( ! $updated ) { |
||
335 | return; |
||
336 | } |
||
337 | |||
338 | // Update network level storage. |
||
339 | $this->_network_options->store(); |
||
340 | // $site_options->store(); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
72% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
341 | } |
||
342 | |||
343 | |||
344 | #-------------------------------------------------------------------------------- |
||
345 | #region Helper Methods |
||
346 | #-------------------------------------------------------------------------------- |
||
347 | |||
348 | /** |
||
349 | * We don't want to load the map right away since it's not even needed in a non-MS environment. |
||
350 | * |
||
351 | * @author Vova Feldman (@svovaf) |
||
352 | * @since 2.0.0 |
||
353 | */ |
||
354 | private static function load_site_options_map() { |
||
355 | self::$_SITE_OPTIONS_MAP = array( |
||
0 ignored issues
–
show
It seems like
array('sites' => true, '...ctive_plugins' => true) of type array<string,boolean,{"s...ve_plugins":"boolean"}> is incompatible with the declared type array<integer,string> of property $_SITE_OPTIONS_MAP .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
356 | 'sites' => true, |
||
357 | 'theme_sites' => true, |
||
358 | 'unique_id' => true, |
||
359 | 'active_plugins' => true, |
||
360 | ); |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * @author Vova Feldman (@svovaf) |
||
365 | * @since 2.0.0 |
||
366 | * |
||
367 | * @param string $option |
||
368 | * |
||
369 | * @return bool |
||
370 | */ |
||
371 | private function is_site_option( $option ) { |
||
372 | if ( WP_FS__ACCOUNTS_OPTION_NAME != $this->_id ) { |
||
373 | return false; |
||
374 | } |
||
375 | |||
376 | if ( ! isset( self::$_SITE_OPTIONS_MAP ) ) { |
||
377 | self::load_site_options_map(); |
||
378 | } |
||
379 | |||
380 | return isset( self::$_SITE_OPTIONS_MAP[ $option ] ); |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * @author Vova Feldman (@svovaf) |
||
385 | * @since 2.0.0 |
||
386 | * |
||
387 | * @param int $blog_id |
||
388 | * |
||
389 | * @return FS_Option_Manager |
||
390 | */ |
||
391 | private function get_site_options( $blog_id = 0 ) { |
||
392 | if ( 0 == $blog_id || $blog_id == $this->_blog_id ) { |
||
393 | return $this->_options; |
||
394 | } |
||
395 | |||
396 | return FS_Option_Manager::get_manager( $this->_id, true, $blog_id ); |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * Check if an option should be stored on the MS network storage. |
||
401 | * |
||
402 | * @author Vova Feldman (@svovaf) |
||
403 | * @since 2.0.0 |
||
404 | * |
||
405 | * @param string $option |
||
406 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
407 | * |
||
408 | * @return bool |
||
409 | */ |
||
410 | private function should_use_network_storage( $option, $network_level_or_blog_id = null ) { |
||
411 | if ( ! $this->_is_multisite ) { |
||
412 | // Not a multisite environment. |
||
413 | return false; |
||
414 | } |
||
415 | |||
416 | if ( is_numeric( $network_level_or_blog_id ) ) { |
||
417 | // Explicitly asked to use a specified blog storage. |
||
418 | return false; |
||
419 | } |
||
420 | |||
421 | if ( is_bool( $network_level_or_blog_id ) ) { |
||
422 | // Explicitly specified whether should use the network or blog level storage. |
||
423 | return $network_level_or_blog_id; |
||
424 | } |
||
425 | |||
426 | // Determine which storage to use based on the option. |
||
427 | return ! $this->is_site_option( $option ); |
||
428 | } |
||
429 | |||
430 | #endregion |
||
431 | } |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.