PluginProbe
Debug Log Manager – Conveniently Monitor and Inspect Errors / 2.2.2
Debug Log Manager – Conveniently Monitor and Inspect Errors v2.2.2
2.5.2 2.5.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.3.0 1.3.1 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.8.0 1.8.2 1.8.3 1.8.4 All 49 releases
debug-log-manager / classes / class-wp-config-transformer.php

class-wp-config-transformer.php in Debug Log Manager – Conveniently Monitor and Inspect Errors 2.2.2, at classes/class-wp-config-transformer.php

427 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace DLM\Classes;
4
5 use Exception;
6
7 /**
8 * Class with methods to manipulate wp-config.php
9 *
10 * @since 1.0.0
11 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
12 */
13 class WP_Config_Transformer {
14
15 /**
16 * The wp-config.php source file
17 *
18 * @since 1.0.0
19 * @access private
20 * @var string $version The current version of this plugin.
21 */
22 private $wp_config_src;
23
24 /**
25 * The configs defined in wp-config.php
26 *
27 * @since 1.0.0
28 * @access private
29 * @var string $version The current version of this plugin.
30 */
31 private $wp_configs;
32
33 /**
34 * Get wp-config.php file path
35 *
36 * @since 1.0.0
37 */
38 public function wpconfig_file( $type = 'path' ) {
39
40 // From wp-load.php
41
42 if ( file_exists( ABSPATH . 'wp-config.php' ) ) {
43
44 /** The config file resides in ABSPATH */
45 $file = ABSPATH . 'wp-config.php';
46 $location = 'WordPress root directory';
47
48
49 } elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {
50
51 /** The config file resides one level above ABSPATH but is not part of another installation */
52 $file = dirname( ABSPATH ) . '/wp-config.php';
53 $location = 'parent directory of WordPress root';
54
55 } else {
56
57 $file = 'Undetectable.';
58 $location = 'not in WordPress root or it\'s parent directory';
59
60 }
61
62 if ( !is_writable( $file ) ) {
63 $writeability = 'not writeable';
64 } else {
65 $writeability = 'writeable';
66 }
67
68 if ( $type == 'path' ) {
69 return $file;
70 } elseif ( $type == 'location' ) {
71 return $location;
72 } elseif ( $type == 'writeability' ) {
73 return $writeability;
74 } elseif ( $type == 'status' ) {
75 return '<div class="dlm-wpconfig-status" style="display: none;">The wp-config.php file is located in ' . $location . ' ('. $file . ') and is ' . $writeability .'.</div>';
76 }
77
78 }
79
80 /**
81 * Get configs in wp-config.php
82 *
83 * @since 1.0.0
84 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
85 */
86 public function configs( $return_type = 'raw' ) {
87
88 $src = file_get_contents( $this->wpconfig_file( 'path' ) );
89
90 $configs = array();
91 $configs['constant'] = array();
92 $configs['variable'] = array();
93
94 // Strip comments.
95 foreach ( token_get_all( $src ) as $token ) {
96 if ( in_array( $token[0], array( T_COMMENT, T_DOC_COMMENT ), true ) ) {
97 $src = str_replace( $token[1], '', $src );
98 }
99 }
100
101 preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*define\s*\(\s*[\'"](\w*?)[\'"]\s*)(,\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*)((?:,\s*(?:true|false)\s*)?\)\s*;)/ims', $src, $constants );
102 preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*\$(\w+)\s*=)(\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*;)/ims', $src, $variables );
103
104 if ( ! empty( $constants[0] ) && ! empty( $constants[1] ) && ! empty( $constants[2] ) && ! empty( $constants[3] ) && ! empty( $constants[4] ) && ! empty( $constants[5] ) ) {
105 foreach ( $constants[2] as $index => $name ) {
106 $configs['constant'][ $name ] = array(
107 'src' => $constants[0][ $index ],
108 'value' => $constants[4][ $index ],
109 'parts' => array(
110 $constants[1][ $index ],
111 $constants[3][ $index ],
112 $constants[5][ $index ],
113 ),
114 );
115 }
116 }
117
118 if ( ! empty( $variables[0] ) && ! empty( $variables[1] ) && ! empty( $variables[2] ) && ! empty( $variables[3] ) && ! empty( $variables[4] ) ) {
119 // Remove duplicate(s), last definition wins.
120 $variables[2] = array_reverse( array_unique( array_reverse( $variables[2], true ) ), true );
121 foreach ( $variables[2] as $index => $name ) {
122 $configs['variable'][ $name ] = array(
123 'src' => $variables[0][ $index ],
124 'value' => $variables[4][ $index ],
125 'parts' => array(
126 $variables[1][ $index ],
127 $variables[3][ $index ],
128 ),
129 );
130 }
131 }
132
133 $this->wp_configs = $configs;
134
135 if ( $return_type == 'raw' ) {
136 return $configs;
137 } elseif ( $return_type == 'print_r' ) {
138 return '<pre>' . print_r( $configs, true ) . '</pre>';
139 }
140 }
141
142 /**
143 * Checks if a config exists in the wp-config.php file.
144 *
145 * @throws Exception If the wp-config.php file is empty.
146 * @throws Exception If the requested config type is invalid.
147 *
148 * @param string $type Config type (constant or variable).
149 * @param string $name Config name.
150 *
151 * @return bool
152 * @since 1.0.0
153 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
154 */
155 public function exists( $type, $name ) {
156 $wp_config_src = file_get_contents( $this->wpconfig_file( 'path' ) );
157
158 if ( ! trim( $wp_config_src ) ) {
159 throw new Exception( 'Config file is empty.' );
160 }
161 // Normalize the newline to prevent an issue coming from OSX.
162 $this->wp_config_src = str_replace( array( "\n\r", "\r" ), "\n", $wp_config_src );
163
164 $this->wp_configs = $this->configs( 'raw' );
165
166 if ( ! isset( $this->wp_configs[ $type ] ) ) {
167 throw new Exception( "Config type '{$type}' does not exist." );
168 }
169
170 return isset( $this->wp_configs[ $type ][ $name ] );
171 }
172
173 /**
174 * Get the value of a config in the wp-config.php file.
175 *
176 * @throws Exception If the wp-config.php file is empty.
177 * @throws Exception If the requested config type is invalid.
178 *
179 * @param string $type Config type (constant or variable).
180 * @param string $name Config name.
181 *
182 * @return array
183 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
184 */
185 public function get_value( $type, $name ) {
186 $wp_config_src = file_get_contents( $this->wpconfig_file( 'path' ) );
187
188 if ( ! trim( $wp_config_src ) ) {
189 throw new Exception( 'Config file is empty.' );
190 }
191
192 $this->wp_config_src = $wp_config_src;
193 $this->wp_configs = $this->configs( 'raw' );
194
195 if ( ! isset( $this->wp_configs[ $type ] ) ) {
196 throw new Exception( "Config type '{$type}' does not exist." );
197 }
198
199 return $this->wp_configs[ $type ][ $name ]['value'];
200 }
201
202 /**
203 * Adds a config to the wp-config.php file.
204 *
205 * @throws Exception If the config value provided is not a string.
206 * @throws Exception If the config placement anchor could not be located.
207 *
208 * @param string $type Config type (constant or variable).
209 * @param string $name Config name.
210 * @param string $value Config value.
211 * @param array $options (optional) Array of special behavior options.
212 *
213 * @return bool
214 * @since 1.0.0
215 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
216 */
217 public function add( $type, $name, $value, array $options = array() ) {
218 if ( ! is_string( $value ) ) {
219 throw new Exception( 'Config value must be a string.' );
220 }
221
222 if ( $this->exists( $type, $name ) ) {
223 return false;
224 }
225
226 if ( in_array( $value, array( 'true', 'false' ), true ) ) {
227 $raw_input = true;
228 } else {
229 $raw_input = false;
230 }
231
232 $wp_config_src = file_get_contents( $this->wpconfig_file( 'path' ) );
233
234 if ( false !== strpos( $wp_config_src, "Happy publishing" ) ) {
235 $anchor = "/* That's all, stop editing! Happy publishing. */";
236 } elseif ( false !== strpos( $wp_config_src, "Happy blogging" ) ) {
237 $anchor = "/* That's all, stop editing! Happy blogging. */";
238 } else {}
239
240 $defaults = array(
241 'raw' => $raw_input, // Display value in raw format without quotes.
242 'anchor' => $anchor, // Config placement anchor string.
243 'separator' => PHP_EOL, // Separator between config definition and anchor string.
244 'placement' => 'before', // Config placement direction (insert before or after).
245 );
246
247 // list( $raw, $anchor, $separator, $placement ) = array_values( $options );
248 list( $raw, $anchor, $separator, $placement ) = array_values( array_merge( $defaults, $options ) );;
249
250 $raw = (bool) $raw;
251 $anchor = (string) $anchor;
252 $separator = (string) $separator;
253 $placement = (string) $placement;
254
255 if ( 'EOF' === $anchor ) {
256 $contents = $this->wp_config_src . $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
257 } else {
258 if ( false === strpos( $this->wp_config_src, $anchor ) ) {
259 throw new Exception( 'Unable to locate placement anchor.' );
260 }
261
262 $new_src = $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
263 $new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor;
264 $contents = str_replace( $anchor, $new_src, $this->wp_config_src );
265 }
266
267 return $this->save( $contents );
268 }
269
270 /**
271 * Updates an existing config in the wp-config.php file.
272 *
273 * @throws Exception If the config value provided is not a string.
274 *
275 * @param string $type Config type (constant or variable).
276 * @param string $name Config name.
277 * @param string $value Config value.
278 * @param array $options (optional) Array of special behavior options.
279 *
280 * @return bool
281 * @since 1.0.0
282 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
283 */
284 public function update( $type, $name, $value, array $options = array() ) {
285 if ( ! is_string( $value ) ) {
286 throw new Exception( 'Config value must be a string.' );
287 }
288
289 // $defaults = array(
290 // 'add' => true, // Add the config if missing.
291 // 'raw' => false, // Display value in raw format without quotes.
292 // 'normalize' => false, // Normalize config output using WP Coding Standards.
293 // );
294
295 // list( $add, $raw, $normalize ) = array_values( array_merge( $defaults, $options ) );
296 list( $add, $raw, $normalize ) = array_values( $options );
297
298 $add = (bool) $add;
299 $raw = (bool) $raw;
300 $normalize = (bool) $normalize;
301
302 if ( ! $this->exists( $type, $name ) ) {
303 return ( $add ) ? $this->add( $type, $name, $value ) : false;
304 }
305
306 $old_src = $this->wp_configs[ $type ][ $name ]['src'];
307 $old_value = $this->wp_configs[ $type ][ $name ]['value'];
308 $new_value = $this->format_value( $value, $raw );
309
310 if ( $normalize ) {
311 $new_src = $this->normalize( $type, $name, $new_value );
312 } else {
313 $new_parts = $this->wp_configs[ $type ][ $name ]['parts'];
314 $new_parts[1] = str_replace( $old_value, $new_value, $new_parts[1] ); // Only edit the value part.
315 $new_src = implode( '', $new_parts );
316 }
317
318 $contents = preg_replace(
319 sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
320 '$1' . str_replace( '$', '\$', trim( $new_src ) ),
321 $this->wp_config_src
322 );
323
324 return $this->save( $contents );
325 }
326
327 /**
328 * Removes a config from the wp-config.php file.
329 *
330 * @param string $type Config type (constant or variable).
331 * @param string $name Config name.
332 *
333 * @return bool
334 * @since 1.0.0
335 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
336 */
337 public function remove( $type, $name ) {
338 if ( ! $this->exists( $type, $name ) ) {
339 return false;
340 }
341
342 $wp_config_src = file_get_contents( $this->wpconfig_file( 'path' ) );
343 $this->wp_config_src = str_replace( array( "\n\r", "\r" ), "\n", $wp_config_src );
344 $this->wp_configs = $this->configs( 'raw' );
345
346 $pattern = sprintf( '/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote( $this->wp_configs[$type][$name]['src'], '/' ) );
347 $contents = preg_replace( $pattern, '$1', $this->wp_config_src );
348
349 return $this->save( $contents );
350 }
351
352 /**
353 * Applies formatting to a config value.
354 *
355 * @throws Exception When a raw value is requested for an empty string.
356 *
357 * @param string $value Config value.
358 * @param bool $raw Display value in raw format without quotes.
359 *
360 * @return mixed
361 * @since 1.0.0
362 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
363 */
364 public function format_value( $value, $raw ) {
365 if ( $raw && '' === trim( $value ) ) {
366 throw new Exception( 'Raw value for empty string not supported.' );
367 }
368
369 return ( $raw ) ? $value : var_export( $value, true );
370 }
371
372 /**
373 * Normalizes the source output for a name/value pair.
374 *
375 * @throws Exception If the requested config type does not support normalization.
376 *
377 * @param string $type Config type (constant or variable).
378 * @param string $name Config name.
379 * @param mixed $value Config value.
380 *
381 * @return string
382 * @since 1.0.0
383 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
384 */
385 public function normalize( $type, $name, $value ) {
386 if ( 'constant' === $type ) {
387 $placeholder = "define( '%s', %s );";
388 } elseif ( 'variable' === $type ) {
389 $placeholder = '$%s = %s;';
390 } else {
391 throw new Exception( "Unable to normalize config type '{$type}'." );
392 }
393
394 return sprintf( $placeholder, $name, $value );
395 }
396
397 /**
398 * Saves new contents to the wp-config.php file.
399 *
400 * @throws Exception If the config file content provided is empty.
401 * @throws Exception If there is a failure when saving the wp-config.php file.
402 *
403 * @param string $contents New config contents.
404 *
405 * @return bool
406 * @since 1.0.0
407 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
408 */
409 public function save( $contents ) {
410 if ( ! trim( $contents ) ) {
411 throw new Exception( 'Cannot save the config file with empty contents.' );
412 }
413
414 if ( $contents === $this->wp_config_src ) {
415 return false;
416 }
417
418 $result = file_put_contents( $this->wpconfig_file( 'path' ), $contents, LOCK_EX );
419
420 if ( false === $result ) {
421 throw new Exception( 'Failed to update the config file.' );
422 }
423
424 return true;
425 }
426
427 }