PluginProbe ʕ •ᴥ•ʔ
Aruba HiSpeed Cache / 3.0.15
Aruba HiSpeed Cache v3.0.15
3.0.15 3.0.14 3.0.13 1.2.4 1.2.5 1.2.6 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.18 2.0.19 2.0.20 2.0.21 2.0.22 2.0.23 2.0.24 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0.0 3.0.1 3.0.10 3.0.11 3.0.12 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3
aruba-hispeed-cache / src / assets / AHSC_WPCT.php
aruba-hispeed-cache / src / assets Last commit date
AHSC_WPCT.php 4 days ago
AHSC_WPCT.php
372 lines
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit;
4 }
5 /**
6 * Transforms a wp-config.php file.
7 */
8 class HASC_WPCT {
9 /**
10 * Append to end of file
11 */
12 const ANCHOR_EOF = 'EOF';
13
14 /**
15 * Path to the wp-config.php file.
16 *
17 * @var string
18 */
19 protected $wp_config_path;
20
21 /**
22 * Original source of the wp-config.php file.
23 *
24 * @var string
25 */
26 protected $wp_config_src;
27
28 /**
29 * Array of parsed configs.
30 *
31 * @var array
32 */
33 protected $wp_configs = array();
34
35 /**
36 * Instantiates the class with a valid wp-config.php.
37 *
38 * @throws Exception If the wp-config.php file is missing.
39 * @throws Exception If the wp-config.php file is not writable.
40 *
41 * @param string $wp_config_path Path to a wp-config.php file.
42 */
43 public function __construct( $wp_config_path, $read_only = false ) {
44 $basename = basename( $wp_config_path );
45
46 if ( ! file_exists( $wp_config_path ) ) {
47 throw new Exception( esc_attr("{$basename} does not exist.") );
48 }
49
50 if ( ! $read_only && ! wp_is_writable( $wp_config_path ) ) {
51 throw new Exception( esc_attr("{$basename} is not writable.") );
52 }
53
54 $this->wp_config_path = $wp_config_path;
55 }
56
57 /**
58 * Checks if a config exists in the wp-config.php file.
59 *
60 * @throws Exception If the wp-config.php file is empty.
61 * @throws Exception If the requested config type is invalid.
62 *
63 * @param string $type Config type (constant or variable).
64 * @param string $name Config name.
65 *
66 * @return bool
67 */
68 public function exists( $type, $name ) {
69 $wp_config_src = file_get_contents( $this->wp_config_path );
70
71 if ( ! trim( $wp_config_src ) ) {
72 throw new Exception( 'Config file is empty.' );
73 }
74 // Normalize the newline to prevent an issue coming from OSX.
75 $this->wp_config_src = str_replace( array( "\r\n", "\n\r", "\r" ), "\n", $wp_config_src );
76 $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
77
78 if ( ! isset( $this->wp_configs[ $type ] ) ) {
79 throw new Exception( esc_attr("Config type '{$type}' does not exist.") );
80 }
81
82 return isset( $this->wp_configs[ $type ][ $name ] );
83 }
84
85 /**
86 * Get the value of a config in the wp-config.php file.
87 *
88 * @throws Exception If the wp-config.php file is empty.
89 * @throws Exception If the requested config type is invalid.
90 *
91 * @param string $type Config type (constant or variable).
92 * @param string $name Config name.
93 *
94 * @return string|null
95 */
96 public function get_value( $type, $name ) {
97 $wp_config_src = file_get_contents( $this->wp_config_path );
98
99 if ( ! trim( $wp_config_src ) ) {
100 throw new Exception( 'Config file is empty.' );
101 }
102
103 $this->wp_config_src = $wp_config_src;
104 $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
105
106 if ( ! isset( $this->wp_configs[ $type ] ) ) {
107 throw new Exception( esc_attr("Config type '{$type}' does not exist.") );
108 }
109
110 return $this->wp_configs[ $type ][ $name ]['value'];
111 }
112
113 /**
114 * Adds a config to the wp-config.php file.
115 *
116 * @throws Exception If the config value provided is not a string.
117 * @throws Exception If the config placement anchor could not be located.
118 *
119 * @param string $type Config type (constant or variable).
120 * @param string $name Config name.
121 * @param string $value Config value.
122 * @param array $options (optional) Array of special behavior options.
123 *
124 * @return bool
125 */
126 public function add( $type, $name, $value, array $options = array() ) {
127 if ( ! is_string( $value ) ) {
128 throw new Exception( 'Config value must be a string.' );
129 }
130
131 if ( $this->exists( $type, $name ) ) {
132 return false;
133 }
134
135 $defaults = array(
136 'raw' => false, // Display value in raw format without quotes.
137 'anchor' => "/* That's all, stop editing!", // Config placement anchor string.
138 'separator' => PHP_EOL, // Separator between config definition and anchor string.
139 'placement' => 'before', // Config placement direction (insert before or after).
140 );
141
142 list( $raw, $anchor, $separator, $placement ) = array_values( array_merge( $defaults, $options ) );
143
144 $raw = (bool) $raw;
145 $anchor = (string) $anchor;
146 $separator = (string) $separator;
147 $placement = (string) $placement;
148
149 if ( self::ANCHOR_EOF === $anchor ) {
150 $contents = $this->wp_config_src . $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
151 } else {
152 if ( false === strpos( $this->wp_config_src, $anchor ) ) {
153 throw new Exception( 'Unable to locate placement anchor.' );
154 }
155
156 $new_src = $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
157 $new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor;
158 $contents = str_replace( $anchor, $new_src, $this->wp_config_src );
159 }
160
161 return $this->save( $contents );
162 }
163
164 /**
165 * Updates an existing config in the wp-config.php file.
166 *
167 * @throws Exception If the config value provided is not a string.
168 *
169 * @param string $type Config type (constant or variable).
170 * @param string $name Config name.
171 * @param string $value Config value.
172 * @param array $options (optional) Array of special behavior options.
173 *
174 * @return bool
175 */
176 public function update( $type, $name, $value, array $options = array() ) {
177 if ( ! is_string( $value ) ) {
178 throw new Exception( 'Config value must be a string.' );
179 }
180
181 $defaults = array(
182 'add' => true, // Add the config if missing.
183 'raw' => false, // Display value in raw format without quotes.
184 'normalize' => false, // Normalize config output using WP Coding Standards.
185 );
186
187 list( $add, $raw, $normalize ) = array_values( array_merge( $defaults, $options ) );
188
189 $add = (bool) $add;
190 $raw = (bool) $raw;
191 $normalize = (bool) $normalize;
192
193 if ( ! $this->exists( $type, $name ) ) {
194 return ( $add ) ? $this->add( $type, $name, $value, $options ) : false;
195 }
196
197 $old_src = $this->wp_configs[ $type ][ $name ]['src'];
198 $old_value = $this->wp_configs[ $type ][ $name ]['value'];
199 $new_value = $this->format_value( $value, $raw );
200
201 if ( $normalize ) {
202 $new_src = $this->normalize( $type, $name, $new_value );
203 } else {
204 $new_parts = $this->wp_configs[ $type ][ $name ]['parts'];
205 $new_parts[1] = str_replace( $old_value, $new_value, $new_parts[1] ); // Only edit the value part.
206 $new_src = implode( '', $new_parts );
207 }
208
209 $contents = preg_replace(
210 sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
211 '$1' . str_replace( '$', '\$', trim( $new_src ) ),
212 $this->wp_config_src
213 );
214
215 return $this->save( $contents );
216 }
217
218 /**
219 * Removes a config from the wp-config.php file.
220 *
221 * @param string $type Config type (constant or variable).
222 * @param string $name Config name.
223 *
224 * @return bool
225 */
226 public function remove( $type, $name ) {
227 if ( ! $this->exists( $type, $name ) ) {
228 return false;
229 }
230
231 $pattern = sprintf( '/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote( $this->wp_configs[ $type ][ $name ]['src'], '/' ) );
232 $contents = preg_replace( $pattern, '$1', $this->wp_config_src );
233
234 return $this->save( $contents );
235 }
236
237 /**
238 * Applies formatting to a config value.
239 *
240 * @throws Exception When a raw value is requested for an empty string.
241 *
242 * @param string $value Config value.
243 * @param bool $raw Display value in raw format without quotes.
244 *
245 * @return mixed
246 */
247 protected function format_value( $value, $raw ) {
248 if ( $raw && '' === trim( $value ) ) {
249 throw new Exception( 'Raw value for empty string not supported.' );
250 }
251
252 /*
253 * Not debug output: var_export() is used here for what it is actually for, turning
254 * a PHP value into valid PHP source, because the result is written verbatim into
255 * wp-config.php. wp_json_encode() would emit JSON literals and corrupt the file.
256 */
257 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- generating PHP source for wp-config.php, not logging.
258 return ( $raw ) ? $value : var_export( $value, true );
259 }
260
261 /**
262 * Normalizes the source output for a name/value pair.
263 *
264 * @throws Exception If the requested config type does not support normalization.
265 *
266 * @param string $type Config type (constant or variable).
267 * @param string $name Config name.
268 * @param mixed $value Config value.
269 *
270 * @return string
271 */
272 protected function normalize( $type, $name, $value ) {
273 if ( 'constant' === $type ) {
274 $placeholder = "define( '%s', %s );";
275 } elseif ( 'variable' === $type ) {
276 $placeholder = '$%s = %s;';
277 } else {
278 throw new Exception( esc_attr("Unable to normalize config type '{$type}'.") );
279 }
280
281 return sprintf( $placeholder, $name, $value );
282 }
283
284 /**
285 * Parses the source of a wp-config.php file.
286 *
287 * @param string $src Config file source.
288 *
289 * @return array
290 */
291 protected function parse_wp_config( $src ) {
292 $configs = array();
293 $configs['constant'] = array();
294 $configs['variable'] = array();
295
296 // Strip comments.
297 foreach ( token_get_all( $src ) as $token ) {
298 if ( in_array( $token[0], array( T_COMMENT, T_DOC_COMMENT ), true ) ) {
299 if ( '//' === $token[1] ) {
300 // For empty line comments, actually remove empty line comments instead of all double-slashes.
301 // See: https://github.com/wp-cli/wp-config-transformer/issues/47
302 $src = preg_replace( '/' . preg_quote( '//', '/' ) . '$/m', '', $src );
303 } else {
304 $src = str_replace( $token[1], '', $src );
305 }
306 }
307 }
308
309 preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*define\s*\(\s*[\'"](\w*?)[\'"]\s*)(,\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*)((?:,\s*(?:true|false)\s*)?\)\s*;)/ims', $src, $constants );
310 preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*\$(\w+)\s*=)(\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*;)/ims', $src, $variables );
311
312 if ( ! empty( $constants[0] ) && ! empty( $constants[1] ) && ! empty( $constants[2] ) && ! empty( $constants[3] ) && ! empty( $constants[4] ) && ! empty( $constants[5] ) ) {
313 foreach ( $constants[2] as $index => $name ) {
314 $configs['constant'][ $name ] = array(
315 'src' => $constants[0][ $index ],
316 'value' => $constants[4][ $index ],
317 'parts' => array(
318 $constants[1][ $index ],
319 $constants[3][ $index ],
320 $constants[5][ $index ],
321 ),
322 );
323 }
324 }
325
326 if ( ! empty( $variables[0] ) && ! empty( $variables[1] ) && ! empty( $variables[2] ) && ! empty( $variables[3] ) && ! empty( $variables[4] ) ) {
327 // Remove duplicate(s), last definition wins.
328 $variables[2] = array_reverse( array_unique( array_reverse( $variables[2], true ) ), true );
329 foreach ( $variables[2] as $index => $name ) {
330 $configs['variable'][ $name ] = array(
331 'src' => $variables[0][ $index ],
332 'value' => $variables[4][ $index ],
333 'parts' => array(
334 $variables[1][ $index ],
335 $variables[3][ $index ],
336 ),
337 );
338 }
339 }
340
341 return $configs;
342 }
343
344 /**
345 * Saves new contents to the wp-config.php file.
346 *
347 * @throws Exception If the config file content provided is empty.
348 * @throws Exception If there is a failure when saving the wp-config.php file.
349 *
350 * @param string $contents New config contents.
351 *
352 * @return bool
353 */
354 protected function save( $contents ) {
355 if ( ! trim( $contents ) ) {
356 throw new Exception( 'Cannot save the config file with empty contents.' );
357 }
358
359 if ( $contents === $this->wp_config_src ) {
360 return false;
361 }
362
363 $result = file_put_contents( $this->wp_config_path, $contents, LOCK_EX );
364
365 if ( false === $result ) {
366 throw new Exception( 'Failed to update the config file.' );
367 }
368
369 return true;
370 }
371 }
372