PluginProbe ʕ •ᴥ•ʔ
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 2.13.0
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v2.13.0
4.4.2 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.11.1 1.11.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 2.0.0 2.0.1 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.10.0 2.10.1 2.11.0 2.11.1 2.11.2 2.11.3 2.11.4 2.12.0 2.13.0 2.14.0 2.14.1 2.15.0 2.15.1 2.16.0 2.16.1 2.16.2 2.16.3 2.17.0 2.17.1 2.17.2 2.18.0 2.19.0 2.19.2 2.19.3 2.19.4 2.2.0 2.2.1 2.20.0 2.20.1 2.20.2 2.20.3 2.20.4 2.20.5 2.20.6 2.21.0 2.22.0 2.22.1 2.23.0 2.24.0 2.25.0 2.25.1 2.25.2 2.26.0 2.27.0 2.27.1 2.28.0 2.29.0 2.29.1 2.29.2 2.29.3 2.29.4 2.3.0 2.3.1 2.30.0 2.31.0 2.31.1 2.31.2 2.31.3 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.40.0 2.40.1 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.9.0 3.0.0 3.0.0-RC1 3.0.0-RC2 3.0.0-beta1 3.0.0-beta2 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.10.0 3.10.1 3.11.0 3.12.0 3.13.0 3.13.1 3.13.2 3.13.3 3.13.4 3.14.0 3.15.0 3.15.1 3.15.2 3.15.3 3.15.4 3.15.5 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.16.6 3.16.7 3.16.8 3.17.0 3.17.1 3.17.2 3.17.3 3.17.4 3.17.5 3.17.6 3.18.0 3.19.0 3.19.1 3.19.2 3.2.0 3.2.1 3.2.2 3.20.0 3.20.1 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 4.0.0 4.0.1 4.0.2 4.0.3 trunk 4.1.0 0.2.19.1 4.1.1 1.0.0 4.2.0 1.0.1 1.0.2
surecart / app / src / Permissions / WPConfig / WPConfigTransformService.php
surecart / app / src / Permissions / WPConfig Last commit date
WPConfigTransformService.php 3 years ago
WPConfigTransformService.php
382 lines
1 <?php
2
3 namespace SureCart\Permissions\WPConfig;
4
5 // The MIT License (MIT)
6
7 // Copyright (C) 2011-2018 WP-CLI Development Group (https://github.com/wp-cli/wp-config-transformer/contributors)
8
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26
27 /**
28 * Transforms a wp-config.php file.
29 */
30 class WPConfigTransformService {
31 /**
32 * Append to end of file
33 */
34 const ANCHOR_EOF = 'EOF';
35
36 /**
37 * Path to the wp-config.php file.
38 *
39 * @var string
40 */
41 protected $wp_config_path;
42
43 /**
44 * Original source of the wp-config.php file.
45 *
46 * @var string
47 */
48 protected $wp_config_src;
49
50 /**
51 * Array of parsed configs.
52 *
53 * @var array
54 */
55 protected $wp_configs = array();
56
57 /**
58 * Instantiates the class with a valid wp-config.php.
59 *
60 * @throws \Exception If the wp-config.php file is missing.
61 * @throws \Exception If the wp-config.php file is not writable.
62 *
63 * @param string $wp_config_path Path to a wp-config.php file.
64 */
65 public function __construct( $wp_config_path ) {
66 $basename = basename( $wp_config_path );
67
68 if ( ! file_exists( $wp_config_path ) ) {
69 throw new \Exception( "{$basename} does not exist." );
70 }
71
72 if ( ! is_writable( $wp_config_path ) ) {
73 throw new \Exception( "{$basename} is not writable." );
74 }
75
76 $this->wp_config_path = $wp_config_path;
77 }
78
79 /**
80 * Checks if a config exists in the wp-config.php file.
81 *
82 * @throws \Exception If the wp-config.php file is empty.
83 * @throws \Exception If the requested config type is invalid.
84 *
85 * @param string $type Config type (constant or variable).
86 * @param string $name Config name.
87 *
88 * @return bool
89 */
90 public function exists( $type, $name ) {
91 $wp_config_src = file_get_contents( $this->wp_config_path );
92
93 if ( ! trim( $wp_config_src ) ) {
94 throw new \Exception( 'Config file is empty.' );
95 }
96 // Normalize the newline to prevent an issue coming from OSX.
97 $this->wp_config_src = str_replace( array( "\n\r", "\r" ), "\n", $wp_config_src );
98 $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
99
100 if ( ! isset( $this->wp_configs[ $type ] ) ) {
101 throw new \Exception( "Config type '{$type}' does not exist." );
102 }
103
104 return isset( $this->wp_configs[ $type ][ $name ] );
105 }
106
107 /**
108 * Get the value of a config in the wp-config.php file.
109 *
110 * @throws \Exception If the wp-config.php file is empty.
111 * @throws \Exception If the requested config type is invalid.
112 *
113 * @param string $type Config type (constant or variable).
114 * @param string $name Config name.
115 *
116 * @return array
117 */
118 public function get_value( $type, $name ) {
119 $wp_config_src = file_get_contents( $this->wp_config_path );
120
121 if ( ! trim( $wp_config_src ) ) {
122 throw new \Exception( 'Config file is empty.' );
123 }
124
125 $this->wp_config_src = $wp_config_src;
126 $this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
127
128 if ( ! isset( $this->wp_configs[ $type ] ) ) {
129 throw new \Exception( "Config type '{$type}' does not exist." );
130 }
131
132 return $this->wp_configs[ $type ][ $name ]['value'];
133 }
134
135 /**
136 * Adds a config to the wp-config.php file.
137 *
138 * @throws \Exception If the config value provided is not a string.
139 * @throws \Exception If the config placement anchor could not be located.
140 *
141 * @param string $type Config type (constant or variable).
142 * @param string $name Config name.
143 * @param string $value Config value.
144 * @param array $options (optional) Array of special behavior options.
145 *
146 * @return bool
147 */
148 public function add( $type, $name, $value, array $options = array() ) {
149 if ( ! is_string( $value ) ) {
150 throw new \Exception( 'Config value must be a string.' );
151 }
152
153 if ( $this->exists( $type, $name ) ) {
154 return false;
155 }
156
157 $defaults = array(
158 'raw' => false, // Display value in raw format without quotes.
159 'anchor' => "/* That's all, stop editing!", // Config placement anchor string.
160 'separator' => PHP_EOL, // Separator between config definition and anchor string.
161 'placement' => 'before', // Config placement direction (insert before or after).
162 );
163
164 list( $raw, $anchor, $separator, $placement ) = array_values( array_merge( $defaults, $options ) );
165
166 $raw = (bool) $raw;
167 $anchor = (string) $anchor;
168 $separator = (string) $separator;
169 $placement = (string) $placement;
170
171 if ( self::ANCHOR_EOF === $anchor ) {
172 $contents = $this->wp_config_src . $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
173 } else {
174 if ( false === strpos( $this->wp_config_src, $anchor ) ) {
175 throw new \Exception( 'Unable to locate placement anchor.' );
176 }
177
178 $new_src = $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
179 $new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor;
180 $contents = str_replace( $anchor, $new_src, $this->wp_config_src );
181 }
182
183 return $this->save( $contents );
184 }
185
186 /**
187 * Updates an existing config in the wp-config.php file.
188 *
189 * @throws \Exception If the config value provided is not a string.
190 *
191 * @param string $type Config type (constant or variable).
192 * @param string $name Config name.
193 * @param string $value Config value.
194 * @param array $options (optional) Array of special behavior options.
195 *
196 * @return bool
197 */
198 public function update( $type, $name, $value, array $options = array() ) {
199 if ( ! is_string( $value ) ) {
200 throw new \Exception( 'Config value must be a string.' );
201 }
202
203 $defaults = array(
204 'add' => true, // Add the config if missing.
205 'raw' => false, // Display value in raw format without quotes.
206 'normalize' => false, // Normalize config output using WP Coding Standards.
207 );
208
209 list( $add, $raw, $normalize ) = array_values( array_merge( $defaults, $options ) );
210
211 $add = (bool) $add;
212 $raw = (bool) $raw;
213 $normalize = (bool) $normalize;
214
215 if ( ! $this->exists( $type, $name ) ) {
216 return ( $add ) ? $this->add( $type, $name, $value, $options ) : false;
217 }
218
219 $old_src = $this->wp_configs[ $type ][ $name ]['src'];
220 $old_value = $this->wp_configs[ $type ][ $name ]['value'];
221 $new_value = $this->format_value( $value, $raw );
222
223 if ( $normalize ) {
224 $new_src = $this->normalize( $type, $name, $new_value );
225 } else {
226 $new_parts = $this->wp_configs[ $type ][ $name ]['parts'];
227 $new_parts[1] = str_replace( $old_value, $new_value, $new_parts[1] ); // Only edit the value part.
228 $new_src = implode( '', $new_parts );
229 }
230
231 $contents = preg_replace(
232 sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
233 '$1' . str_replace( '$', '\$', trim( $new_src ) ),
234 $this->wp_config_src
235 );
236
237 return $this->save( $contents );
238 }
239
240 /**
241 * Removes a config from the wp-config.php file.
242 *
243 * @param string $type Config type (constant or variable).
244 * @param string $name Config name.
245 *
246 * @return bool
247 */
248 public function remove( $type, $name ) {
249 if ( ! $this->exists( $type, $name ) ) {
250 return false;
251 }
252
253 $pattern = sprintf( '/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote( $this->wp_configs[ $type ][ $name ]['src'], '/' ) );
254 $contents = preg_replace( $pattern, '$1', $this->wp_config_src );
255
256 return $this->save( $contents );
257 }
258
259 /**
260 * Applies formatting to a config value.
261 *
262 * @throws \Exception When a raw value is requested for an empty string.
263 *
264 * @param string $value Config value.
265 * @param bool $raw Display value in raw format without quotes.
266 *
267 * @return mixed
268 */
269 protected function format_value( $value, $raw ) {
270 if ( $raw && '' === trim( $value ) ) {
271 throw new \Exception( 'Raw value for empty string not supported.' );
272 }
273
274 return ( $raw ) ? $value : var_export( $value, true );
275 }
276
277 /**
278 * Normalizes the source output for a name/value pair.
279 *
280 * @throws \Exception If the requested config type does not support normalization.
281 *
282 * @param string $type Config type (constant or variable).
283 * @param string $name Config name.
284 * @param mixed $value Config value.
285 *
286 * @return string
287 */
288 protected function normalize( $type, $name, $value ) {
289 if ( 'constant' === $type ) {
290 $placeholder = "define( '%s', %s );";
291 } elseif ( 'variable' === $type ) {
292 $placeholder = '$%s = %s;';
293 } else {
294 throw new \Exception( "Unable to normalize config type '{$type}'." );
295 }
296
297 return sprintf( $placeholder, $name, $value );
298 }
299
300 /**
301 * Parses the source of a wp-config.php file.
302 *
303 * @param string $src Config file source.
304 *
305 * @return array
306 */
307 protected function parse_wp_config( $src ) {
308 $configs = array();
309 $configs['constant'] = array();
310 $configs['variable'] = array();
311
312 // Strip comments.
313 foreach ( token_get_all( $src ) as $token ) {
314 if ( in_array( $token[0], array( T_COMMENT, T_DOC_COMMENT ), true ) ) {
315 $src = str_replace( $token[1], '', $src );
316 }
317 }
318
319 preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*define\s*\(\s*[\'"](\w*?)[\'"]\s*)(,\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*)((?:,\s*(?:true|false)\s*)?\)\s*;)/ims', $src, $constants );
320 preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*\$(\w+)\s*=)(\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*;)/ims', $src, $variables );
321
322 if ( ! empty( $constants[0] ) && ! empty( $constants[1] ) && ! empty( $constants[2] ) && ! empty( $constants[3] ) && ! empty( $constants[4] ) && ! empty( $constants[5] ) ) {
323 foreach ( $constants[2] as $index => $name ) {
324 $configs['constant'][ $name ] = array(
325 'src' => $constants[0][ $index ],
326 'value' => $constants[4][ $index ],
327 'parts' => array(
328 $constants[1][ $index ],
329 $constants[3][ $index ],
330 $constants[5][ $index ],
331 ),
332 );
333 }
334 }
335
336 if ( ! empty( $variables[0] ) && ! empty( $variables[1] ) && ! empty( $variables[2] ) && ! empty( $variables[3] ) && ! empty( $variables[4] ) ) {
337 // Remove duplicate(s), last definition wins.
338 $variables[2] = array_reverse( array_unique( array_reverse( $variables[2], true ) ), true );
339 foreach ( $variables[2] as $index => $name ) {
340 $configs['variable'][ $name ] = array(
341 'src' => $variables[0][ $index ],
342 'value' => $variables[4][ $index ],
343 'parts' => array(
344 $variables[1][ $index ],
345 $variables[3][ $index ],
346 ),
347 );
348 }
349 }
350
351 return $configs;
352 }
353
354 /**
355 * Saves new contents to the wp-config.php file.
356 *
357 * @throws \Exception If the config file content provided is empty.
358 * @throws \Exception If there is a failure when saving the wp-config.php file.
359 *
360 * @param string $contents New config contents.
361 *
362 * @return bool
363 */
364 protected function save( $contents ) {
365 if ( ! trim( $contents ) ) {
366 throw new \Exception( 'Cannot save the config file with empty contents.' );
367 }
368
369 if ( $contents === $this->wp_config_src ) {
370 return false;
371 }
372
373 $result = file_put_contents( $this->wp_config_path, $contents, LOCK_EX );
374
375 if ( false === $result ) {
376 throw new \Exception( 'Failed to update the config file.' );
377 }
378
379 return true;
380 }
381 }
382