PluginProbe
Debug Log Manager – Conveniently Monitor and Inspect Errors / 1.5.3
Debug Log Manager – Conveniently Monitor and Inspect Errors v1.5.3
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 1.5.3, at classes/class-wp-config-transformer.php

419 lines 13.1 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 $defaults = array(
233 'raw' => $raw_input, // Display value in raw format without quotes.
234 'anchor' => "/* That's all, stop editing! Happy publishing. */", // Config placement anchor string.
235 'separator' => PHP_EOL, // Separator between config definition and anchor string.
236 'placement' => 'before', // Config placement direction (insert before or after).
237 );
238
239 // list( $raw, $anchor, $separator, $placement ) = array_values( $options );
240 list( $raw, $anchor, $separator, $placement ) = array_values( array_merge( $defaults, $options ) );;
241
242 $raw = (bool) $raw;
243 $anchor = (string) $anchor;
244 $separator = (string) $separator;
245 $placement = (string) $placement;
246
247 if ( 'EOF' === $anchor ) {
248 $contents = $this->wp_config_src . $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
249 } else {
250 if ( false === strpos( $this->wp_config_src, $anchor ) ) {
251 throw new Exception( 'Unable to locate placement anchor.' );
252 }
253
254 $new_src = $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
255 $new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor;
256 $contents = str_replace( $anchor, $new_src, $this->wp_config_src );
257 }
258
259 return $this->save( $contents );
260 }
261
262 /**
263 * Updates an existing config in the wp-config.php file.
264 *
265 * @throws Exception If the config value provided is not a string.
266 *
267 * @param string $type Config type (constant or variable).
268 * @param string $name Config name.
269 * @param string $value Config value.
270 * @param array $options (optional) Array of special behavior options.
271 *
272 * @return bool
273 * @since 1.0.0
274 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
275 */
276 public function update( $type, $name, $value, array $options = array() ) {
277 if ( ! is_string( $value ) ) {
278 throw new Exception( 'Config value must be a string.' );
279 }
280
281 // $defaults = array(
282 // 'add' => true, // Add the config if missing.
283 // 'raw' => false, // Display value in raw format without quotes.
284 // 'normalize' => false, // Normalize config output using WP Coding Standards.
285 // );
286
287 // list( $add, $raw, $normalize ) = array_values( array_merge( $defaults, $options ) );
288 list( $add, $raw, $normalize ) = array_values( $options );
289
290 $add = (bool) $add;
291 $raw = (bool) $raw;
292 $normalize = (bool) $normalize;
293
294 if ( ! $this->exists( $type, $name ) ) {
295 return ( $add ) ? $this->add( $type, $name, $value ) : false;
296 }
297
298 $old_src = $this->wp_configs[ $type ][ $name ]['src'];
299 $old_value = $this->wp_configs[ $type ][ $name ]['value'];
300 $new_value = $this->format_value( $value, $raw );
301
302 if ( $normalize ) {
303 $new_src = $this->normalize( $type, $name, $new_value );
304 } else {
305 $new_parts = $this->wp_configs[ $type ][ $name ]['parts'];
306 $new_parts[1] = str_replace( $old_value, $new_value, $new_parts[1] ); // Only edit the value part.
307 $new_src = implode( '', $new_parts );
308 }
309
310 $contents = preg_replace(
311 sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
312 '$1' . str_replace( '$', '\$', trim( $new_src ) ),
313 $this->wp_config_src
314 );
315
316 return $this->save( $contents );
317 }
318
319 /**
320 * Removes a config from the wp-config.php file.
321 *
322 * @param string $type Config type (constant or variable).
323 * @param string $name Config name.
324 *
325 * @return bool
326 * @since 1.0.0
327 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
328 */
329 public function remove( $type, $name ) {
330 if ( ! $this->exists( $type, $name ) ) {
331 return false;
332 }
333
334 $wp_config_src = file_get_contents( $this->wpconfig_file( 'path' ) );
335 $this->wp_config_src = str_replace( array( "\n\r", "\r" ), "\n", $wp_config_src );
336 $this->wp_configs = $this->configs( 'raw' );
337
338 $pattern = sprintf( '/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote( $this->wp_configs[$type][$name]['src'], '/' ) );
339 $contents = preg_replace( $pattern, '$1', $this->wp_config_src );
340
341 return $this->save( $contents );
342 }
343
344 /**
345 * Applies formatting to a config value.
346 *
347 * @throws Exception When a raw value is requested for an empty string.
348 *
349 * @param string $value Config value.
350 * @param bool $raw Display value in raw format without quotes.
351 *
352 * @return mixed
353 * @since 1.0.0
354 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
355 */
356 public function format_value( $value, $raw ) {
357 if ( $raw && '' === trim( $value ) ) {
358 throw new Exception( 'Raw value for empty string not supported.' );
359 }
360
361 return ( $raw ) ? $value : var_export( $value, true );
362 }
363
364 /**
365 * Normalizes the source output for a name/value pair.
366 *
367 * @throws Exception If the requested config type does not support normalization.
368 *
369 * @param string $type Config type (constant or variable).
370 * @param string $name Config name.
371 * @param mixed $value Config value.
372 *
373 * @return string
374 * @since 1.0.0
375 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
376 */
377 public function normalize( $type, $name, $value ) {
378 if ( 'constant' === $type ) {
379 $placeholder = "define( '%s', %s );";
380 } elseif ( 'variable' === $type ) {
381 $placeholder = '$%s = %s;';
382 } else {
383 throw new Exception( "Unable to normalize config type '{$type}'." );
384 }
385
386 return sprintf( $placeholder, $name, $value );
387 }
388
389 /**
390 * Saves new contents to the wp-config.php file.
391 *
392 * @throws Exception If the config file content provided is empty.
393 * @throws Exception If there is a failure when saving the wp-config.php file.
394 *
395 * @param string $contents New config contents.
396 *
397 * @return bool
398 * @since 1.0.0
399 * @link https://plugins.svn.wordpress.org/debug-log-config-tool/tags/1.1/src/Classes/vendor/WPConfigTransformer.php
400 */
401 public function save( $contents ) {
402 if ( ! trim( $contents ) ) {
403 throw new Exception( 'Cannot save the config file with empty contents.' );
404 }
405
406 if ( $contents === $this->wp_config_src ) {
407 return false;
408 }
409
410 $result = file_put_contents( $this->wpconfig_file( 'path' ), $contents, LOCK_EX );
411
412 if ( false === $result ) {
413 throw new Exception( 'Failed to update the config file.' );
414 }
415
416 return true;
417 }
418
419 }