init();
// @todo: check for wp-cli and offer quick install via
// set ups from orbisius.com account.
$ctrl->preRun();
// Do we define quick run without theme loading???
// This WP load may fail which we'll check()
$wp_load_locations = array(
dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'wp-load.php',
dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'wp-load.php',
dirname( dirname( dirname( __FILE__ ) ) ) . DIRECTORY_SEPARATOR . 'wp-load.php',
dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . DIRECTORY_SEPARATOR . 'wp-load.php',
dirname( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) ) . DIRECTORY_SEPARATOR . 'wp-load.php',
);
foreach ( $wp_load_locations as $wp_load_php ) {
if ( file_exists( $wp_load_php ) ) {
include_once( $wp_load_php );
if ( defined( 'ABSPATH' ) ) {
break;
}
}
}
// This stops WP Super Cache and W3 Total Cache from caching
defined( 'WP_CACHE' ) || define( 'WP_CACHE', false );
$ctrl->check();
$ctrl->run();
$ctrl->postRun();
} catch (Exception $e) {
echo "Error: " . htmlentities($e->getMessage());
} finally {
$dbg_output = ob_get_clean();
echo $dbg_output;
}
/**
*
*/
class Orbisius_WP_SAK_Controller_Module {
protected $description = '';
private $params = array();
public function init($params = null) {
if (!is_null($params)) {
$this->params = $params;
}
}
public function handleAction() {
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, json_encode( array('status' => 0, 'message' => "Invalid Action") ) );
}
/**
* Descripton about what the module does
*/
public function getInfo() {
return $this->description;
}
/**
* Descripton about what the module does
*/
public function run() {
trigger_error("Module doesn't implement run() method.", E_USER_ERROR);
}
}
/**
* Self_Protect Module - Make sure that only one user can access SAK.
*/
class Orbisius_WP_SAK_Controller_Module_Self_Protect extends Orbisius_WP_SAK_Controller_Module {
private $first_run_file;
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->first_run_file = Orbisius_WP_SAK_Util::getWPUploadsDir() . '.ht-sak4wp-' . ORBISIUS_WP_SAK_HOST;
$this->description = <<Self Protect
This module allows you to run SAK4WP more securely. The first time you access SAK4WP, it will save your IP and browser info.
If somebody else accesses the file from a different IP or browser, he/she will be stopped.
The module doesn't require any configurations. It is always run before other modules.
EOF;
}
/**
* Creates a first run file and stores IP + browser info
*/
public function run() {
$buff = '';
$this->checkFirstRun();
return $buff;
}
/**
* Checks if the script is access from a different IP or browser.
* It dies with an error
*/
public function checkFirstRun() {
// Creates a (host specific) file which stops people from accessing SAK4WP as the same time as you.
$first_run_file = $this->first_run_file;
$ip = Orbisius_WP_SAK_Util::getIP();
$ua = empty($_SERVER['HTTP_USER_AGENT']) ? '' : $_SERVER['HTTP_USER_AGENT'];
if (file_exists($first_run_file)) {
$data = Orbisius_WP_SAK_Util_File::read($first_run_file, Orbisius_WP_SAK_Util_File::UNSERIALIZE);
// If any of the recorded info is different, we don't want to deal with that person.
if (empty($data) || $data['ip'] != $ip || $data['ua'] != $ua) {
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$ctrl->doExit('Error');
}
} else {
$creation_time = time();
$data['ua'] = $ua;
$data['ip'] = $ip;
$data['creation_time'] = $creation_time;
$data['hash'] = sha1($ua . $ip . $creation_time . ORBISIUS_WP_SAK_HOST);
Orbisius_WP_SAK_Util_File::write($first_run_file, $data, Orbisius_WP_SAK_Util_File::SERIALIZE);
}
return true;
}
/**
* Removes the first run file. This file prevents other users from accessing the file.
* Even the browser has to match.
*/
public function clean() {
unlink($this->first_run_file);
}
}
/**
* Example Module - Handles ...
*/
class Orbisius_WP_SAK_Controller_Module_Example extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<Example
This module allows you to ...
EOF;
}
/**
*
*/
public function run() {
$buff = '';
if (!empty($_REQUEST['cmd'])) {
if ($_REQUEST['cmd'] == 'command') {
$text = empty($_REQUEST['text']) ? substr(sha1(mt_rand(100, 1000) . time()), 0, 6) : trim($_REQUEST['text']);
$this->doSomething($text);
$buff .= " ";
}
}
// Let's show delete button if any if the files exists.
if ($ht_files_exist) {
$buff .= "
\n";
}
return $buff;
}
/**
* Sample Method
*/
public function doSomething($text) {
return $text;
}
}
/**
* Example Module - Handles ...
*/
class Orbisius_WP_SAK_Controller_Module_PostMeta extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<Post Meta
This module allows you to view and edit post meta information.
";
$buff .= "\n";
if (!empty($_REQUEST['cmd'])) {
if ($_REQUEST['cmd'] == 'delete_post_meta') {
$post_id = empty($_REQUEST['post_id']) ? 0 : $_REQUEST['post_id'];
$this->deletePostMeta($post_id, $meta_key);
}
if ($_REQUEST['cmd'] == 'edit_post_meta') {
$this->setPostMeta($post_id, $meta_key, $meta_value);
}
// This should fetch the freshest info.
if ($_REQUEST['cmd'] == 'get_post_meta') {
$buff .= $this->getMetaAsString($post_id);
$buff .= " ";
}
}
return $buff;
}
/**
* This method is called when we have the module and action specified.
*/
public function getPostMetaAjaxAction() {
$msg = '';
$result_html = '';
$status = 1;
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$post_ids_list = $ctrl->getVar('post_id'); // could be 1 or more IDs
$ids = explode(',', $post_ids_list);
$ids = array_map('trim', $ids);
$ids = array_filter($ids); // non empty ones
$ids = array_unique($ids);
foreach ($ids as $post_id) {
// If the user has entered a slug we'll use it to get the post ID
if (!is_numeric($post_id)) {
$post = get_page_by_path($post_id);
if (empty($post)) {
$result_html .= Orbisius_WP_SAK_Util::msg('Path: [' . esc_attr($post_id) . '] was not found. Skipping. ', 0);
continue;
}
$post_id = $post->ID;
}
$result_html .= $this->getMetaAsString($post_id);
}
$result_status = array('status' => $status, 'message' => $msg, 'results' => $result_html, );
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $result_status);
}
/**
* This method is called when we have the module and action specified.
*/
public function setPostMetaAjaxAction() {
$msg = '';
$result_html = '';
$status = 1;
$cmd = isset($_REQUEST['cmd']) ? trim($_REQUEST['cmd']) : null;
$cmd_label = preg_match('#delete#si', $cmd) ? 'Delete Meta' : 'Update Meta';
// raw data
$meta_key = empty($_REQUEST['meta_key']) ? '' : trim($_REQUEST['meta_key']);
$meta_value = isset($_REQUEST['meta_value']) ? trim($_REQUEST['meta_value']) : null;
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$post_ids_list = $ctrl->getVar('post_id'); // could be 1 or more IDs
$ids = explode(',', $post_ids_list);
$ids = array_map('trim', $ids);
$ids = array_filter($ids); // non empty ones
$ids = array_unique($ids);
foreach ($ids as $post_id) {
// If the user has entered a slug we'll use it to get the post ID
if (!is_numeric($post_id)) {
$post = get_page_by_path($post_id);
if (empty($post)) {
$result_html .= Orbisius_WP_SAK_Util::msg('Path: [' . esc_attr($post_id) . '] was not found. Skipping. ', 0);
continue;
}
$post_id = $post->ID;
}
$res = $this->setPostMeta($post_id, $meta_key, $meta_value);
$result_html .= ($res === false)
? Orbisius_WP_SAK_Util::msg($cmd_label . ' Error. post meta for post/page ID: ' . esc_attr($post_id) . '] or the new value matches the old one. ', 0)
: Orbisius_WP_SAK_Util::msg($cmd_label. ' OK meta for post/page ID: ' . esc_attr($post_id) . ']. ', 1);
}
$result_status = array('status' => $status, 'message' => $msg, 'results' => $result_html, );
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $result_status);
}
/**
*
* @param int $post_id
* @param string $meta_key
* @param string $meta_value
* @see https://codex.wordpress.org/Function_Reference/update_post_meta
*/
public function setPostMeta($post_id, $meta_key, $meta_value) {
if ( is_null( $meta_value ) ) {
$mixed_res = delete_post_meta($post_id, $meta_key);
} else {
/*Returns meta_id if the meta doesn't exist, otherwise returns true on success and false on failure.
* NOTE: If the meta_value passed to this function is the same as the value that is already in the database, this function returns false. */
$mixed_res = update_post_meta($post_id, $meta_key, $meta_value);
}
return $mixed_res;
}
/**
* Sample Method
*/
public function getMetaAsString($post_id) {
$str = '';
$post = get_post($post_id);
$meta = !empty($post)
? get_post_meta($post_id)
: null;
$author_meta = !empty($post->post_author)
? get_user_meta($post->post_author)
: null;
$link_str = '';
if (!empty($post)) {
$link = get_permalink($post_id);
$link_str = "(View)";
}
// if the item is one element that means that it's one value
if (count($meta) == 1) {
$meta = $meta[0];
}
$str .= "
Post/Page ID: $post_id $link_str
" . var_export($post, 1) . "
\n";
$str .= '
Post/Page Meta
' . var_export($meta, 1) . "
\n";
$str .= '
Author Meta
' . var_export($author_meta, 1) . "
\n";
return $str;
}
}
/**
* Example Module - Handles ...
*/
class Orbisius_WP_SAK_Controller_Module_UserMeta extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<User Meta
This module allows you to view and edit user meta information.
";
$buff .= "\n";
if (!empty($_REQUEST['cmd'])) {
if ($_REQUEST['cmd'] == 'delete_user_meta') {
$user_id = empty($_REQUEST['user_id']) ? 0 : $_REQUEST['user_id'];
$this->deleteUserMeta($user_id, $meta_key);
}
if ($_REQUEST['cmd'] == 'edit_user_meta') {
$this->setUserMeta($user_id, $meta_key, $meta_value);
}
// This should fetch the freshest info.
if ($_REQUEST['cmd'] == 'get_user_meta') {
$buff .= $this->getMetaAsString($user_id);
$buff .= " ";
}
}
return $buff;
}
/**
* This method is called when we have the module and action specified.
*/
public function getUserMetaAjaxAction() {
$msg = '';
$result_html = '';
$status = 1;
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$user_ids_list = $ctrl->getVar('user_id'); // could be 1 or more IDs
$ids = explode(',', $user_ids_list);
$ids = array_map('abs', $ids);
$ids = array_map('trim', $ids);
$ids = array_filter($ids); // non empty ones
$ids = array_unique($ids);
foreach ($ids as $user_id) {
$result_html .= $this->getMetaAsString($user_id);
}
$result_status = array('status' => $status, 'message' => $msg, 'results' => $result_html, );
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $result_status);
}
/**
* This method is called when we have the module and action specified.
*/
public function setUserMetaAjaxAction() {
$msg = '';
$result_html = '';
$status = 1;
$cmd = isset($_REQUEST['cmd']) ? trim($_REQUEST['cmd']) : null;
$cmd_label = preg_match('#delete#si', $cmd) ? 'Delete Meta' : 'Update Meta';
// raw data
$meta_key = empty($_REQUEST['meta_key']) ? '' : trim($_REQUEST['meta_key']);
$meta_value = isset($_REQUEST['meta_value']) ? trim($_REQUEST['meta_value']) : null;
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$user_ids_list = $ctrl->getVar('user_id'); // could be 1 or more IDs
$ids = explode(',', $user_ids_list);
$ids = array_map('trim', $ids);
$ids = array_map('abs', $ids);
$ids = array_filter($ids); // non empty ones
$ids = array_unique($ids);
foreach ($ids as $user_id) {
$res = $this->setUserMeta($user_id, $meta_key, $meta_value);
$result_html .= ($res === false)
? Orbisius_WP_SAK_Util::msg($cmd_label . ' Error. user meta for user ID: ' . esc_attr($user_id) . '] or the new value matches the old one. ', 0)
: Orbisius_WP_SAK_Util::msg($cmd_label. ' OK meta for user ID: ' . esc_attr($user_id) . ']. ', 1);
}
$result_status = array('status' => $status, 'message' => $msg, 'results' => $result_html, );
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $result_status);
}
/**
*
* @param int $user_id
* @param string $meta_key
* @param string $meta_value
* @see https://codex.wordpress.org/Function_Reference/update_user_meta
*/
public function setUserMeta($user_id, $meta_key, $meta_value = null) {
if ( is_null( $meta_value ) ) {
$mixed_res = delete_user_meta($user_id, $meta_key);
} else {
/*Returns meta_id if the meta doesn't exist, otherwise returns true on success and false on failure.
* NOTE: If the meta_value passed to this function is the same as the value that is already in the database, this function returns false. */
$mixed_res = update_user_meta($user_id, $meta_key, $meta_value);
}
return $mixed_res;
}
/**
* Sample Method
*/
public function getMetaAsString($user_id) {
$str = '';
$user_id = abs($user_id);
$user = get_user_by( 'id', $user_id);
$meta = !empty($user)
? get_user_meta($user_id)
: null;
$link_str = '';
// if the item is one element that means that it's one value
if (count($meta) == 1) {
$meta = $meta[0];
}
$str .= "
User ID: $user_id $link_str
" . var_export($user, 1) . "
\n";
$str .= '
User Meta
' . var_export($meta, 1) . "
\n";
return $str;
}
}
/**
* Example Module - Handles ...
*/
class Orbisius_WP_SAK_Controller_Module_User_Manager extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions.
* If user ID is present it will call method so the method can execute before any content is out.
*/
public function __construct() {
if (!empty($_REQUEST['user_id'])) {
$this->loginAs();
}
$this->description = <<User Manager
This module allows you to see user account, user meta info, to log in as a user without knowing their password. TODO: Create, delete users.
Administrator accounts are highlighted.
EOF;
$current_user = wp_get_current_user();
if ( empty( $_REQUEST['load_user_meta'] ) ) {
$this->description .= " Load user meta | ";
} else {
$this->description .= " Skip user meta loading | ";
}
if (!empty($current_user->ID)) {
$this->description .= "Currently Logged User: $current_user->display_name
[$current_user->user_email] (ID: $current_user->ID)";
} else {
$this->description .= "Currently Logged User: (none)";
}
$this->description .= " ";
}
/**
* Lists users and their meta info.
* The user info is dumped on the screen. TODO: make it look pretty.
* This listing also allows the user of SAK4WP to login as given user.
*/
public function run() {
$buff = '';
$args = array(
'number' => 250,
'orderby' => 'registered',
);
$data = get_users( $args );
$records = array();
$highlight_admins = array();
foreach ($data as $idx => $user_obj) {
$rec = (array) $user_obj->data;
// Let's remove those fields because the table can't fit more than 5
unset($rec['user_url']);
unset($rec['user_pass']);
unset($rec['user_status']);
unset($rec['user_activation_key']);
// This allows us to swich the user to a different one.
$rec['user_login'] .= " (Login)";
if ( ! empty( $_REQUEST['load_user_meta'] ) ) {
$user_meta_html = '
\n";
$rec['ID'] .= " (show/hide meta)\n" . $user_meta_html;
}
if ( user_can( $user_obj->ID, 'manage_options' ) ) {
$highlight_admins[] = $idx;
$rec['user_login'] .= ' (admin)';
}
$records[] = $rec;
}
$buff .= "\n";
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$buff .= $ctrl->renderTable('Users: ' . count($data), '', $records, $highlight_admins);
return $buff;
}
/**
* This method auto logins in the user with certain user ID (int)
* After the user is logged in this will redirect again to the User Manager's page.
*/
public function loginAs() {
$user_id = empty($_REQUEST['user_id']) ? 0 : intval($_REQUEST['user_id']);
wp_set_auth_cookie( $user_id, false, is_ssl() );
wp_redirect('?page=mod_user_manager&logged_in_as=' . $user_id);
exit;
}
}
/**
* Plugin_Manager Module - Allows you to manage plugins: bulk install, de/activate, delete
*/
class Orbisius_WP_SAK_Controller_Module_Plugin_Manager extends Orbisius_WP_SAK_Controller_Module {
private $target_dir = ''; // plugins directory i.e. wp-content/plugins/
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->target_dir = WP_PLUGIN_DIR;
$warning = Orbisius_WP_SAK_Util::msg("If the plugin already exists its files will be overridden!", 0);
$this->description = <<Plugin Manager
This module allows you to manage plugins: bulk download, install, and activate plugins. TODO: (de)activate, delete. Just enter the plugin's WordPress.org page
or a zip file location (web). Enter multiple links each on a new line. Warning: If the plugin already exists its files will be overridden!
Plugins will be extracted in: $this->target_dir
$warning
\n";
$buff .= "\n";
return $buff;
}
/**
* This is called via ajax and downloads some plugins and extracts the zip files' contents into plugins folder.
* The result is JSON
*/
public function downloadAction() {
$msg = '';
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$params = $ctrl->getParams();
$download_list_buff = empty($params['download_list_buff']) ? '' : trim($params['download_list_buff']);
$activate_plugins = empty($params['activate_plugins']) ? 0 : 1;
$locations = preg_split('#[\r\n]+#si', $download_list_buff); // let's split things by new lines.
$locations = array_map('trim', $locations); // no spaces
$locations = array_unique($locations); // only unique links
$locations = array_filter($locations); // skip empty lines
if (!empty($locations)) {
$plugins_dir = $this->target_dir;
$req_cnt = 0;
$limit = 10 * 1024 * 1024; // 10MB
$limit_fmt = Orbisius_WP_SAK_Util::formatFileSize($limit);
foreach ($locations as $link) {
if (empty($link)) {
continue;
}
// If the link points to a plugin hosted by wordpress.org go and find the download link.
// otherwise we'll skip them because SAK4WP can find other random ZIP files or bad plugins
// which could break WP. There could be some www
if (preg_match('#https?://[w\.]*wordpress.org/(?:extend/)?plugins/#si', $link)
&& !preg_match('#\.zip$#si', $link)) {
// let's load WP page
$result = Orbisius_WP_SAK_Util::makeHttpRequest($link);
$org_link_esc = esc_attr($link);
if (empty($result['debug']['http_code']) || $result['debug']['http_code'] != 200) {
$result_html .= Orbisius_WP_SAK_Util::msg("Couldn't Download Link: HTTP Code: " . $result['debug']['http_code'], 2);
} elseif (empty($result['error'])) {
$body_buff = $result['buffer'];
// the download link may contain alphanumeric + some versioning.
// e.g. http://downloads.wordpress.org/plugin/orbisius-cyberstore.1.1.7.zip
if (preg_match('#(https?://downloads.wordpress.org/plugin/(?:[\w-.]+).zip)#si', $body_buff, $matches)) {
$link = $matches[1];
$result_html .= Orbisius_WP_SAK_Util::msg("Found Download Link: [$org_link_esc => $link]", 2);
}
} else {
$result_html .= Orbisius_WP_SAK_Util::msg("Couldn't Find Plugin Download Link: [$link]", 2);
}
// let's give the server a chance to relax for a sec.
if (++$req_cnt % 5 == 0) {
sleep(1);
}
}
$link_esc = esc_attr($link);
// skip links not ending in .zip for now.
if (!preg_match('#\.zip$#si', $link)) {
$result_html .= Orbisius_WP_SAK_Util::msg("Skipping link: [$link_esc]. Reason: doesn't end in .zip");
continue;
} else {
$dl_status = null;
$extract_status = null;
$result_html .= Orbisius_WP_SAK_Util::msg("Processing link: [$link_esc]", 2);
// Let's do a quick check
$remote_file_size = Orbisius_WP_SAK_Util::getRemoteFileSize($link);
// The max plugin size is 10MB
if ($remote_file_size > $limit) {
$file_size_fmt = Orbisius_WP_SAK_Util::formatFileSize($remote_file_size);
$result_html .= Orbisius_WP_SAK_Util::msg("Download Failed: [$link_esc, $file_size_fmt]."
. " Plugin file is bigger than $limit_fmt.", 0);
} else {
$dl_status = Orbisius_WP_SAK_Util::downloadFile($link);
if (empty($dl_status['status'])
|| empty($dl_status['debug']['http_code'])
|| $dl_status['debug']['http_code'] != 200) {
$result_html .= Orbisius_WP_SAK_Util::msg("Download Failed: [$link_esc].
Request Info: (show/hide)
"
. var_export( $dl_status, 1) . "
", 0);
} else {
$file = $dl_status['file'];
$file_size = filesize($file);
$file_size_fmt = Orbisius_WP_SAK_Util::formatFileSize($file_size);
$result_html .= Orbisius_WP_SAK_Util::msg("Download OK: [$link_esc, $file_size_fmt]", 1);
// Here we're assuming that the plugin will be in a folder in the zip file.
$extract_status = Orbisius_WP_SAK_Util::extractArchiveFile($file, $plugins_dir);
if (!empty($extract_status['status'])) {
$result_html .= Orbisius_WP_SAK_Util::msg("Plugin Extracting OK: [$link_esc] in plugins/{$extract_status['plugin_folder']}", 1);
if ($activate_plugins) {
$act_status = Orbisius_WP_SAK_Util::doPluginAction($extract_status['main_plugin_file'], 1);
if (!empty($act_status['status'])) {
$result_html .= Orbisius_WP_SAK_Util::msg("The plugin was successfully activated.", 1);
} else {
$result_html .= Orbisius_WP_SAK_Util::msg("Plugin couldn't be activated. Error: " . $act_status['error'], 0);
}
}
} else {
$result_html .= Orbisius_WP_SAK_Util::msg("Plugin Extracting Failed: [$link_esc]", 0);
}
// Let's remove the temporary file so it doesn't take too much space in the TMP folder.
// Note: if we start using downloadFile with 2nd parameter e.g. target dir
// this unlink idea may not be a good one.
unlink($file);
}
}
$result_html .= ' ';
}
}
$status = 1;
} else {
$status = 1;
$result_html = Orbisius_WP_SAK_Util::msg('No links have been entered or the entered ones do not end in .zip.', 2);
}
$result_status = array('status' => $status, 'message' => $msg, 'results' => $result_html, );
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $result_status);
}
/**
* This is called via ajax and downloads some plugins and extracts the zip files' contents into plugins folder.
* The result is JSON
*/
public function get_download_listAction() {
$msg = $result_html = '';
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$params = $ctrl->getParams();
$download_list_url = empty($params['download_list_url']) ? '' : $params['download_list_url'];
if (!empty($download_list_url)) {
$result = Orbisius_WP_SAK_Util::makeHttpRequest($download_list_url);
$org_link_esc = esc_attr($link);
if (empty($result['error'])) {
$plugin_list = array();
$body_buff = $result['buffer'];
// Do we have links to WP plugins?
if (preg_match_all('#https?://[w\.]*wordpress.org/(?:extend/)?plugins/[\w-]+/?#si', $body_buff, $matches)) {
$plugin_list += $matches[0];
}
// How about .zip files? direct downloads
if (preg_match_all('#https?://[^\s]+\.zip#si', $body_buff, $matches)) {
$plugin_list += $matches[0];
}
$plugin_list = array_unique($plugin_list);
$result_html .= "Found link(s) ";
$result_html .= "(show/hide retrieved content) \n";
$result_html .= "
";
$result_html .= " ";
$result_html .= <<Add to Download
HTML_EOF;
} else {
$result_html .= Orbisius_WP_SAK_Util::msg("Couldn't Find Plugin Download Link: [$link]", 2);
}
$status = 1;
} else {
$status = 1;
$result_html = Orbisius_WP_SAK_Util::msg('No link has been entered.', 2);
}
$result_status = array('status' => $status, 'message' => $msg, 'results' => $result_html, );
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $result_status);
}
}
/**
* Locate_WordPress Module - Searches for local WordPress installations in different folders and shows their versions.
*/
class Orbisius_WP_SAK_Controller_Module_Locate_WordPress extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<Locate WordPress
Searches for local WordPress installations in different folders and shows their versions.
Useful if you manage multiple WordPress sites and want to make sure all of them are running the latest WordPress.
\n";
$buff .= "\n";
return $buff;
}
/**
* This is called via ajax and searches for WP by finding wp-includes folder starting from start_folder.
* Needs starting folder.
* The result is JSON
*/
public function searchAction() {
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$params = $ctrl->getParams();
$start_folder = empty($params['start_folder']) ? dirname(__FILE__) : $params['start_folder'];
$s = 0;
$msg = '';
$status = array('status' => 0, 'message' => '', 'results' => '', 'start_folder' => $start_folder);
$find_bin = Orbisius_WP_SAK_Util_File::getBinary('find');
// this searches for folders that contain wp-includes and that's where we'll read version.php
$cmd = "$find_bin $start_folder -type d -name \"wp-includes\" 2>/dev/null";
if (!empty($start_folder)) {
$latest_wp_version = Orbisius_WP_SAK_Util::getLatestWordPressVersion();
$file_search_buffer = `$cmd`;
if (!empty($file_search_buffer)) {
$lines = preg_split('#[\r\n]+#si', $file_search_buffer);
foreach ($lines as $line) {
if (empty($line)) {
continue;
}
$ver_file = $line . '/version.php'; // we just need to append the file to the abs dir path.
$ver_buff = Orbisius_WP_SAK_Util_File::read($ver_file); // will be faster if we read first 120 bytes?
$version = '0.0.0'; // defaut
// parse version which is like this $wp_version = '3.5.2';
if (preg_match('#wp_version\s*=\s*[\'"]([^\'"]+)#si', $ver_buff, $matches)) {
$version = $matches[1];
// is it the latest?; no -> let's warn them
if (version_compare($version, $latest_wp_version, '<')) {
$version = Orbisius_WP_SAK_Util::msg("$version (upgrade)", 0, 1);
} else {
$version = Orbisius_WP_SAK_Util::msg("$version", 1, 1);
}
}
// by doing the dirname we'll go up 1 level above wp-includes -> wp root dir
$data[dirname($line)] = $version;
}
$result_html = $ctrl->renderKeyValueTable('WordPress Installations. Latest WordPress Version: ' . $latest_wp_version, $data, array(
'table_css' => 'app-table-long-first-col',
'header' => array('Location', 'WordPress Version'),
)
);
}
$status['status'] = 1;
} else {
$status['message'] = 'Error';
}
$status['results'] = empty($result_html) ? Orbisius_WP_SAK_Util::msg("Nothing found", 2) : $result_html;
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $status);
}
}
/**
* Search Module - Searches for text using grep
*/
class Orbisius_WP_SAK_Controller_Module_Search extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<Search
Search for a given text keyword within files of WordPress.
\n";
}
return $buff;
}
/**
* This is called via ajax and searches for WP by finding wp-includes folder starting from start_folder.
* Needs starting folder.
* The result is JSON
*/
public function searchAction() {
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$params = $ctrl->getParams();
$q = empty($params['q']) ? '' : trim( $params['q'] );
if ( empty( $q ) ) {
return;
}
$start_folder = empty($params['start_folder']) ? ABSPATH : $params['start_folder'];
$start_folder = str_replace( '/', DIRECTORY_SEPARATOR, $start_folder );
$start_folder = trim( $start_folder, '\\/' );
$q_esc = escapeshellarg($q);
$start_folder_esc = escapeshellarg($start_folder);
$s = 0;
$msg = '';
$bin = Orbisius_WP_SAK_Util_File::getBinary('grep');
// this searches for folders that contain wp-includes and that's where we'll read version.php
$cmd = "$bin -irn $q_esc $start_folder_esc 2>&1";
$search_buffer = `$cmd`;
$search_buffer = trim( $search_buffer );
return $search_buffer;
}
}
/**
* This module handles lists page templates.
*/
class Orbisius_WP_SAK_Controller_Module_Htaccess extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->htaccess_dir = ABSPATH . 'wp-admin/';
$this->description = <<.htaccess
This module allows you to create an .htaccess and .htpasswd files for the WordPress admin area.
It will also add a snippet in the main .htaccess file so wp-login.php is protected too.
";
} elseif ( // delete file
preg_match('#delete_file#si', $_REQUEST['cmd'] )
&& !empty($_REQUEST['file'])
&& preg_match('#^' . preg_quote($db_export_file_prefix) . '#si', $_REQUEST['file'] )
) {
$file = ORBISIUS_WP_SAK_APP_BASE_DIR . '/' . $_REQUEST['file'];
if (file_exists($file)) {
unlink( $file);
}
}
}
$folder = ORBISIUS_WP_SAK_APP_BASE_DIR;
$files_arr = glob($folder . '/' . $db_export_file_prefix . '*.*'); // list only sa4kwp exported files.
// @todo: email the db archive as attachment.
foreach ($files_arr as $file) {
$file_base_name = basename($file);
$delete_link = '?page=mod_db_dump&cmd=delete_file&file=' . urlencode($file_base_name);
$dl_link = site_url($file_base_name);
$size = filesize($file);
$size_fmt = Orbisius_WP_SAK_Util::formatFileSize($size);
$buff .= " [X] ";
$buff .= "$file_base_name ($size_fmt)";
$buff .= " ";
}
set_time_limit($old_time_limit);
return $buff;
}
}
/**
* This module handles lists page templates.
*/
class Orbisius_WP_SAK_Controller_Module_Site_Packager extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<Site Packager
This module allows you to compress the current site (whole site or partially) in tar or tar.gz formats.
EOF;
}
/**
*
*/
public function run() {
$buff = '';
// @TODO: download only tables that are specific to the selected install!
// see http://qSandbox.com db dump for ideas.
// let's allow the script to run longer in case we download lots of files.
$old_time_limit = ini_get('max_execution_time');
set_time_limit(600);
// We want the directory prefix that goes into the archive to be
// the folder name and not the full system path.
// e.g. /var/www/vhosts/etc/aaaaa/htdocs
// we'll go 1 level up and zip the folder that way and later come back to the current dir.
$target_dir = ORBISIUS_WP_SAK_APP_BASE_DIR . '/';
$db_export_file_prefix = '!sak4wp-site-packager-';
$buff .= "\n";
if ( !empty( $_REQUEST['cmd'] ) ) {
$archive_start = empty($_REQUEST['archive_start']) ? ABSPATH : $_REQUEST['archive_start'];
$cur_dir = getcwd();
$dir2chdir = $archive_start;
$dir2compress = $archive_start;
$cmd_params_arr = array();
if (1 || $archive_start == 'add_cur_folder') {
$dir2compress = basename($archive_start);
$dir2chdir = dirname($archive_start);
chdir($dir2chdir);
// This is passed as 1st param to the tar command
// if archivig current folder and using text file no need to specify folder. I think.
$cmd_params_arr[] = $dir2compress;
} else {
$cmd_params_arr[] = '.';
}
if ( preg_match('#export#si', $_REQUEST['cmd'] ) ) {
// fixes: "file changed as we read it" due to creation of the log and gz file
// src: http://www.ensode.net/roller/dheffelfinger/entry/tar_failing_with_error_message
$cmd_params_arr[] = ' --ignore-failed-read';
// On Windows tar zcvf produces this error: tar: Cannot use compressed or remote archives
// If we need gzip on Windows we can do it in 2 steps.
// 1. tar
// 2. gzip $gz_cmd = "gzip < $target_sql_esc > $target_sql_gz_esc";
$archive_type = preg_match('#gz#si', $_REQUEST['cmd']) && !Orbisius_WP_SAK_Util::isWindows() ? '.tar.gz' : '.tar';
$file_suffix = 'full';
// Let's make tar include only some files.
if ( empty($_REQUEST['backup_type']) || $_REQUEST['backup_type'] == 'site_only' ) {
// http://php.net/manual/en/function.tempnam.php
$tmp_file = tempnam(sys_get_temp_dir(), '!sak4wp-site-pkg-');
Orbisius_WP_SAK_Util_File::get_wp_files($dir2compress, $tmp_file);
$cmd_params_arr[] = '--files-from=' . escapeshellarg($tmp_file);
$file_suffix = 'site_only';
}
$output_file = $target_dir
. $db_export_file_prefix
. ORBISIUS_WP_SAK_HOST
. '-'
. date( 'Ymd_his' )
. '-ts-'
. time()
. '-'
. sha1( microtime() )
. '-' . $file_suffix
. $archive_type;
$output_log_file = $output_file . '.log';
$output_error_log_file = $output_file . '.error.log';
$output_done_file = $output_file . '.done';
$exclude_items = array(
'!sak4wp.php', // sak4wp is not necessary in the pkg
'.ht-sak4wp*',
'Maildir/*',
'*.log',
'*.wpress', // ai1wm
'logs/*',
'tmp/*',
'sess_*', // php session files
'*/sess_*', // php session files
'*.cache',
// there is another function to get backups: is_wp_backup_resource
'wp-content/uploads/*backup*',
'wp-content/ai1wm-backups/*',
'wp-content/cache/*',
'wp-content/*cache*/*',
'wp-content/*updraft*',
'wp-content/*backup*',
'wp-content/uploads/backupbuddy*',
'wp-content/backupwordpress*',
'wp-snapshots/*', // Duplicator
'__MACOSX', // mac
'.DS_Store', // mac
$db_export_file_prefix . '*',
$db_export_file_prefix . '*.*',
// full paths
$output_file,
$output_log_file,
$output_done_file,
$output_error_log_file,
// just names
basename($output_file),
basename($output_log_file),
basename($output_done_file),
basename($output_error_log_file),
);
foreach ($exclude_items as $line) {
$cmd_params_arr[] = "--exclude=" . escapeshellarg($line);
$cmd_params_arr[] = "--exclude=" . escapeshellarg('*/'. $line);
$cmd_params_arr[] = "--exclude=" . escapeshellarg('./'. $line);
}
// Verify only tar files.
if ( ! empty( $_REQUEST['verify'] ) && preg_match( '#\.tar$#si', $archive_type ) ) {
$cmd_params_arr[] = '--verify';
}
$cmd_param_str = join(' ', $cmd_params_arr);
$output_file_esc = escapeshellarg( $output_file );
$output_log_file_esc = escapeshellarg( $output_log_file );
$output_error_log_file_esc = escapeshellarg( $output_error_log_file );
// Are we creating a tar or tar.gz file
$tar_main_cmd_arg = preg_match('#\.(tar\.gz|t?gz)$#si', $output_file) ? 'zcvf' : 'cvf';
$cmd = Orbisius_WP_SAK_Util_File::getBinary('tar')
. " $cmd_param_str $tar_main_cmd_arg $output_file_esc > $output_log_file_esc 2> $output_error_log_file_esc";
if ( ! empty( $_REQUEST['bg'] ) ) {
// @note: for some weird reason I can't fork the process and execute a task after it finishes.
// This is strange! I wanted to know if the tar has finished.
// creating a .done file to let the user know that the archiving has finished. Cool, eh?
/*$output_done_file_esc = escapeshellarg( $output_file . '.done' );
$cmd = "($cmd ; touch $output_done_file_esc) &";*/
$cmd .= " &";
}
// $result = `$cmd`;
$ret_val = 0;
system($cmd, $ret_val);
chdir($cur_dir);
if (empty($_REQUEST['bg'])) {
// No need for an empty file only if NOT running in bg
if (file_exists($output_log_file) && filesize($output_log_file) == 0) {
unlink($output_log_file);
}
if (file_exists($output_error_log_file) && filesize($output_error_log_file) == 0) {
unlink($output_error_log_file);
}
}
$buff .= "
";
} elseif ( // delete file
preg_match('#delete_file#si', $_REQUEST['cmd'] )
&& !empty($_REQUEST['file'])
&& preg_match('#^' . preg_quote($db_export_file_prefix) . '#si', $_REQUEST['file'] )
) {
$file = ORBISIUS_WP_SAK_APP_BASE_DIR . '/' . $_REQUEST['file'];
if (file_exists($file)) {
unlink( $file);
}
}
}
$folder = ORBISIUS_WP_SAK_APP_BASE_DIR;
$files_arr = glob($folder . '/' . $db_export_file_prefix . '*.*'); // list only sa4kwp exported files.
foreach ($files_arr as $file) {
$file_base_name = basename($file);
$delete_link = '?page=mod_site_packager&cmd=delete_file&file=' . urlencode($file_base_name);
$dl_link = site_url($file_base_name);
$size = filesize($file);
$size_fmt = Orbisius_WP_SAK_Util::formatFileSize($size);
$buff .= " [X] ";
$buff .= "$file_base_name ($size_fmt)";
$buff .= " ";
}
set_time_limit($old_time_limit);
return $buff;
}
}
/**
* This module handles actions related to Limit Login Attempts plugin.
*/
class Orbisius_WP_SAK_Controller_Module_Limit_Login_Attempts_Unblocker extends Orbisius_WP_SAK_Controller_Module {
/**
* Gets the IP address that are blocked.
* Limit Login Attempts saves them in WP db's options under: 'limit_login_lockouts' name
*/
public function __construct() {
$lockouts = get_option('limit_login_lockouts');
$retries = get_option('limit_login_retries');
$this->lockouts = $lockouts;
$this->retries = $retries;
// ::SNOTE: fake IPs for testing
/*$this->lockouts['111'] = time();
$this->retries['111'] = 1;*/
$this->ip = Orbisius_WP_SAK_Util::getIP();
$this->description = <<Limit Login Attempts Unblocker
This section allows you to unblock yourself or another IP address that was blocked by
Limit Login Attempts plugin.
EOF;
}
/**
* Checks if the current IP is blocked and lists all the blocked IPs in a table.
*/
public function run() {
$buff = '';
$my_ip = $this->ip;
if ($this->isBlocked($my_ip)) {
$buff .= "
Your IP [$my_ip] address is blocked.
Scroll down to the yellow row and click on Unblock link.
";
} else {
$buff .= "
Your IP [$my_ip] address is NOT blocked.
";
}
$buff .= " ";
$buff .= $this->getBlockedAsHTML();
return $buff;
}
/**
* Handles IP unblocking. It searches the IP in the list and then
* updates the array and saves it in the db.
* The result is JSON
*/
public function unblockIPAction() {
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$params = $ctrl->getParams();
$lockouts = $this->lockouts;
$retries = $this->retries;
$ip = empty($params['ip']) ? '' : $params['ip'];
$s = 0;
$msg = '';
$status = array('status' => 0, 'message' => '');
if (!empty($lockouts[$ip])) {
unset($lockouts[$ip]);
unset($retries[$ip]);
update_option('limit_login_lockouts', $lockouts);
update_option('limit_login_retries', $retries);
$status['status'] = 1;
} else {
$status['message'] = 'IP address: [' . esc_attr($ip) . '] not found.';
//$status['data'] = $lockouts; // let's not send the data.
}
$ctrl->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, json_encode($status));
}
/**
* Checks if the current user or a specific IP is banned.
* @param string $ip
* @return bool
*/
public function isBlocked($ip = '') {
$ip = empty($ip) ? Orbisius_WP_SAK_Util::getIP() : $ip;
$lockouts = $this->lockouts;
$banned = !empty($lockouts) && !empty($lockouts[$ip]);
return $banned;
}
/**
* Renders all the IPs in a nice table.
*
* @param string $ip
* @return string
*/
public function getBlockedAsHTML() {
$buff = '';
$lockouts = $this->lockouts;
$my_ip = $this->ip;
if (!empty($lockouts)) {
$cnt = 0;
$data = $highlight_rows = array();
foreach ($lockouts as $ip => $ts) {
$you = '';
if ($my_ip == $ip) {
$you = '← (you)';
$highlight_rows[] = $cnt;
}
$t = date('r', $ts);
//$ip_who_is_link = "$ip $you";
$ip_who_is_link = "$ip $you";
$when_blocked = $t;
$action = "Unblock";
$data[] = array(
'IP' => $ip_who_is_link,
'When Blocked' => $when_blocked,
'Action' => $action,
);
$cnt++;
}
$ctrl = Orbisius_WP_SAK_Controller::getInstance();
$buff .= $ctrl->renderTable('Blocked IPs', '', $data, $highlight_rows);
}
return $buff;
}
}
class Orbisius_WP_SAK_Controller_Module_Stats extends Orbisius_WP_SAK_Controller_Module {
/**
* Setups the object stuff and defines some descriptions
*/
public function __construct() {
$this->description = <<Stats
This module allows you to see a lot of stats for your WordPress site.
';
$data['Total Disk Usage (df --human-readable)'] = $disk_free_space;
$top_bin = Orbisius_WP_SAK_Util_File::getBinary('top');
if (!empty($top_bin)) { // Processes info
$cmd_buff = `$top_bin -b -n 1`;
$cmd_buff = trim($cmd_buff);
}
$cmd_buff = empty($cmd_buff) ? 'N/A' : '';
$data['Processes Info (top -b -n 1)'] = $cmd_buff;
// Free memory
$free_bin = Orbisius_WP_SAK_Util_File::getBinary('free');
if (!empty($free_bin)) { // Processes info
$cmd_buff = `$free_bin -m`;
$cmd_buff = trim($cmd_buff);
}
$cmd_buff = empty($cmd_buff) ? 'N/A' : '';
$data['Free Memory (free -m)'] = $cmd_buff;
// lists 15 files and sorts them by size. e.g. 100K
$du_bin = Orbisius_WP_SAK_Util_File::getBinary('du');
if (!empty($du_bin)) { // Processes info
$large_files = `$du_bin -ah $dir | sort -nr | head -n +15`;
$large_files = trim($large_files);
$large_files = str_replace($dir, '', $large_files);
}
$data['Large Files'] = empty($large_files) ? 'n/a' : '';
$buff .= $ctrl->renderKeyValueTable('System Info', $data);
$data = array();
$data["User(s) [table:{$wpdb->users}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->users");
$data["User Meta Row(s) [table:{$wpdb->usermeta}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta");
$data["Comment(s) [table:{$wpdb->comments}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->comments");
$data["Comment Meta Rows(s) [table:{$wpdb->commentmeta}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->commentmeta");
$data['Posts'] = $wpdb->get_var("SELECT COUNT(ID) as rev_cnt FROM $wpdb->posts p WHERE p.post_type = 'post'");
$data['Pages'] = $wpdb->get_var("SELECT COUNT(ID) as rev_cnt FROM $wpdb->posts p WHERE p.post_type = 'page'");
$data['Custom Posts'] = $wpdb->get_var("SELECT COUNT(ID) as rev_cnt FROM $wpdb->posts p WHERE "
. "(p.post_type != 'page' AND p.post_type != 'post')");
$data['Attachments'] = $wpdb->get_var("SELECT COUNT(ID) as rev_cnt FROM $wpdb->posts p WHERE p.post_type = 'attachment'");
$data["Options [table:{$wpdb->options}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->options");
$data["Link(s) [table:{$wpdb->links}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->links");
$data["Terms [table:{$wpdb->terms}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->terms");
$data["Terms Taxonomy Row(s) [table:{$wpdb->term_taxonomy}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->term_taxonomy");
$data["Terms Relationship(s) [table:{$wpdb->term_relationships}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->term_relationships");
$data["Meta Data Row(s) [table:{$wpdb->postmeta}]"] = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->postmeta pm");
$data['Revisions'] = $wpdb->get_var(
"SELECT COUNT(*) as rev_cnt FROM $wpdb->posts p
LEFT JOIN $wpdb->term_relationships r ON (p.ID = r.object_id)
LEFT JOIN $wpdb->postmeta pm ON (p.ID = pm.post_id)
WHERE p.post_type = 'revision'"
);
$buff .= $ctrl->renderKeyValueTable('WordPress Site Stats', $data);
ob_start();
phpinfo();
$php_info = ob_get_contents();
ob_get_clean();
// clear HTML buff around content and reduce heading tags to h4
$php_info = preg_replace('#.*?]*>#si', '', $php_info);
$php_info = preg_replace('#PHP Info'
. " (show/hide)\n"
. "
" . $php_info . '
';
$buff .= $php_info;
return $buff;
}
/**
* checks several variables and returns the lowest (in MB).
* @see http://www.kavoir.com/2010/02/php-get-the-file-uploading-limit-max-file-size-allowed-to-upload.html
* @return int
*/
public static function get_max_upload_size() {
$max_upload = (int)(ini_get('upload_max_filesize'));
$max_post = (int)(ini_get('post_max_size'));
$memory_limit = self::get_memory_limit();
$upload_mb = min($max_upload, $max_post, $memory_limit);
return $upload_mb;
}
/**
* Returns memory limit based on the CFG in MB
*
* @return int
*/
public static function get_memory_limit() {
$memory_limit = (int)(ini_get('memory_limit'));
// Some hostings report this in bytes? instead of MB e.g. 256M
if ( $memory_limit >= 1024 * 1024 ) { // more than 1MB
$memory_limit /= 1024 * 1024;
}
return $memory_limit;
}
/**
* Reads wordpress's config file and returns db data in an array.
*
* @param void $wp_config_file
* @return array; array(4) { ["db_name"]=> string(10) "aaaaaa" ["db_user"]=> string(8) "aaaa" ["db_host"]=> string(9) "localhost" ["db_prefix"]=> string(9) "wp_fresh_" }
*/
public function read_wp_config($wp_config_file = '') {
if (empty($wp_config_file)) {
$wp_config_file = ABSPATH . '/wp-config.php';
}
$data = array();
$wp_config_buff = Orbisius_WP_SAK_Util_File::read($wp_config_file);
/*if (empty($wp_config_buff)) {
throw new Exception("There was an error with the mibew zip package.");
}*/
// define('DB_NAME', 'default_db');
if (preg_match('#define\s*\(\s*[\'"]DB_NAME[\'"]\s*,\s*[\'"]\s*(.*?)\s*[\'"]#si', $wp_config_buff, $matches)) {
$data['db_name'] = $matches[1];
}
// DB_USER
if (preg_match('#define\s*\(\s*[\'"]DB_USER[\'"]\s*,\s*[\'"]\s*(.*?)\s*[\'"]#si', $wp_config_buff, $matches)) {
$data['db_user'] = $matches[1];
}
// DB_PASSWORD
if (preg_match('#define\s*\(\s*[\'"]DB_PASSWORD[\'"]\s*,\s*[\'"]\s*(.*?)\s*[\'"]#si', $wp_config_buff, $matches)) {
$data['db_pass'] = $matches[1];
}
// DB_HOST
if (preg_match('#define\s*\(\s*[\'"]DB_HOST[\'"]\s*,\s*[\'"]\s*(.*?)\s*[\'"]#si', $wp_config_buff, $matches)) {
$data['db_host'] = $matches[1];
}
// wp prefix; $table_prefix = 'default_db_wp_';
if (preg_match('#table_prefix\s*=\s*[\'"]\s*(.*?)\s*[\'"]#si', $wp_config_buff, $matches)) {
$data['db_prefix'] = $matches[1];
}
return $data;
}
}
/**
* Cool file functions. Support file locking, (de)serialization etc.
*/
class Orbisius_WP_SAK_Util_File {
// options for read/write methods.
const SERIALIZE = 2;
const UNSERIALIZE = 4;
const FILE_APPEND = 8;
/**
* Attempts to find the path to a binary by iterating over several cases.
*
* Usage: Orbisius_WP_SAK_Util_File::getBinary();
* @param string $file
* borrowed from SAK4WP
*/
public static function getBinary($file) {
if (!function_exists('exec')) {
return false;
}
$file_esc = escapeshellcmd($file);
// hmm, what did we receive? that required escaping?
if ($file != $file_esc) {
return false;
}
$options = $output_arr = array();
$return_var = false;
$options[] = $file;
$options[] = basename($file);
$options[] = "/usr/bin/$file";
$options[] = "/usr/local/bin/$file";
$options[] = "/usr/sbin/$file";
$options = array_unique($options);
foreach ($options as $file) {
$cmd = "$file --help 2>&1";
exec($cmd, $output_arr, $return_var);
if (empty($return_var)) { // found it! exit code 0 means success in linux
return $file;
}
}
return false;
}
/**
* @desc write function using flock
*
* @param string $vars
* @param string $buffer
* @param int $append
* @return bool
*/
public static function write($file, $buffer = '', $option = null) {
$buff = false;
$tries = 0;
$handle = '';
$write_mod = 'wb';
if (!is_null($option)) {
if ($option & self::SERIALIZE) {
$buffer = serialize($buffer);
}
if ($option & self::FILE_APPEND) {
$write_mod = 'ab';
}
}
if (($handle = @fopen($file, $write_mod))
&& flock($handle, LOCK_EX)) {
// lock obtained
if (fwrite($handle, $buffer) !== false) {
@fclose($handle);
return true;
}
}
return false;
}
/**
* @desc read function using flock
*
* @param string $vars
* @param string $buffer
* @param int $option whether to unserialize the data
* @return mixed : string/data struct
*/
public static function read($file, $option = null) {
$buff = false;
$read_mod = "rb";
$handle = false;
if (($handle = @fopen($file, $read_mod))
&& (flock($handle, LOCK_EX))) { // | LOCK_NB - let's block; we want everything saved
$buff = @fread($handle, filesize($file));
@fclose($handle);
}
if ($option == self::UNSERIALIZE) {
$buff = unserialize($buff);
}
return $buff;
}
/**
*
* @param string $file
* @return int
*/
public static function is_wp_backup_resource($file) {
$is_backup_res = 0;
$exclude_list = array(
'wp-snapshots', // Duplicator
'wp-content/updraft',
'wp-content/backup',
'wp-content/uploads/backup',
'.log',
'.bak',
);
foreach ($exclude_list as $exclude_file) {
if (stripos($file, $exclude_file) !== false) {
$is_backup_res = 1;
break;
}
}
return $is_backup_res;
}
/**
* Finds all WP related files from a given directory.
* the result is either returned as an array OR saved in txt file
* which can later be used when using tar --files-from=files.txt
* Usage: Orbisius_WP_SAK_Util_File::get_wp_files();
* @param string $start_folder
* @param string $target_file
* @return array or bool when file is saved.
*/
public static function get_wp_files($start_folder = '.', $target_file = '') {
$find_bin = Orbisius_WP_SAK_Util_File::getBinary('find');
$start_folder = str_replace('\\', '/', $start_folder); // win -> linux slashes
$start_folder = rtrim($start_folder, '/');
$result = `$find_bin $start_folder -name "wp-*" -print`; // only one type of extensions is search not OR search; sometimes it puts files that match wp-
$result = trim($result); // rm last empty line
$files = preg_split('#[\r\n]+#si', $result);
$files = preg_grep('#^'.preg_quote($start_folder) . '[./\\\]*wp-#si', $files); // there could be a starting ./ & make sure they all start with wp-
$auto_append_files = array(
'.htaccess',
'index.php',
);
$x = rtrim($start_folder, '/') . '/';
foreach ($auto_append_files as $file) {
if (is_file( $x . $file)) {
$files[] = $x . $file;
}
}
foreach ($files as $idx => $file) {
$file = str_replace('\\', '/', $file); // win -> linux slashes
$file = ltrim($file, './'); // rm leading ./
$file = preg_replace('#^' . preg_quote($start_folder) . '[./]*#si', '', $file);
if (self::is_wp_backup_resource($file)) {
unset($files[$idx]);
continue;
}
if ($file == 'htaccess') { // restore the dot
$file = '.' . $file;
}
$files[$idx] = $file;
}
if (!empty($target_file)) {
$stat = file_put_contents($target_file, join("\n", $files), LOCK_EX);
return $stat;
}
return $files;
}
}
/**
* Cool functions that do not belong to a class and can be called individually.
*/
class Orbisius_WP_SAK_Util {
public static $curl_options = array(
CURLOPT_USERAGENT => 'SAK4WP/1.0',
CURLOPT_AUTOREFERER => true,
CURLOPT_COOKIEFILE => '',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_TIMEOUT => 600,
);
/**
* Orbisius_WP_SAK_Util::isWindows()
* @return bool
*/
public static function isWindows() {
$yes = stristr(PHP_OS, 'WIN');
return $yes;
}
/**
* Gets IP. This may require checking some $_SERVER variables ... if the user is using a proxy.
* @return string
*/
public static function getIP() {
$ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
return $ip;
}
/**
* Gets Server IP from env.
* @return string
*/
public static function getServerIP() {
$ip = empty($_SERVER['SERVER_ADDR']) ? '' : $_SERVER['SERVER_ADDR'];
return $ip;
}
/**
* proto str formatFileSize( int $size )
*
* @param string
* @return string 1 KB/ MB
*/
public static function formatFileSize($size) {
$size_suff = 'Bytes';
if ($size > 1024 ) {
$size /= 1024;
$size_suff = 'KB';
}
if ( $size > 1024 ) {
$size /= 1024;
$size_suff = 'MB';
}
if ( $size > 1024 ) {
$size /= 1024;
$size_suff = 'GB';
}
if ( $size > 1024 ) {
$size /= 1024;
$size_suff = 'TB';
}
$size = number_format($size, 2);
$size = preg_replace('#\.00$#', '', $size);
return $size . " $size_suff";
}
/**
* a simple status message, no formatting except color.
* status is 0, 1 or 2
* Orbisius_WP_SAK_Util::msg()
*/
static function msg($msg, $status = 0, $use_simple_css = 0) {
$inline_css = '';
if ($status == 1) {
$cls = 'app-alert-success';
} elseif ($status == 2) {
$cls = 'app-alert-notice';
} else {
$cls = 'app-alert-error';
}
// use a simple CSS e.g. a nice span to alert, not just huge divs
if ($use_simple_css) {
$cls = str_replace('alert', 'simple-alert', $cls);
}
$str = "
$msg
";
return $str;
}
/**
* Orbisius_WP_SAK_Util::m()
* a simple status message, no formatting except color.
* status is 0, 1 or 2
*/
static function m($msg, $status = 0, $use_simple_css = 0) {
$msg = self::msg( $msg, $status, 1 );
// use a simple CSS e.g. a nice span to alert, not just huge divs
if ($use_simple_css) {
$msg = str_replace('div', 'span', $msg);
}
return $msg;
}
/**
* Since we are downloading files, it is a good idea to be smart about it.
* For example it doesn't make sense to download 10MB plugin and stress the server.
* @see http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file
*/
public static function getRemoteFileSize($url) {
$ch = curl_init($url);
curl_setopt_array($ch, self::$curl_options);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$data = curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
curl_close($ch);
return $size;
}
/**
* Downloads a file from a given url. The file is saved in a tmp folder and the location is returned
* in the record
*/
public static function downloadFile($url, $target_dir = '') {
$status = 0;
$error = $file = $debug = '';
// let's allow the script to run longer in case we download lots of files.
$old_time_limit = ini_get('max_execution_time');
set_time_limit(600);
try {
if (!empty($target_dir)) { // trailingslash
$target_dir = rtrim($target_dir, '/');
$target_dir .= '/';
}
if (($ch = curl_init($url)) == false) {
throw new Exception("curl_init error for url [$url].");
}
curl_setopt_array($ch, self::$curl_options);
$file = tempnam(self::getTempDir(), '!sak4wp_');
$fp = fopen($file, "wb");
if (empty($fp)) {
throw new Exception("fopen error for file [$url]");
}
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
if (curl_exec($ch) === false) {
unlink($file);
throw new Exception("curl_exec error $file. Curl Error: " . curl_error($ch));
} elseif (!empty($target_dir) && is_dir($target_dir)) { // ::SNOTE: this is not tested yet!
$eurl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
if (preg_match('#^.*/(.+)$#', $eurl, $match)) {
if (rename($file, $target_dir . $match[1]) || copy($file, $target_dir . $match[1])) {
$file = $target_dir . $match[1];
}
}
}
$debug = curl_getinfo($ch);
fclose($fp);
curl_close($ch);
$status = 1;
} catch (Exception $e) {
$error = $e->getMessage();
}
$data = array(
'status' => $status,
'error' => $error,
'file' => $file,
'debug' => $debug,
);
set_time_limit($old_time_limit);
return $data;
}
/**
* Activates or Deactivates a plugin.
*
* @param string $plugin_file - plugin's folder e.g. wp-content/plugins/like-gate/like-gate.php
* @param int $action - 0 - for deactivate, 1 - activation
* @return WP_Error in case of an error or true
*/
static public function doPluginAction($plugin_file = '', $action = 1) {
$error = '';
$status = 0;
require_once(ABSPATH . '/wp-admin/includes/plugin.php');
if (empty($plugin_file)) {
$data = array(
'status' => $status,
'error' => 'Plugin file not specified.',
);
return $data;
}
$result = empty($action)
? deactivate_plugins($plugin_file)
: activate_plugin($plugin_file);
if (is_wp_error($result)) {
$error = $result->get_error_message();
} else {
$status = 1;
}
$data = array(
'status' => $status,
'error' => $error,
);
return $data;
}
/**
* Reads a file partially e.g. the first NN bytes.
*
* @param string $file
* @param int $len_bytes how much bytes to read
* @param int $seek_bytes should we start from the start?
* @return string
*/
static function readFilePartially($file, $len_bytes = 512, $seek_bytes = 0) {
$buff = '';
if (!file_exists($file)) {
return false;
}
$file_handle = fopen($file, 'rb');
if (!empty($file_handle)) {
if ($seek_bytes > 0) {
fseek($file_handle, $seek_bytes);
}
$buff = fread($file_handle, $len_bytes);
fclose($file_handle);
}
return $buff;
}
/**
* This plugin scans the files in a folder and tries to get plugin data.
* The real plugin file will have Name, Description variables set.
* If the file doesn't have that info WP will prefill the data with empty values.
*
* @param string $folder - plugin's folder e.g. wp-content/plugins/like-gate/
* @return string wp-content/plugins/like-gate/like-gate.php or false if not found.
*/
static public function findMainPluginFile($folder = '') {
$folder = trailingslashit($folder);
$files_arr = glob($folder . '*.php'); // list only php files.
foreach ($files_arr as $file) {
$buff = self::readFilePartially($file);
// Did we find the plugin? If yes, it'll have Name filled in.
if (stripos($buff, 'Plugin Name') !== false) {
return $file;
}
}
return false;
}
/**
* Extracts a which was saved in a tmp folder. We're expecting the zip file to contain a folder first
* and then some contents
* @param string $archive_file a file in the tmp folder
* @param string $target_directory usually wp-content/plugins/
* @see http://www.phpconcept.net/pclzip/user-guide/54
* @see http://core.trac.wordpress.org/browser/tags/3.6/wp-admin/includes/file.php#L0
*/
static public function extractArchiveFile($archive_file, $target_directory) {
$status = 0;
$error = $plugin_folder = $main_plugin_file = '';
// Requires WP to be loaded.
include_once(ABSPATH . 'wp-admin/includes/file.php');
include_once(ABSPATH . 'wp-admin/includes/class-pclzip.php');
if (function_exists('WP_Filesystem')) {
WP_Filesystem();
$archive = new PclZip($archive_file);
$list = $archive->listContent(); // this contains all of the files and directories
/*
array(2) {
[0]=>
array(10) {
["filename"]=>
string(7) "addons/"
["stored_filename"]=>
string(7) "addons/"
["size"]=>
int(0)
["compressed_size"]=>
int(0)
["mtime"]=>
int(1377115594)
["comment"]=>
string(0) ""
["folder"]=>
bool(true)
["index"]=>
int(0)
["status"]=>
string(2) "ok"
["crc"]=>
int(0)
}
[1]=>
array(10) {
["filename"]=>
string(39) "addons/!sak4wp-theme-troubleshooter.php"
["stored_filename"]=>
string(39) "addons/!sak4wp-theme-troubleshooter.php"
["size"]=>
int(2900)
["compressed_size"]=>
int(1112)
["mtime"]=>
int(1377116198)
["comment"]=>
string(0) ""
["folder"]=>
bool(false)
["index"]=>
int(1)
["status"]=>
string(2) "ok"
["crc"]=>
int(-1530906934)
}
}
*/
// the first element should be the folder. e.g. like-gate.zip -> like-gate/ folder
// listContent returns an array and folder key should be true.
foreach ($list as $file_or_dir_rec) {
if (empty($file_or_dir_rec['filename'])
|| preg_match('#^(\.|__)#si', $file_or_dir_rec['filename'])) { // skip hidden or MAC files
continue;
}
// We want to check if there is a folder at the root level (index=0).
if (!empty($file_or_dir_rec['folder']) && empty($file_or_dir_rec['index'])) {
$plugin_folder = $file_or_dir_rec['filename'];
break;
}
}
if (!empty($plugin_folder)) {
$status = unzip_file($archive_file, $target_directory);
} else {
$status = new WP_Error('100', "Cannot find plugin folder in the zip archive.");
}
if (is_wp_error($status)) {
$error = $status->get_error_message();
} else {
$status = 1;
$main_plugin_file = self::findMainPluginFile( trailingslashit( trailingslashit($target_directory) . $plugin_folder) );
}
} else {
$error = 'WP_Filesystem is not loaded.';
}
$data = array(
'status' => $status,
'error' => $error,
'plugin_folder' => $plugin_folder,
'main_plugin_file' => $main_plugin_file,
);
return $data;
}
/**
* Returns WordPress' uploads folder. Local path. The directory includes a trailing slash
* We may need to save some hidden files there which weren't a good match for the temp directory.
* Since this code is run before the WP load, we might need to guess it?
*
* @see http://codex.wordpress.org/Function_Reference/wp_upload_dir
* @return string
*/
public static function getWPUploadsDir() {
if (function_exists('wp_upload_dir')) {
$upload_dir = wp_upload_dir();
$dir = $upload_dir['basedir'];
$dir = rtrim($dir, '/') . '/';
} else {
$dir = dirname(__FILE__) . '/wp-content/uploads/';
}
// As a last resource we'll use temp dir.
// which is not a cool thing because anybody can search the temp folder
// and find out who is using SAK4WP
if (!is_dir($dir) || !is_writable($dir)) {
throw new Exception("Cannot find WordPress' upload_dir or it is not wriable.");
}
return $dir;
}
/**
* Tries to get the temp directory for php.
* It checks if this function exists: sys_get_temp_dir (since php 5.2).
* Otherwise it checks the ENV variables TMP, TEMP, and TMPDIR
*
* @see http://php.net/manual/en/function.sys-get-temp-dir.php
* @return string
*/
public static function getTempDir() {
$dir = '/tmp';
if (function_exists('sys_get_temp_dir')) {
$dir = sys_get_temp_dir();
} else {
if ($temp = getenv('TMP')) {
$dir = $temp;
} elseif ($temp = getenv('TEMP')) {
$dir = $temp;
} elseif ($temp = getenv('TMPDIR')) {
$dir = $temp;
} else {
$temp = tempnam(__FILE__, '');
if (file_exists($temp)) {
unlink($temp);
$dir = dirname($temp);
}
}
}
return $dir;
}
/**
* Parses the WP.org website to get the latest WP version.
* It uses the temp directory to store the version
*
* @param void
* @return string e.g. 3.5.1 or defaults to 0.0.0 in case of an error
*/
public static function getLatestWordPressVersion() {
$url = 'http://wordpress.org/download/';
$ver = $default_ver = '0.0.0'; // default
$ver_file = rtrim(self::getTempDir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'wp-ver.txt'; // C:\Windows\TEMP\wp-ver.txt
// we will check every 4h for a WP version
if (!file_exists($ver_file) || (time() - filemtime($ver_file) > 4 * 3600)) {
$result = Orbisius_WP_SAK_Util::makeHttpRequest($url);
if (empty($result['error'])) {
$body_buff = $result['buffer'];
// look for a link that points to latest.zip"
//
// Download WordPress 3.5.1
if (preg_match('#()#si', $body_buff, $matches)) {
$dl_link = $matches[1];
$dl_link = strip_tags($dl_link);
if (preg_match('#(\d+\.\d+(?:\.\d+)?[\w]*)#si', $dl_link, $ver_matches)) { // 1.2.3 or 1.2.3b
$ver = $ver_matches[1];
Orbisius_WP_SAK_Util_File::write($ver_file, $ver);
}
}
}
} else {
$ver = Orbisius_WP_SAK_Util_File::read($ver_file);
// Did somebody change the version file from the tmp?
// and inserted some bad JS?
if (!preg_match('#^[\.\d]+$#', $ver)) {
$ver = $default_ver;
}
}
return $ver;
}
/**
* Makes a request to a given URL. Headers are requested too.
*
* @param string
* @return array ; use $data['buffer'] to get the contents and $data['headers'] to get an array of headers.
* @see http://stackoverflow.com/questions/28395/passing-post-values-with-curl
*/
public static function makeHttpRequest($url, $params = array()) {
if (!function_exists('curl_init')) {
throw new Exception("Cannot find cURL php extension or it's not loaded.");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_VERBOSE, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
//curl_setopt($ch, CURLOPT_SSLVERSION,3);
if (defined('CURLOPT_CERTINFO')) {
curl_setopt($ch, CURLOPT_CERTINFO, 1);
}
curl_setopt($ch, CURLOPT_USERAGENT, empty($params['user_agent']) ? 'Mozilla/4.0 (compatible; MSIE 1.0; unknown)' : $params['user_agent']);
if (!empty($params)) {
if (isset($params['__req']) && strtolower($params['__req']) == 'get') {
unset($params['__req']);
$url .= '?' . http_build_query($params);
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
}
}
curl_setopt($ch, CURLOPT_URL, $url);
$buffer = curl_exec($ch);
$status = !empty($buffer);
$error = empty($buffer) ? curl_error($ch) : '';
$error_no = empty($buffer) ? curl_errno($ch) : '';
$data = array(
'status' => $status,
'error' => $error,
'error_no' => $error_no,
'debug' => curl_getinfo($ch),
);
curl_close($ch);
$data['debug']['ip'] = $_SERVER['REMOTE_ADDR'];
$data['debug']['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
if (empty($error)) {
$m = array();
// the buffer contains headers and the document body
$arr = preg_match('#(.*?)\r?\n\r?\n(.*)#si', $buffer, $m);
$headers_buff = $m[1];
$body_buff = trim($m[2]);
$data['buffer'] = $body_buff;
$data['raw_buffer'] = $buffer;
$header_lines = preg_split('#[\r]\n#si', $headers_buff);
// Parse header lines and put them in array
foreach ($header_lines as $line) {
$key = $val = '';
@list ($key, $val) = preg_split('#\s*:\s*#si', $line);
// parse status field: HTTP/1.1 200 OK
if (empty($val) && preg_match('#HTTP/1.\d\s(\d+)#si', $key, $matches)) {
$key = 'Status';
$val = $matches[1];
}
$data['headers'][$key] = $val;
}
}
return $data;
}
}
class Orbisius_WP_SAK_Controller {
private $on_document_ready_assets = array();
private function __construct() {
}
public function __destruct() {
// This is just here to remind you that the
// destructor must be public even in the case
// of a singleton.
}
public function __clone() {
trigger_error('Cloning instances of this class is forbidden.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Unserializing instances of this class is forbidden.', E_USER_ERROR);
}
/**
* Does some cleanup, outputs some text (if any) and exists.
*/
public function doExit($msg = '', $title = '') {
unset($this->params);
if (!empty($msg)) {
$app_name = ORBISIUS_WP_SAK_APP_SHORT_NAME;
echo "
$app_name: $msg
";
}
exit;
}
/**
* Performs some checks after wp-load
*/
public function check() {
if (!defined('ABSPATH')) {
die('ABSPATH is not defined. This script must be installed at the same level as your WordPress Installation.');
}
// Let's make sure we are protected all the time.
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Self_Protect();
$mod_obj->run();
}
private $params = [];
static private $_instance = null;
public static function getInstance() {
if (is_null(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Gets a variable from the request and removes any tags and trims spaces.
* That's of course if options are passed so the orignal value will be returned.
*/
public function getVar($key, $default = '', $options = array()) {
$val = isset($_REQUEST[$key]) ? $_REQUEST[$key] : $default;
if (!isset($options['raw'])) {
$val = strip_tags($val);
$val = trim($val);
}
return $val;
}
/**
* Gets a variable and casts it to an INT
*/
public function getIntVar($key, $default = 0) {
$val = isset($_REQUEST[$key]) ? intval($_REQUEST[$key]) : $default;
return $val;
}
/**
* Setup params.
*/
public function init() {
$params = $_REQUEST;
$params = array_map('trim', $params);
$this->params = $params;
}
/**
* Executes some quick and light actions that do not require WP to be loaded.
* E.g. outputting JS, CSS etc. as well as self destroy
*/
public function preRun() {
$params = $this->params;
if (isset($params['css'])) {
$this->outputStyles($params['css']);
} elseif (isset($params['js'])) {
$this->outputScripts($params['js']);
} elseif (isset($params['img'])) {
if ($params['img'] == 'icon_user') {
$img_buff = self::app_icon_user;
} else {
$img_buff = $params['img'] == 'glyphicons-halflings-white'
? self::bootstrap_glyphicons_halflings_white
: self::bootstrap_glyphicons_halflings;
}
$img_buff = base64_decode($img_buff);
$this->sendHeader(self::HEADER_IMAGE_PNG, $img_buff);
} elseif (isset($params['destroy'])) {
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Self_Protect();
$mod_obj->clean();
if (!unlink(__FILE__)) {
$this->doExit('Cannot self destroy. Please delete '
. __FILE__
. ' manually.');
}
// Redirect to the main site (/) and not to the file itself because this would log
// a page not found as if somebody was trying to access sak4wp file.
$this->redirect('/');
}
}
/**
* Executes tasks that require WP to loaded
*/
public function redirect($url, $status = 302) {
header('Location: ' . $url, true, $status);
$this->doExit();
}
/**
* Executes tasks that require WP to be loaded.
*/
public function run() {
$params = $this->params;
if (!empty($params['module']) && !empty($params['action'])) {
$module = $params['module'];
$action = $params['action'];
// e.g. Orbisius_WP_SAK_Controller_Module_Limit_Login_Attempts_Unblocker
$module_class = 'Orbisius_WP_SAK_Controller_Module_' . $module;
$obj_action_name = $action . 'Action';
// if the module name doesn't exist OR the class -> it's an error.
if (!class_exists($module_class)
|| (($obj = new $module_class()) && !method_exists($obj, $obj_action_name))) {
$status['status'] = 0;
$status['message'] = 'Internal Error.';
$this->sendHeader(Orbisius_WP_SAK_Controller::HEADER_JS, $status);
}
$obj->init();
$obj->$obj_action_name();
}
$this->displayHeader();
$this->displayFooter();
}
public function getParams() {
return $this->params;
}
/**
* WP should be loaded by now.
*/
public function postRun() {
}
/**
* Returns HTML content which is shown in the centre of the page.
*
* @param string $page
* @return string
*/
public function getPageContent($page = '') {
try {
$descr = '';
if (empty($page) && !empty($_REQUEST['page'])) {
$page = $_REQUEST['page'];
}
$script = ORBISIUS_WP_SAK_APP_SCRIPT;
$app_name = ORBISIUS_WP_SAK_APP_NAME;
switch ($page) {
case 'mod_self_protect':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Self_Protect();
$descr = $mod_obj->getInfo();
//$descr .= $mod_obj->run();
break;
case 'mod_user_manager':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_User_Manager();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_plugin_manager':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Plugin_Manager();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_locate_wp':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Locate_WordPress();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_search':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Search();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_htaccess':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Htaccess();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_stats':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Stats();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_list_page_templates':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_List_Page_Templates();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_unblock':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Limit_Login_Attempts_Unblocker();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_post_meta':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_PostMeta();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_user_meta':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_UserMeta();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_db_dump':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Db_Dump();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case 'mod_site_packager':
$mod_obj = new Orbisius_WP_SAK_Controller_Module_Site_Packager();
$descr = $mod_obj->getInfo();
$descr .= $mod_obj->run();
break;
case '':
case 'home':
$descr = <<$app_name is a standalone script which allows you to see some stats for your wordpress site and also perform some
recovery operations on your WordPress site.
This script is intended to be used for short time only and then removed in order to prevent security issues.
When you are done click on the Self Destroy
button and the script will attempt to delete itself (if it has the necessary permissions).
BUFF_EOF;
break;
case 'help':
$app_url = ORBISIUS_WP_SAK_APP_URL;
$ver = "Always remove this file when the work is complete!
| Powered by $app_name (v" . ORBISIUS_WP_SAK_APP_VER . ')';
$descr = <<Support
BUFF_EOF;
echo $buff;
}
/**
*
* @param string $buffer
* @param bool $render_in_footer
*/
public function enqeueOnDocumentReady($buffer) {
$this->on_document_ready_assets[] = $buffer;
}
public function displayFooter() {
$script = ORBISIUS_WP_SAK_APP_SCRIPT;
$on_document_ready_assets_str = join("\n\n", $this->on_document_ready_assets);
$buff = <<
BUFF_EOF;
echo $buff;
}
/**
* Renders a nice stats table. Expects that the data is rows of associative array.
* @param string $title - the text that will be shown above the table.
* @param array $data
* @param array $highlight_rows - some rows may need to be highlighted to stand out (diff bg color)
* @return string HTML table
*/
public function renderTable($title = '', $description = '', $data = array(), $highlight_rows = array()) {
$buff = '';
if (!empty($title)) {
$buff .= "
$title
\n";
}
if (!empty($description)) {
$buff .= "
$description
\n";
}
$buff .= "
\n";
foreach ($data as $idx => $row_obj) {
// conv. to array if necessary
$row_arr = is_object($row_obj) ? (array) $row_obj : $row_obj;
// let's put header col. we'll output the keys in a tr
if ($idx == 0) {
$buff .= "\t
\n";
foreach (array_keys($row_arr) as $key) {
$buff .= "\t\t
$key
\n";
}
$buff .= "\t
\n";
}
// Do we need to highlight the current row?
$extra_cls = (!empty($highlight_rows) && in_array($idx, $highlight_rows))
? ' app-table-hightlist-row ' : '';
$cls = $idx % 2 != 0 ? 'app-table-row-odd' : '';
$cls .= $extra_cls;
$buff .= "\t
\n";
// let's put header col. we'll output the keys in a tr
if ($idx == count($data) - 1) {
$buff .= "\t
\n";
foreach (array_keys($row_arr) as $key) {
$buff .= "\t\t
$key
\n";
}
$buff .= "\t
\n";
}
}
$buff .= "
\n";
return $buff;
}
/**
* Renders a nice stats table. Expects that the data is key value pairs.
* @param string $title - the text that will be shown above the table.
* @param array $data
* @return string HTML table
*/
public function renderKeyValueTable($title, $data = array(), $options = array()) {
$buff = '';
if (!empty($title)) {
$buff .= "
$title
\n";
}
// this is a nice way to add extra CSS
$table_css = empty($options['table_css']) ? '' : $options['table_css'];
$cnt = 0;
$buff .= "
\n";
if (!empty($options['header'])) {
$buff .= "\t
\n";
foreach ($options['header'] as $label) {
$buff .= "\t\t