GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#13)
by Per
01:21
created

compiler.php (4 issues)

Upgrade to new PHP Analysis Engine

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 {
0 ignored issues
show
Coding Style Compatibility introduced by
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.

Loading history...
25
26
	/**
27
	 * @var DynamicCSSCompiler 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 = [];
35
36
	/**
37
	 * @var array The list of registered callbacks
38
	 */
39
	private $callbacks = [];
40
41
	/**
42
	 * @var aray The list of registered filters
43
	 */
44
	private $filters = [];
45
46
	/**
47
	 * Returns the *Singleton* instance of this class.
48
	 *
49
	 * @return DynamicCSSCompiler The *Singleton* instance.
50
	 */
51
	public static function get_instance() {
52
53
		if ( null === static::$instance ) {
0 ignored issues
show
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
54
			static::$instance = new static();
0 ignored issues
show
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
55
		}
56
		return static::$instance;
0 ignored issues
show
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
57
	}
58
59
	/**
60
	 * Enqueue all registered stylesheets.
61
	 */
62
	public function enqueue_styles() {
63
64
		foreach ( $this->stylesheets as $stylesheet ) {
65
			if ( $this->callback_exists( $stylesheet['handle'] ) ) {
66
				$this->enqueue_style( $stylesheet );
67
			}
68
		}
69
	}
70
71
	/**
72
	 * Enqueue a single registered stylesheet.
73
	 *
74
	 * @param array $stylesheet
75
	 */
76
	public function enqueue_style( $stylesheet ) {
77
78
		$handle = 'wp-dynamic-css-' . $stylesheet['handle'];
79
		$print  = $stylesheet['print'];
80
81
		wp_register_style(
82
			$handle,
83
			// Don't pass a URL if this style is to be printed
84
			$print ? false : $this->get_ajax_callback_url( $stylesheet['handle'] ),
85
			$stylesheet['deps']
86
		);
87
88
		wp_enqueue_style( $handle, $stylesheet['handle'], $stylesheet['deps'] );
89
90
		// Add inline styles for styles that are set to be printed
91
		if ( $print ) {
92
			// Inline styles only work if the handle has already been registered and enqueued
93
			wp_add_inline_style( $handle, $this->get_compiled_style( $stylesheet ), $stylesheet['deps'] );
94
		}
95
	}
96
97
	/**
98
	 * This is the AJAX callback used for loading styles externally via an http
99
	 * request.
100
	 */
101
	public function ajax_callback() {
102
103
		header( 'Content-type: text/css; charset: UTF-8' );
104
		$handle = filter_input( INPUT_GET, 'handle' );
105
106
		foreach ( $this->stylesheets as $stylesheet ) {
107
			if ( $handle === $stylesheet['handle'] ) {
108
				echo $this->get_compiled_style( $stylesheet );
109
			}
110
		}
111
112
		wp_die();
113
	}
114
115
	/**
116
	 * Add a style path to the pool of styles to be compiled
117
	 *
118
	 * @param string $handle The stylesheet's name/id
119
	 * @param string $path The absolute path to the dynamic style
120
	 * @param boolean $print Whether to print the compiled CSS to the document
121
	 * head, or include it as an external CSS file
122
	 * @param boolean $minify Whether to minify the CSS output
123
	 * @param boolean $cache Whether to store the compiled version of this
124
	 * stylesheet in cache to avoid compilation on every page load.
125
	 */
126
	public function register_style( $handle, $path, $deps, $print, $minify, $cache, $expiration ) {
127
128
		$this->stylesheets[] = [
129
			'handle'     => $handle,
130
			'path'       => $path,
131
			'deps'       => $deps,
132
			'print'      => $print,
133
			'minify'     => $minify,
134
			'cache'      => $cache,
135
			'cache_time' => $expiration,
136
		];
137
	}
138
139
	/**
140
	 * Register a value retrieval function and associate it with the given handle
141
	 *
142
	 * @param string $handle The stylesheet's name/id
143
	 * @param callable $callback
144
	 */
145
	public function register_callback( $handle, $callback ) {
146
147
		$this->callbacks[ $handle ] = $callback;
148
	}
149
150
	/**
151
	 * Register a filter function for a given stylesheet handle.
152
	 */
153
	public function register_filter( $handle, $filter_name, $callback ) {
154
155
		if ( ! array_key_exists( $handle, $this->filters ) ) {
156
			$this->filters[ $handle ] = [];
157
		}
158
		$this->filters[ $handle ][ $filter_name ] = $callback;
159
	}
160
161
	/**
162
	 * Get the compiled CSS for the given style. Skips compilation if the compiled
163
	 * version can be found in cache.
164
	 *
165
	 * @param array $style List of styles with the same structure as they are
166
	 * stored in $this->stylesheets
167
	 * @return string The compiled CSS for this stylesheet
168
	 */
169
	protected function get_compiled_style( $style ) {
170
171
		$cache = DynamicCSSCache::get_instance();
172
173
		// Use cached compiled CSS if applicable
174
		if ( $style['cache'] ) {
175
			$cached_css = $cache->get( $style['handle'] );
176
			if ( false !== $cached_css ) {
177
				return $cached_css;
178
			}
179
		}
180
181
		$css = file_get_contents( $style['path'] );
182
		if ( $style['minify'] ) {
183
			$css = $this->minify_css( $css );
184
		}
185
186
		// Compile the dynamic CSS
187
		$compiled_css = $this->compile_css(
188
			$css,
189
			$this->callbacks[ $style['handle'] ],
190
			(array) @$this->filters[ $style['handle'] ]
191
		);
192
193
		$cache->update( $style['handle'], $compiled_css, $style['cache_time'] );
194
		return $this->add_meta_info( $compiled_css );
195
	}
196
197
	/**
198
	 * Add meta information to the compiled CSS
199
	 *
200
	 * @param string $compiled_css The compiled CSS
201
	 * @return string The compiled CSS with the meta information added to it
202
	 */
203
	protected function add_meta_info( $compiled_css ) {
204
205
		return "/**\n" .
206
			   " * Compiled using wp-dynamic-css\n" .
207
			   " * https://github.com/askupasoftware/wp-dynamic-css\n" .
208
			   " */\n\n" .
209
			   $compiled_css;
210
	}
211
212
	/**
213
	 * Get the callback URL for enqueuing the stylesheet extrnally
214
	 *
215
	 * @param string $handle The stylesheet's handle
216
	 * @return string The URL for the given handle
217
	 */
218
	protected function get_ajax_callback_url( $handle ) {
219
220
		return esc_url_raw(
221
			add_query_arg( [
222
				'action' => 'wp_dynamic_css',
223
				'handle' => $handle,
224
			], admin_url( 'admin-ajax.php' ) )
225
		);
226
	}
227
228
	/**
229
	 * Minify a given CSS string by removing comments, whitespaces and newlines
230
	 *
231
	 * @see http://stackoverflow.com/a/6630103/1096470
232
	 * @param string $css CSS style to minify
233
	 * @return string Minified CSS
234
	 */
235
	protected function minify_css( $css ) {
236
237
		return preg_replace( '@({)\s+|(\;)\s+|/\*.+?\*\/|\R@is', '$1$2 ', $css );
238
	}
239
240
	/**
241
	 * Check if a callback function has been register for the given handle.
242
	 *
243
	 * @param string $handle
244
	 * @return boolean
245
	 */
246
	protected function callback_exists( $handle ) {
247
248
		if ( array_key_exists( $handle, $this->callbacks ) ) {
249
			return true;
250
		}
251
		trigger_error(
252
			"There is no callback function associated with the handle '$handle'. " .
253
			'Use <b>wp_dynamic_css_set_callback()</b> to register a callback function for this handle.'
254
		);
255
		return false;
256
	}
257
258
	/**
259
	 * Parse the given CSS string by converting the variables to their
260
	 * corresponding values retrieved by applying the callback function
261
	 *
262
	 * @param callable $callback A function that replaces the variables with
263
	 * their values. The function accepts the variable's name as a parameter
264
	 * @param string $css A string containing dynamic CSS (pre-compiled CSS with
265
	 * variables)
266
	 * @return string The compiled CSS after converting the variables to their
267
	 * corresponding values
268
	 */
269
	protected function compile_css( $css, $callback, $filters ) {
270
271
		return preg_replace_callback(
272
273
			'#' . // Begin
274
			'\\$' . // Must start with $
275
			'([\\w-]+)' . // Match alphanumeric characters and dashes
276
			"((?:\\['?[\\w-]+'?\\])*)" . // Optionally match array subscripts i.e. $myVar['index']
277
			'((?:' . // Optionally match pipe filters i.e. $myVar|myFilter
278
				'\\|[\\w-]+' . // Starting with the | character
279
				"(\([\w\.,']+\))?" . // Filters can have strings and numbers i.e myFilter('string',1,2.5)
280
			')*)' . // Allow for 0 or more piped filters
281
			'#',                        // End
282
			function( $matches ) use ( $callback, $filters ) {
283
				$subscripts = [];
284
285
				// If this variable is an array, get the subscripts
286
				if ( '' !== $matches[2] ) {
287
					preg_match_all( '/[\w-]+/i', $matches[2], $subscripts );
288
				}
289
290
				$val = call_user_func_array( $callback, [ $matches[1], @$subscripts[0] ] );
291
292
				// If there are filters, apply them
293
				if ( '' !== $matches[3] ) {
294
					$val = $this->apply_filters( substr( $matches[3], 1 ), $val, $filters );
295
				}
296
297
				return $val;
298
			}, $css
299
		);
300
	}
301
302
	/**
303
	 * Apply the filters specified in $filters_string to the given $value.
304
	 *
305
	 * @param string $filters_string
306
	 * @param string $value
307
	 * @param array $filters Array of callback functions
308
	 * @return string The value after all filters have been applied
309
	 */
310
	protected function apply_filters( $filters_string, $value, $filters = [] ) {
311
312
		foreach ( explode( '|', $filters_string ) as $filter ) {
313
			$args = [ $value ];
314
315
			if ( false !== strrpos( $filters_string, '(' ) ) {
316
				$pieces = explode( '(', $filter );
317
				$filter = $pieces[0];
318
				$params = explode( ',', str_replace( ')', '', $pieces[1] ) );
319
				array_walk( $params, [ $this, 'strtoval' ] ); // Convert string values to actual values
320
				$args = array_merge( $args, $params );
321
			}
322
323
			if ( key_exists( $filter, $filters ) ) {
324
				$value = call_user_func_array( $filters[ $filter ], $args );
325
			}
326
		}
327
		return $value;
328
	}
329
330
	/**
331
	 * Convert the given string to its actual value.
332
	 *
333
	 * @param string $str The string to be converted (passed by reference)
334
	 */
335
	protected function strtoval( &$str ) {
336
337
		if ( 'false' === strtolower( $str ) ) {
338
			$str = false;
339
		}
340
		if ( 'true' === strtolower( $str ) ) {
341
			$str = true;
342
		}
343
		if ( false !== strrpos( $str, "'" ) ) {
344
			$str = str_replace( "'", '', $str );
345
		}
346
		if ( is_numeric( $str ) ) {
347
			$str = floatval( $str );
348
		}
349
	}
350
}
351