<?php
namespace WpInstaller;
class Core {
// List of added plugins
private $plugins;
private $config_filename;
private $is_installed;
function __construct(string $config_filename) {
$this->config_filename = $config_filename;
}
// Returns a function that can be passed to FileManager::transform_file() to update
// wp-config.php
public static function conf_transform_function (array $constant_values, string $table_prefix) {
return function ($line) use (&$constant_values, $table_prefix) {
// If the current line matches one of our constants return an updated line and remove
// the constant from our list.
$names = array_keys($constant_values);
foreach ($names as $name) {
$pattern = self::_conf_transform_define_pattern( $name );
if (preg_match($pattern, $line)) {
$value = $constant_values[ $name ];
unset($constant_values[ $name ]);
return self::_conf_transform_define_statement(
$name,
self::_conf_transform_serialize_value($name, $value)
);
}
}
// table_prefix is special because it's a variable rather than a constant.
$prefix_patt = self::_conf_transform_table_prefix_pattern();
if (preg_match($prefix_patt, $line)) {
$remaining = "\$table_prefix = '$table_prefix';\n";
// Add any constants that haven't yet been accounted for right after the
// table_prefix line.
foreach ($constant_values as $constant => $value) {
$remaining .= self::_conf_transform_define_statement(
$constant,
self::_conf_transform_serialize_value($constant, $value)
);
}
return $remaining;
}
return $line;
};
}
public function perform_install ($site_title, $admin_user, $admin_pw, $admin_email) {
// Set installing status
define('WP_INSTALLING', true);
// Include necessary files
self::require_wp_files([
'wp-load.php',
'wp-admin/includes/upgrade.php',
]);
// Set some superglobal variables that WordPress wants to be able to see during install
$_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'] = explode('.',gethostname())[0];
/*
Preventing wordpress 'welcome' email being sent.
WordPress' install process tries to 'guess' the siteurl for the content of this email,
and it's always wrong. (something like: https://162.241.217.90/json-api/cpanel)
*/
$fake_email = 'wpinstall@localhost.localdomain';
/*
Perform the install
(https://developer.wordpress.org/reference/functions/wp_install)
*/
$install_resp = \wp_install($site_title, $admin_user, $fake_email, true, '', $admin_pw);
// Update the email to be non-fake
$user = new \WP_User($install_resp['user_id']);
$user->user_email = $admin_email;
$user->user_url = "";
$user_update_resp = \wp_insert_user($user);
if ($user_update_resp instanceof \WP_Error) {
$msg = 'Failed to update admin user:' . $user_update_resp->get_error_message();
throw new \Exception($msg);
}
return [
# Important to get 'user_login' from WordPress since it munges what we give it in some
# cases.
'admin_user' => $user->user_login,
'admin_password' => $install_resp['password'],
];
}
public static function require_wp_files ($file_list) {
foreach ($file_list as $file) {
require_once($file);
}
// Some required files turn these off. Turn them back on.
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 0);
}
public function is_installed () {
if ($this->is_installed) {
return true;
}
if (file_exists($this->config_filename) !== true) {
return false;
}
$this->require_wp_files(['wp-load.php']);
if (\is_blog_installed() !== true) {
return false;
}
return $this->is_installed = true;
}
public function set_options (array $options) {
if (!$this->is_installed()) {
throw new \Exception('Tried to set options before WordPress was installed.');
}
foreach ($options as $name => $value) {
if ($name == 'admin_email') {
$this->prevent_admin_email_change_notification();
}
$current_value = \get_option($name);
if ($current_value == $value) {
continue;
}
if ($current_value !== false) {
$update_resp = \update_option($name, $value);
if (!$update_resp && $value !== false) {
throw new \Exception("Failed to update option: $name to $value");
}
}
else {
$add_resp = \add_option($name, $value);
if (!$add_resp && $value !== false) {
throw new \Exception("Failed to add option: $name with value $value");
}
}
}
}
public function activate_plugin ($plugin) {
$this->require_wp_files(['wp-admin/includes/plugin.php']);
// in case we've previously called \get_plugins()
\wp_cache_delete('plugins', 'plugins');
$plugins = array_keys(\get_plugins());
$matching_plugins = preg_grep("/^$plugin/", $plugins);
$installed_plugin = array_shift($matching_plugins);
if (!$installed_plugin) {
throw new \Exception("$plugin wasn't found when we tried to activate it");
}
if (!\is_plugin_active($installed_plugin) ) {
$act_resp = \activate_plugin($installed_plugin);
if (\is_wp_error($act_resp)) {
$details = print_r($act_resp, true);
throw new \Exception("Failed to install $plugin: $details");
}
}
}
private function prevent_admin_email_change_notification () {
// https://developer.wordpress.org/reference/hooks/send_site_admin_email_change_email/
\add_filter('send_site_admin_email_change_email', function () { return false; });
}
public function create_htaccess () {
if (!$this->is_installed()) {
throw new \Exception('Tried to create .htaccess before WordPress was installed.');
}
global $wp_rewrite;
$rules = explode("\n", $wp_rewrite->mod_rewrite_rules());
\insert_with_markers(".htaccess", 'WordPress', $rules);
}
// Will attempt a full update of of the core as well as all installed themes, plugins
public function update_installation () {
if (!$this->is_installed()) {
throw new \Exception('Tried to update a WordPress site that was not installed.');
}
$this->require_wp_files([
'wp-admin/includes/update.php',
'wp-admin/includes/file.php',
'wp-admin/includes/class-wp-automatic-updater.php',
'wp-admin/includes/class-wp-upgrader.php',
'wp-admin/includes/class-plugin-upgrader.php',
'wp-admin/includes/class-theme-upgrader.php',
]);
\add_filter('allow_major_auto_core_updates', '__return_true');
\add_filter('allow_minor_auto_core_updates', '__return_true');
\add_filter('auto_update_plugin', '__return_true');
\add_filter('auto_update_theme', '__return_true');
\add_filter('auto_update_translation', '__return_true');
( new \WP_Automatic_Updater() )->run();
}
// Returns a pattern that can be used to find existing define() statements in wp-config.php
// that match the constants we wish to add or update.
public static function _conf_transform_define_pattern ($constant_name) {
return "/^\s*define\s*\(\s*[\"']{$constant_name}[\"']\s*,/i";
}
public static function _conf_transform_table_prefix_pattern () {
return '/^\s*\$table_prefix\s*=/';
}
public static function _conf_transform_define_statement ($constant, $value) {
return "define('$constant', $value);\n";
}
// Ensures we write the correct output for each given value type
public static function _conf_transform_serialize_value ($constant, $value) {
$type = gettype($value);
// Dont put quotes around intenger values
if ($type == 'integer') {
return $value;
}
// Make booleans print as 'true' and 'false' rather than '1' and ''
if ($type == 'boolean') {
return $value ? 'true' : 'false';
}
// Print the literal NULL
if ($type == 'NULL') {
return 'NULL';
}
// Escape single quotes for strings
if ($type == 'string') {
$singles_escaped = str_replace("'", "\'", $value);
return "'$singles_escaped'";
}
throw new \Exception("Unexpected value type: $type for constant: $constant");
}
}
?>