These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @package WordPress Dynamic CSS |
||
4 | * @version 1.0.5 |
||
5 | * @author Askupa Software <[email protected]> |
||
6 | * @link https://github.com/askupasoftware/wp-dynamic-css |
||
7 | * @copyright 2016 Askupa Software |
||
8 | */ |
||
9 | |||
10 | /** |
||
11 | * Dynamic CSS Compiler Utility Class |
||
12 | * |
||
13 | * |
||
14 | * Dynamic CSS Syntax |
||
15 | * ------------------ |
||
16 | * <pre> |
||
17 | * body {color: $body_color;} |
||
18 | * </pre> |
||
19 | * In the above example, the variable $body_color is replaced by a value |
||
20 | * retrieved by the value callback function. The function is passed the variable |
||
21 | * name without the dollar sign, which can be used with get_option() or |
||
22 | * get_theme_mod() etc. |
||
23 | */ |
||
24 | class DynamicCSSCompiler |
||
25 | { |
||
26 | /** |
||
27 | * @var Singleton The reference to *Singleton* instance of this class |
||
28 | */ |
||
29 | private static $instance; |
||
30 | |||
31 | /** |
||
32 | * @var array The list of dynamic styles paths to compile |
||
33 | */ |
||
34 | private $stylesheets = array(); |
||
35 | |||
36 | /** |
||
37 | * @var array The list of registered callbacks |
||
38 | */ |
||
39 | private $callbacks = array(); |
||
40 | |||
41 | /** |
||
42 | * @var aray The list of registered filters |
||
43 | */ |
||
44 | private $filters = array(); |
||
45 | |||
46 | /** |
||
47 | * Returns the *Singleton* instance of this class. |
||
48 | * |
||
49 | * @return Singleton The *Singleton* instance. |
||
50 | */ |
||
51 | public static function get_instance() |
||
52 | { |
||
53 | if (null === static::$instance) |
||
54 | { |
||
55 | static::$instance = new static(); |
||
0 ignored issues
–
show
|
|||
56 | } |
||
57 | return static::$instance; |
||
0 ignored issues
–
show
|
|||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Enqueue the stylesheets that are registered to be loaded externally |
||
62 | */ |
||
63 | public function enqueue_styles() |
||
64 | { |
||
65 | foreach( $this->stylesheets as $stylesheet ) |
||
66 | { |
||
67 | if( !$stylesheet['print'] && $this->callback_exists( $stylesheet['handle'] ) ) |
||
68 | { |
||
69 | wp_enqueue_style( |
||
70 | 'wp-dynamic-css-'.$stylesheet['handle'], |
||
71 | esc_url_raw( add_query_arg(array( |
||
72 | 'action' => 'wp_dynamic_css', |
||
73 | 'handle' => $stylesheet['handle'] |
||
74 | ), admin_url( 'admin-ajax.php'))) |
||
75 | ); |
||
76 | } |
||
77 | } |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Print the stylesheets that are registered to be printed to the document head |
||
82 | */ |
||
83 | public function print_styles() |
||
84 | { |
||
85 | foreach( $this->stylesheets as $stylesheet ) |
||
86 | { |
||
87 | if( $stylesheet['print'] && $this->callback_exists( $stylesheet['handle'] ) ) |
||
88 | { |
||
89 | $compiled_css = $this->get_compiled_style( $stylesheet ); |
||
90 | |||
91 | echo "<style id=\"wp-dynamic-css-".$stylesheet['handle']."\">\n"; |
||
92 | include 'style.phtml'; |
||
93 | echo "\n</style>\n"; |
||
94 | } |
||
95 | } |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * This is the AJAX callback used for loading styles externally via an http |
||
100 | * request. |
||
101 | */ |
||
102 | public function ajax_callback() |
||
103 | { |
||
104 | header( "Content-type: text/css; charset: UTF-8" ); |
||
105 | $handle = filter_input( INPUT_GET, 'handle' ); |
||
106 | |||
107 | foreach( $this->stylesheets as $stylesheet ) |
||
108 | { |
||
109 | if( $handle === $stylesheet['handle'] ) |
||
110 | { |
||
111 | $compiled_css = $this->get_compiled_style( $stylesheet ); |
||
112 | include 'style.phtml'; |
||
113 | } |
||
114 | } |
||
115 | |||
116 | wp_die(); |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Add a style path to the pool of styles to be compiled |
||
121 | * |
||
122 | * @param string $handle The stylesheet's name/id |
||
123 | * @param string $path The absolute path to the dynamic style |
||
124 | * @param boolean $print Whether to print the compiled CSS to the document |
||
125 | * head, or include it as an external CSS file |
||
126 | * @param boolean $minify Whether to minify the CSS output |
||
127 | * @param boolean $cache Whether to store the compiled version of this |
||
128 | * stylesheet in cache to avoid compilation on every page load. |
||
129 | */ |
||
130 | public function enqueue_style( $handle, $path, $print, $minify, $cache ) |
||
131 | { |
||
132 | $this->stylesheets[] = array( |
||
133 | 'handle'=> $handle, |
||
134 | 'path' => $path, |
||
135 | 'print' => $print, |
||
136 | 'minify'=> $minify, |
||
137 | 'cache' => $cache |
||
138 | ); |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Register a value retrieval function and associate it with the given handle |
||
143 | * |
||
144 | * @param type $handle The stylesheet's name/id |
||
145 | * @param type $callback |
||
146 | */ |
||
147 | public function register_callback( $handle, $callback ) |
||
148 | { |
||
149 | $this->callbacks[$handle] = $callback; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Register a filter function for a given stylesheet handle. |
||
154 | */ |
||
155 | public function register_filter( $handle, $filter_name, $callback ) |
||
156 | { |
||
157 | if( !array_key_exists( $handle, $this->filters ) ) |
||
158 | { |
||
159 | $this->filters[$handle] = array(); |
||
160 | } |
||
161 | $this->filters[$handle][$filter_name] = $callback; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Get the compiled CSS for the given style. Skips compilation if the compiled |
||
166 | * version can be found in cache. |
||
167 | * |
||
168 | * @param array $style List of styles with the same structure as they are |
||
169 | * stored in $this->stylesheets |
||
170 | * @return type |
||
171 | */ |
||
172 | protected function get_compiled_style( $style ) |
||
173 | { |
||
174 | $cache = DynamicCSSCache::get_instance(); |
||
175 | |||
176 | // Use cached compiled CSS if applicable |
||
177 | if( $style['cache'] ) |
||
178 | { |
||
179 | $cached_css = $cache->get( $style['handle'] ); |
||
180 | if( false !== $cached_css ) |
||
181 | { |
||
182 | return $cached_css; |
||
183 | } |
||
184 | } |
||
185 | |||
186 | $css = file_get_contents( $style['path'] ); |
||
187 | if( $style['minify'] ) $css = $this->minify_css( $css ); |
||
188 | |||
189 | // Compile the dynamic CSS |
||
190 | $compiled_css = $this->compile_css( |
||
191 | $css, |
||
192 | $this->callbacks[$style['handle']], |
||
193 | key_exists( $style['handle'], $this->filters ) ? $this->filters[$style['handle']] : array() |
||
194 | ); |
||
195 | |||
196 | $cache->update( $style['handle'], $compiled_css ); |
||
197 | return $compiled_css; |
||
0 ignored issues
–
show
The return type of
return $compiled_css; (string ) is incompatible with the return type documented by DynamicCSSCompiler::get_compiled_style of type type .
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 ![]() |
|||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Minify a given CSS string by removing comments, whitespaces and newlines |
||
202 | * |
||
203 | * @see http://stackoverflow.com/a/6630103/1096470 |
||
204 | * @param string $css CSS style to minify |
||
205 | * @return string Minified CSS |
||
206 | */ |
||
207 | protected function minify_css( $css ) |
||
208 | { |
||
209 | return preg_replace( '@({)\s+|(\;)\s+|/\*.+?\*\/|\R@is', '$1$2 ', $css ); |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Check if a callback function has been register for the given handle. |
||
214 | * |
||
215 | * @param string $handle |
||
216 | * @return boolean |
||
217 | */ |
||
218 | protected function callback_exists( $handle ) |
||
219 | { |
||
220 | if( array_key_exists( $handle, $this->callbacks ) ) |
||
221 | { |
||
222 | return true; |
||
223 | } |
||
224 | trigger_error( |
||
225 | "There is no callback function associated with the handle '$handle'. ". |
||
226 | "Use <b>wp_dynamic_css_set_callback()</b> to register a callback function for this handle." |
||
227 | ); |
||
228 | return false; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Parse the given CSS string by converting the variables to their |
||
233 | * corresponding values retrieved by applying the callback function |
||
234 | * |
||
235 | * @param callable $callback A function that replaces the variables with |
||
236 | * their values. The function accepts the variable's name as a parameter |
||
237 | * @param string $css A string containing dynamic CSS (pre-compiled CSS with |
||
238 | * variables) |
||
239 | * @return string The compiled CSS after converting the variables to their |
||
240 | * corresponding values |
||
241 | */ |
||
242 | protected function compile_css( $css, $callback, $filters ) |
||
243 | { |
||
244 | return preg_replace_callback( |
||
245 | |||
246 | "#". // Begin |
||
247 | "\\$". // Must start with $ |
||
248 | "([\\w-]+)". // Match alphanumeric characters and dashes |
||
249 | "((?:\\['?[\\w-]+'?\\])*)". // Optionally match array subscripts i.e. $myVar['index'] |
||
250 | "((?:". // Optionally match pipe filters i.e. $myVar|myFilter |
||
251 | "\\|[\\w-]+". // Starting with the | character |
||
252 | "(\([\w\.,']+\))?". // Filters can have strings and numbers i.e myFilter('string',1,2.5) |
||
253 | ")*)". // Allow for 0 or more piped filters |
||
254 | "#", // End |
||
255 | |||
256 | function( $matches ) use ( $callback, $filters ) { |
||
257 | // If this variable is an array, get the subscripts |
||
258 | if( '' !== $matches[2] ) |
||
259 | { |
||
260 | preg_match_all('/[\w-]+/i', $matches[2], $subscripts); |
||
261 | } |
||
262 | |||
263 | $val = call_user_func_array( $callback, array($matches[1],@$subscripts[0]) ); |
||
0 ignored issues
–
show
The variable
$subscripts 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
![]() |
|||
264 | |||
265 | // Apply custom filters |
||
266 | if( '' !== $matches[3] ) |
||
267 | { |
||
268 | $val = $this->apply_filters( substr($matches[3], 1), $val, $filters ); |
||
269 | } |
||
270 | |||
271 | return $val; |
||
272 | }, $css); |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * Apply the filters specified in $filters_string to the given $value. |
||
277 | * |
||
278 | * @param string $filters_string |
||
279 | * @param string $value |
||
280 | * @param array $filters Array of callback functions |
||
281 | * @return string The value after all filters have been applied |
||
282 | */ |
||
283 | protected function apply_filters( $filters_string, $value, $filters ) |
||
284 | { |
||
285 | foreach( explode( '|', $filters_string) as $filter ) |
||
286 | { |
||
287 | $args = array( $value ); |
||
288 | |||
289 | if( false !== strrpos( $filters_string, "(" ) ) |
||
290 | { |
||
291 | $pieces = explode( '(', $filter ); |
||
292 | $filter = $pieces[0]; |
||
293 | $params = explode( ',', str_replace( ')', '', $pieces[1] ) ); |
||
294 | array_walk( $params, array( $this, 'strtoval' ) ); // Convert string values to actual values |
||
295 | $args = array_merge( $args, $params ); |
||
296 | } |
||
297 | |||
298 | if( key_exists( $filter, $filters ) ) |
||
299 | { |
||
300 | $value = call_user_func_array( $filters[$filter], $args ); |
||
301 | } |
||
302 | } |
||
303 | return $value; |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Convert the given string to its actual value. |
||
308 | * |
||
309 | * @param string $str The string to be converted (passed by reference) |
||
310 | */ |
||
311 | protected function strtoval( &$str ) |
||
312 | { |
||
313 | if( 'false' === strtolower($str) ) $str = false; |
||
314 | if( 'true' === strtolower($str) ) $str = true; |
||
315 | if( false !== strrpos( $str, "'" ) ) $str = str_replace ( "'", "", $str ); |
||
316 | if( is_numeric( $str ) ) $str = floatval( $str ); |
||
317 | } |
||
318 | } |
||
319 |
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..