first commit
This commit is contained in:
@@ -0,0 +1,494 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @package Duplicator
|
||||
* @copyright (c) 2022, Snap Creek LLC
|
||||
*/
|
||||
|
||||
namespace Duplicator\Libs\WpConfig;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Transforms a wp-config.php file.
|
||||
* Fork of wp-cli/trnasformer
|
||||
*/
|
||||
class WPConfigTransformer
|
||||
{
|
||||
const REPLACE_TEMP_STIRNG = '_1_2_RePlAcE_3_4_TeMp_5_6_StRiNg_7_8_';
|
||||
|
||||
/**
|
||||
* Path to the wp-config.php file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $wp_config_path;
|
||||
|
||||
/**
|
||||
* Original source of the wp-config.php file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $wp_config_src;
|
||||
|
||||
/**
|
||||
* Array of parsed configs.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected $wp_configs = array();
|
||||
|
||||
/**
|
||||
* Instantiates the class with a valid wp-config.php.
|
||||
*
|
||||
* @throws Exception If the wp-config.php file is missing.
|
||||
* @throws Exception If the wp-config.php file is not writable.
|
||||
*
|
||||
* @param string $wp_config_path Path to a wp-config.php file.
|
||||
*/
|
||||
public function __construct($wp_config_path)
|
||||
{
|
||||
if (! file_exists($wp_config_path)) {
|
||||
throw new Exception('wp-config.php file does not exist. Path:' . $wp_config_path);
|
||||
}
|
||||
// Duplicator Extra
|
||||
/*
|
||||
if ( ! is_writable( $wp_config_path ) ) {
|
||||
throw new Exception( 'wp-config.php file is not writable.' );
|
||||
}
|
||||
*/
|
||||
|
||||
$this->wp_config_path = $wp_config_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a config exists in the wp-config.php file.
|
||||
*
|
||||
* @throws Exception If the wp-config.php file is empty.
|
||||
* @throws Exception If the requested config type is invalid.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($type, $name)
|
||||
{
|
||||
$wp_config_src = file_get_contents($this->wp_config_path);
|
||||
|
||||
if (! trim($wp_config_src)) {
|
||||
throw new Exception('wp-config.php file is empty.');
|
||||
}
|
||||
|
||||
// SnapCreek custom change
|
||||
// Normalize the newline to prevent an issue coming from OSX
|
||||
$wp_config_src = str_replace(array("\r\n", "\r"), "\n", $wp_config_src);
|
||||
|
||||
$this->wp_config_src = $wp_config_src;
|
||||
$this->wp_configs = $this->parseWpConfig($this->wp_config_src);
|
||||
|
||||
if (! isset($this->wp_configs[ $type ])) {
|
||||
throw new Exception("Config type '{$type}' does not exist.");
|
||||
}
|
||||
|
||||
return isset($this->wp_configs[ $type ][ $name ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a config in the wp-config.php file.
|
||||
*
|
||||
* @throws Exception If the wp-config.php file is empty.
|
||||
* @throws Exception If the requested config type is invalid.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
* @param bool $get_real_value if true return real value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue($type, $name, $get_real_value = true)
|
||||
{
|
||||
$wp_config_src = file_get_contents($this->wp_config_path);
|
||||
if (! trim($wp_config_src)) {
|
||||
throw new Exception('wp-config.php file is empty.');
|
||||
}
|
||||
|
||||
// SnapCreek custom change
|
||||
// Normalize the newline to prevent an issue coming from OSX
|
||||
$wp_config_src = str_replace(array("\r\n", "\r"), "\n", $wp_config_src);
|
||||
|
||||
$this->wp_config_src = $wp_config_src;
|
||||
$this->wp_configs = $this->parseWpConfig($this->wp_config_src);
|
||||
|
||||
if (! isset($this->wp_configs[ $type ])) {
|
||||
throw new Exception("Config type '{$type}' does not exist.");
|
||||
}
|
||||
|
||||
// Duplicator Extra
|
||||
$val = $this->wp_configs[ $type ][ $name ]['value'];
|
||||
if ($get_real_value) {
|
||||
return self::getRealValFromVal($val);
|
||||
} else {
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get typed val from string val
|
||||
*
|
||||
* @param string $val string value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getRealValFromVal($val)
|
||||
{
|
||||
if ($val[0] === '\'') {
|
||||
// string with '
|
||||
$result = substr($val, 1, strlen($val) - 2);
|
||||
return str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $result);
|
||||
} elseif ($val[0] === '"') {
|
||||
// string with "
|
||||
return json_decode(str_replace('\\$', '$', $val));
|
||||
} elseif (strcasecmp($val, 'true') === 0) {
|
||||
return true;
|
||||
} elseif (strcasecmp($val, 'false') === 0) {
|
||||
return false;
|
||||
} elseif (strcasecmp($val, 'null') === 0) {
|
||||
return null;
|
||||
} elseif (preg_match('/^[-+]?[0-9]+$/', $val)) {
|
||||
return (int) $val;
|
||||
} elseif (preg_match('/^[-+]?[0-9]+\.[0-9]+$/', $val)) {
|
||||
return (float) $val;
|
||||
} else {
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a config to the wp-config.php file.
|
||||
*
|
||||
* @throws Exception If the config value provided is not a string.
|
||||
* @throws Exception If the config placement anchor could not be located.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
* @param string $value Config value.
|
||||
* @param array<string, mixed> $options (optional) Array of special behavior options.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function add($type, $name, $value, array $options = array())
|
||||
{
|
||||
if (! is_string($value)) {
|
||||
throw new Exception('Config value must be a string.');
|
||||
}
|
||||
|
||||
if ($this->exists($type, $name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'raw' => false, // Display value in raw format without quotes.
|
||||
'anchor' => "/* That's all, stop editing!", // Config placement anchor string.
|
||||
'separator' => PHP_EOL, // Separator between config definition and anchor string.
|
||||
'placement' => 'before', // Config placement direction (insert before or after).
|
||||
);
|
||||
|
||||
list( $raw, $anchor, $separator, $placement ) = array_values(array_merge($defaults, $options));
|
||||
|
||||
$raw = (bool) $raw;
|
||||
$anchor = (string) $anchor;
|
||||
$separator = (string) $separator;
|
||||
$placement = (string) $placement;
|
||||
|
||||
// Custom code by the SnapCreek Team
|
||||
if (false === strpos($this->wp_config_src, $anchor)) {
|
||||
$other_anchor_points = array(
|
||||
'/** Absolute path to the WordPress directory',
|
||||
// ABSPATH defined check with single quote
|
||||
"if ( !defined('ABSPATH') )",
|
||||
"if ( ! defined( 'ABSPATH' ) )",
|
||||
"if (!defined('ABSPATH') )",
|
||||
"if(!defined('ABSPATH') )",
|
||||
"if(!defined('ABSPATH'))",
|
||||
"if ( ! defined( 'ABSPATH' ))",
|
||||
"if ( ! defined( 'ABSPATH') )",
|
||||
"if ( ! defined('ABSPATH' ) )",
|
||||
"if (! defined( 'ABSPATH' ))",
|
||||
"if (! defined( 'ABSPATH') )",
|
||||
"if (! defined('ABSPATH' ) )",
|
||||
"if ( !defined( 'ABSPATH' ))",
|
||||
"if ( !defined( 'ABSPATH') )",
|
||||
"if ( !defined('ABSPATH' ) )",
|
||||
"if( !defined( 'ABSPATH' ))",
|
||||
"if( !defined( 'ABSPATH') )",
|
||||
"if( !defined('ABSPATH' ) )",
|
||||
// ABSPATH defined check with double quote
|
||||
'if ( !defined("ABSPATH") )',
|
||||
'if ( ! defined( "ABSPATH" ) )',
|
||||
'if (!defined("ABSPATH") )',
|
||||
'if(!defined("ABSPATH") )',
|
||||
'if(!defined("ABSPATH"))',
|
||||
'if ( ! defined( "ABSPATH" ))',
|
||||
'if ( ! defined( "ABSPATH") )',
|
||||
'if ( ! defined("ABSPATH" ) )',
|
||||
'if (! defined( "ABSPATH" ))',
|
||||
'if (! defined( "ABSPATH") )',
|
||||
'if (! defined("ABSPATH" ) )',
|
||||
'if ( !defined( "ABSPATH" ))',
|
||||
'if ( !defined( "ABSPATH") )',
|
||||
'if ( !defined("ABSPATH" ) )',
|
||||
'if( !defined( "ABSPATH" ))',
|
||||
'if( !defined( "ABSPATH") )',
|
||||
'if( !defined("ABSPATH" ) )',
|
||||
|
||||
'/** Sets up WordPress vars and included files',
|
||||
'require_once(ABSPATH',
|
||||
'require_once ABSPATH',
|
||||
'require_once( ABSPATH',
|
||||
'require_once',
|
||||
"define( 'DB_NAME'",
|
||||
'define( "DB_NAME"',
|
||||
"define('DB_NAME'",
|
||||
'define("DB_NAME"',
|
||||
'require',
|
||||
'include_once',
|
||||
);
|
||||
foreach ($other_anchor_points as $anchor_point) {
|
||||
$anchor_point = (string) $anchor_point;
|
||||
if (false !== strpos($this->wp_config_src, $anchor_point)) {
|
||||
$anchor = $anchor_point;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false === strpos($this->wp_config_src, $anchor)) {
|
||||
throw new Exception('Unable to locate placement anchor.');
|
||||
}
|
||||
|
||||
$new_src = $this->normalize($type, $name, $this->formatValue($value, $raw));
|
||||
$new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor;
|
||||
$contents = str_replace($anchor, $new_src, $this->wp_config_src);
|
||||
|
||||
return $this->save($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing config in the wp-config.php file.
|
||||
*
|
||||
* @throws Exception If the config value provided is not a string.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
* @param string $value Config value.
|
||||
* @param array<string, bool> $options (optional) Array of special behavior options.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update($type, $name, $value, array $options = array())
|
||||
{
|
||||
if (! is_string($value)) {
|
||||
throw new Exception('Config value must be a string.');
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'add' => true, // Add the config if missing.
|
||||
'raw' => false, // Display value in raw format without quotes.
|
||||
'normalize' => false, // Normalize config output using WP Coding Standards.
|
||||
);
|
||||
|
||||
list( $add, $raw, $normalize ) = array_values(array_merge($defaults, $options));
|
||||
|
||||
$add = (bool) $add;
|
||||
$raw = (bool) $raw;
|
||||
$normalize = (bool) $normalize;
|
||||
|
||||
if (! $this->exists($type, $name)) {
|
||||
return ( $add ) ? $this->add($type, $name, $value, $options) : false;
|
||||
}
|
||||
|
||||
$old_src = $this->wp_configs[ $type ][ $name ]['src'];
|
||||
$old_value = $this->wp_configs[ $type ][ $name ]['value'];
|
||||
$new_value = $this->formatValue($value, $raw);
|
||||
|
||||
if ($normalize) {
|
||||
$new_src = $this->normalize($type, $name, $new_value);
|
||||
} else {
|
||||
$new_parts = $this->wp_configs[ $type ][ $name ]['parts'];
|
||||
$new_parts[1] = str_replace($old_value, $new_value, $new_parts[1]); // Only edit the value part.
|
||||
$new_src = implode('', $new_parts);
|
||||
}
|
||||
|
||||
$contents = preg_replace(
|
||||
sprintf('/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote(trim($old_src), '/')),
|
||||
'$1' . self::REPLACE_TEMP_STIRNG,
|
||||
$this->wp_config_src
|
||||
);
|
||||
$contents = str_replace(self::REPLACE_TEMP_STIRNG, trim($new_src), $contents);
|
||||
return $this->save($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a config from the wp-config.php file.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($type, $name)
|
||||
{
|
||||
if (! $this->exists($type, $name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pattern = sprintf('/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote($this->wp_configs[ $type ][ $name ]['src'], '/'));
|
||||
$contents = preg_replace($pattern, '$1', $this->wp_config_src);
|
||||
|
||||
return $this->save($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies formatting to a config value.
|
||||
*
|
||||
* @throws Exception When a raw value is requested for an empty string.
|
||||
*
|
||||
* @param string $value Config value.
|
||||
* @param bool $raw Display value in raw format without quotes.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function formatValue($value, $raw)
|
||||
{
|
||||
if ($raw && '' === trim($value)) {
|
||||
throw new Exception('Raw value for empty string not supported.');
|
||||
}
|
||||
|
||||
return ( $raw ) ? $value : var_export($value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the source output for a name/value pair.
|
||||
*
|
||||
* @throws Exception If the requested config type does not support normalization.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
* @param mixed $value Config value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function normalize($type, $name, $value)
|
||||
{
|
||||
if ('constant' === $type) {
|
||||
$placeholder = "define( '%s', %s );";
|
||||
} elseif ('variable' === $type) {
|
||||
$placeholder = '$%s = %s;';
|
||||
} else {
|
||||
throw new Exception("Unable to normalize config type '{$type}'.");
|
||||
}
|
||||
|
||||
return sprintf($placeholder, $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the source of a wp-config.php file.
|
||||
*
|
||||
* @param string $src Config file source.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function parseWpConfig($src)
|
||||
{
|
||||
$configs = array();
|
||||
$configs['constant'] = array();
|
||||
$configs['variable'] = array();
|
||||
|
||||
if (function_exists('token_get_all')) {
|
||||
// Strip comments.
|
||||
foreach (token_get_all($src) as $token) {
|
||||
if (in_array($token[0], array( T_COMMENT, T_DOC_COMMENT ), true)) {
|
||||
$src = str_replace($token[1], '', $src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preg_match_all(
|
||||
'/(?<=^|;|<\?php\s|<\?\s)' .
|
||||
'(\h*define\s*\(\s*[\'"](\w*?)[\'"]\s*)(,\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*)' .
|
||||
'((?:,\s*(?:true|false)\s*)?\)\s*;)/ims',
|
||||
$src,
|
||||
$constants
|
||||
);
|
||||
preg_match_all('/(?<=^|;|<\?php\s|<\?\s)(\h*\$(\w+)\s*=)(\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*;)/ims', $src, $variables);
|
||||
|
||||
if (
|
||||
!empty($constants[0]) &&
|
||||
!empty($constants[1]) &&
|
||||
!empty($constants[2]) &&
|
||||
!empty($constants[3]) &&
|
||||
!empty($constants[4]) &&
|
||||
!empty($constants[5])
|
||||
) {
|
||||
foreach ($constants[2] as $index => $name) {
|
||||
$configs['constant'][ $name ] = array(
|
||||
'src' => $constants[0][ $index ],
|
||||
'value' => $constants[4][ $index ],
|
||||
'parts' => array(
|
||||
$constants[1][ $index ],
|
||||
$constants[3][ $index ],
|
||||
$constants[5][ $index ],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($variables[0]) && ! empty($variables[1]) && ! empty($variables[2]) && ! empty($variables[3]) && ! empty($variables[4])) {
|
||||
// Remove duplicate(s), last definition wins.
|
||||
$variables[2] = array_reverse(array_unique(array_reverse($variables[2], true)), true);
|
||||
foreach ($variables[2] as $index => $name) {
|
||||
$configs['variable'][ $name ] = array(
|
||||
'src' => $variables[0][ $index ],
|
||||
'value' => $variables[4][ $index ],
|
||||
'parts' => array(
|
||||
$variables[1][ $index ],
|
||||
$variables[3][ $index ],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves new contents to the wp-config.php file.
|
||||
*
|
||||
* @throws Exception If the config file content provided is empty.
|
||||
* @throws Exception If there is a failure when saving the wp-config.php file.
|
||||
*
|
||||
* @param string $contents New config contents.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function save($contents)
|
||||
{
|
||||
if (!trim($contents)) {
|
||||
throw new Exception('Cannot save the wp-config.php file with empty contents.');
|
||||
}
|
||||
|
||||
if ($contents === $this->wp_config_src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = file_put_contents($this->wp_config_path, $contents, LOCK_EX);
|
||||
|
||||
if (false === $result) {
|
||||
throw new Exception('Failed to update the wp-config.php file.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @package Duplicator
|
||||
* @copyright (c) 2022, Snap Creek LLC
|
||||
*/
|
||||
|
||||
namespace Duplicator\Libs\WpConfig;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Transforms a wp-config.php file.
|
||||
*/
|
||||
class WPConfigTransformerSrc extends WPConfigTransformer
|
||||
{
|
||||
/**
|
||||
* Instantiates the class with a valid wp-config.php scr text
|
||||
*
|
||||
* @param string $wp_config_src Path to a wp-config.php file.
|
||||
*/
|
||||
public function __construct($wp_config_src)
|
||||
{
|
||||
// Normalize the newline to prevent an issue coming from OSX
|
||||
$this->wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSrc()
|
||||
{
|
||||
return $this->wp_config_src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a config exists in the wp-config.php src
|
||||
*
|
||||
* @throws Exception If the wp-config.php file is empty.
|
||||
* @throws Exception If the requested config type is invalid.
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($type, $name)
|
||||
{
|
||||
$this->wp_configs = $this->parseWpConfig($this->wp_config_src);
|
||||
|
||||
if (!isset($this->wp_configs[$type])) {
|
||||
throw new Exception("Config type '{$type}' does not exist.");
|
||||
}
|
||||
|
||||
return isset($this->wp_configs[$type][$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a config in the wp-config.php src
|
||||
*
|
||||
* @param string $type Config type (constant or variable).
|
||||
* @param string $name Config name.
|
||||
* @param bool $get_real_value if true return typed value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue($type, $name, $get_real_value = true)
|
||||
{
|
||||
$this->wp_configs = $this->parseWpConfig($this->wp_config_src);
|
||||
|
||||
if (!isset($this->wp_configs[$type])) {
|
||||
throw new Exception("Config type '{$type}' does not exist.");
|
||||
}
|
||||
|
||||
// Duplicator Extra
|
||||
$val = $this->wp_configs[$type][$name]['value'];
|
||||
if ($get_real_value) {
|
||||
return self::getRealValFromVal($val);
|
||||
} else {
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update wp_config_src
|
||||
*
|
||||
* @param string $contents config content
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function save($contents)
|
||||
{
|
||||
$this->wp_config_src = $contents;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user