plugins/ssh/classes/yf_ssh.class.php
<?php
/**
* SSH Client (based on SSH2 PHP extension).
*
* @author YFix Team <yfix.dev@gmail.com>
* @version 1.0
*/
class yf_ssh
{
// TODO: chained mode like in form and table, mass actions on one server, array of servers, named group(s) of servers:
// ssh('s23.dev')->exec('service memcached restart');
// ssh('s23*.dev')->exec('service memcached restart');
// ssh('s23.dev','s567.dev')->exec('service memcached restart');
// ssh(array('s23.dev','s567.dev'), 's89*.dev')->exec('service memcached restart');
// ssh('group:nginx_proxy')->exec('service nginx reload');
// ssh('group:nginx_proxy')->exec('service nginx reload', 'service cron reload');
// ssh('group:nginx_proxy', 's345.dev')->exec(array('service nginx reload', 'service cron reload'))->write_string('/tmp/last_mass_ssh_action.done', time());
// ssh('group:nginx_proxy', 's345.dev')->each(function($srv, $ssh){ $ssh->exec('service nginx reload'); });
/** @var string @conf_skip array('phpseclib','pecl_ssh2','auto') */
public $DRIVER = 'phpseclib';
/** @var bool @conf_skip */
public $_INIT_OK = false;
/** @var string @conf_skip */
public $_TMP_DIR = 'uploads/tmp';
/** @var enum('password','pubkey') */
public $AUTH_TYPE = 'password';
/** @var bool Save actions log or not */
public $LOG_ACTIONS = false;
/** @var bool Use archiving for mass actions */
public $MASS_USE_ARCHIVES = true;
/** @var string Path to the tar archiver in console */
public $TAR_PATH = '';
/** @var string Path to the gzip console programm */
public $GZIP_PATH = '';
/** @var bool */
public $USE_GZIP = true;
/** @var bool */
public $CONNECT_TIMEOUT = 5;
/** @var bool */
public $MAX_RECONNECTS = 1;
/** @var bool */
public $LOG_FULL_EXEC = 0;
/** @var bool */
public $_debug = [];
/**
* Catch missing method call.
* @param mixed $name
* @param mixed $args
*/
public function __call($name, $args)
{
return main()->extend_call($this, $name, $args);
}
/**
* Framework constructor.
*/
public function _init()
{
if ( ! $this->DRIVER) {
$this->DRIVER = 'phpseclib';
}
if ($this->DRIVER == 'phpseclib') {
require_php_lib('phpseclib_v1');
}
if ($this->DRIVER == 'phpseclib' && ! class_exists('Net_SSH2')) {
trigger_error('phpseclib Net_SSH2 not found', E_USER_WARNING);
return false;
} elseif ($this->DRIVER == 'pecl_ssh2' && ! function_exists('ssh2_connect')) {
trigger_error('function ssh2_connect does not exist', E_USER_WARNING);
return false;
}
$this->_INIT_OK = true;
}
/**
* Return internal SERVER_ID (usually 'ssh_host:ssh_port').
* @param mixed $server_info
*/
public function _get_server_id($server_info = [])
{
if ( ! $server_info) {
return false;
}
$ssh_host = $server_info['base_ip'] ? $server_info['base_ip'] : $server_info['ssh_host'];
$ssh_port = $server_info['ssh_port'] ? $server_info['ssh_port'] : 22;
if ( ! $ssh_host) {
return false;
}
return $ssh_host . ':' . $ssh_port;
}
/**
* Return remote OS string.
* @param mixed $server_info
*/
public function _get_remote_os($server_info = [])
{
$_SERVER_ID = $this->_get_server_id($server_info);
if (isset($this->_ssh_cache_os[$_SERVER_ID])) {
return $this->_ssh_cache_os[$_SERVER_ID];
}
$result = strtoupper(trim($this->exec($server_info, 'uname')));
$this->_ssh_cache_os[$_SERVER_ID] = $result;
return $result;
}
/**
* Connect to the remote server.
*
* @example
*
* $server_info = array(
* 'ssh_host' => '192.168.1.2',
* 'ssh_user' => 'root',
* 'ssh_pswd' => '111111',
* );
* @param mixed $server_info
*/
public function connect($server_info = [])
{
if ( ! $this->_INIT_OK || ! $server_info) {
return false;
}
$ssh_host = $server_info['base_ip'] ? $server_info['base_ip'] : $server_info['ssh_host'];
$ssh_port = $server_info['ssh_port'] ? $server_info['ssh_port'] : 22;
if ( ! $ssh_host) {
trigger_error('SSH: missing server IP to connect', E_USER_WARNING);
return false;
}
$_SERVER_ID = $this->_get_server_id($server_info);
// Cache calls to the same server
if (isset($this->_ssh_connected[$_SERVER_ID])) {
return $this->_ssh_connected[$_SERVER_ID];
}
if ($this->_ssh_try_to_connect[$_SERVER_ID] >= $this->MAX_RECONNECTS) {
return $this->_ssh_connected[$_SERVER_ID];
}
$ssh_user = $server_info['ssh_user'] ? $server_info['ssh_user'] : 'root';
$ssh_pswd = $server_info['ssh_pswd'];
if (DEBUG_MODE) {
$time_start = microtime(true);
}
// Try to connect to server with selected params
// This avoid long timeouts if server not connected
$fp = fsockopen($ssh_host, $ssh_port, $errno, $errstr, $this->CONNECT_TIMEOUT);
if ( ! $fp) {
$this->_ssh_try_to_connect[$_SERVER_ID]++;
trigger_error('SSH: cannot connect to: ' . $_SERVER_ID . '', E_USER_WARNING);
return false;
}
fclose($fp);
// IMPORTANT: for best execution speed need to do: apt-get install php5-gmp php5-mcrypt php5-mhash
if ($this->DRIVER == 'phpseclib') {
$use_pswd = true;
if ( ! empty($server_info['ssh_key_private'])) {
$use_pswd = false;
}
if ( ! $use_pswd) {
$key = new Crypt_RSA();
if ($server_info['ssh_key_pswd']) {
$key->setPassword($server_info['ssh_key_pswd']); // password for key
}
$key_result = $key->loadKey(file_get_contents($server_info['ssh_key_private']));
if ( ! $key_result) {
$this->_ssh_try_to_connect[$_SERVER_ID]++;
trigger_error('SSH: wrong key: ' . $server_info['ssh_key_private'] . ' for: ' . $_SERVER_ID . '', E_USER_WARNING);
return false;
}
}
$con = new Net_SSH2($ssh_host);
$auth_result = $con->login($ssh_user, $use_pswd ? $ssh_pswd : $key);
} elseif ($this->DRIVER == 'pecl_ssh2') {
$con = ssh2_connect($ssh_host, $ssh_port, null, []);
// Try to authenticate
$auth_result = false;
if ($con) {
if ( ! empty($server_info['ssh_key_public']) && ! empty($server_info['ssh_key_private'])) {
// using public key
$auth_result = ssh2_auth_pubkey_file($con, $ssh_user, $server_info['ssh_key_public'], $server_info['ssh_key_private']);
} else {
// using plain password
$auth_result = ssh2_auth_password($con, $ssh_user, $ssh_pswd);
}
}
}
if (DEBUG_MODE) {
$this->_debug['connect_time'] = microtime(true) - $time_start;
}
if ( ! $con) {
$this->_ssh_try_to_connect[$_SERVER_ID]++;
trigger_error('SSH: cannot connect to: ' . $_SERVER_ID, E_USER_WARNING);
return false;
}
if ($auth_result) {
$this->_ssh_connected[$_SERVER_ID] = $con;
$this->_log($server_info, __FUNCTION__, 'user: ' . $ssh_user . ', auth successful');
return $con;
}
trigger_error('SSH: auth on: ' . $ssh_host . ':' . $ssh_port . ' failed for ' . ($this->AUTH_TYPE == 'pubkey' ? 'pubkey: ' . $server_info['pubkey_path'] : 'user: ' . $ssh_user . ''), E_USER_WARNING);
return false;
}
/**
* SFTP subsystem for phpseclib.
* @param mixed $server_info
*/
public function _init_sftp_phpseclib($server_info = [])
{
if ( ! $this->DRIVER == 'phpseclib') {
return false;
}
if ( ! $this->_INIT_OK || ! $server_info) {
return false;
}
$ssh_host = $server_info['base_ip'] ? $server_info['base_ip'] : $server_info['ssh_host'];
$ssh_port = $server_info['ssh_port'] ? $server_info['ssh_port'] : 22;
if ( ! $ssh_host) {
trigger_error('SSH: missing server IP to connect', E_USER_WARNING);
return false;
}
$_SERVER_ID = $this->_get_server_id($server_info);
// Cache calls to the same server
if (isset($this->_sftp_connected[$_SERVER_ID])) {
return $this->_sftp_connected[$_SERVER_ID];
}
if ($this->_sftp_try_to_connect[$_SERVER_ID] >= $this->MAX_RECONNECTS) {
return $this->_sftp_connected[$_SERVER_ID];
}
$ssh_user = $server_info['ssh_user'] ? $server_info['ssh_user'] : 'root';
$ssh_pswd = $server_info['ssh_pswd'];
if (DEBUG_MODE) {
$time_start = microtime(true);
}
// Try to connect to server with selected params
// This avoid long timeouts if server not connected
$fp = fsockopen($ssh_host, $ssh_port, $errno, $errstr, $this->CONNECT_TIMEOUT);
if ( ! $fp) {
$this->_ssh_try_to_connect[$_SERVER_ID]++;
trigger_error('SSH: cannot connect to: ' . $_SERVER_ID, E_USER_WARNING);
return false;
}
fclose($fp);
$use_pswd = true;
if ($this->AUTH_TYPE == 'pubkey' && ! empty($server_info['ssh_key_private'])) {
$use_pswd = false;
}
if ( ! $use_pswd) {
$key = new Crypt_RSA();
if ($server_info['ssh_key_pswd']) {
$key->setPassword($server_info['ssh_key_pswd']); // password for key
}
$key_result = $key->loadKey(file_get_contents($server_info['ssh_key_private']));
if ( ! $key_result) {
$this->_ssh_try_to_connect[$_SERVER_ID]++;
trigger_error('SSH: wrong key: ' . $server_info['ssh_key_private'] . ' for: ' . $_SERVER_ID . '', E_USER_WARNING);
return false;
}
}
require_once 'Net/SFTP.php';
$con = new Net_SFTP($ssh_host);
$auth_result = $con->login($ssh_user, $use_pswd ? $ssh_pswd : $key);
if (DEBUG_MODE) {
$this->_debug['connect_time'] += microtime(true) - $time_start;
}
if ( ! $con) {
$this->_sftp_try_to_connect[$_SERVER_ID]++;
trigger_error('SSH: cannot connect to: ' . $_SERVER_ID, E_USER_WARNING);
return false;
}
if ($auth_result) {
$this->_sftp_connected[$_SERVER_ID] = $con;
$this->_log($server_info, __FUNCTION__, 'user: ' . $ssh_user . ', auth successful');
return $con;
}
trigger_error('SSH: auth on ' . $ssh_host . ':' . $ssh_port . ' failed for ' . ($this->AUTH_TYPE == 'pubkey' ? 'pubkey: ' . $server_info['pubkey_path'] : 'user: ' . $ssh_user . ''), E_USER_WARNING);
return false;
}
/**
* Executes remote command on given shell and returns result.
* @param mixed $server_info
* @param mixed $cmd
*/
public function exec($server_info = [], $cmd = '')
{
if ( ! $this->_INIT_OK || ! $cmd || ! $server_info) {
return false;
}
$con = $this->connect($server_info);
if ( ! $con) {
return false;
}
// Execute several commands per one call ($cmd as array)
if (is_array($cmd)) {
$result = [];
foreach ((array) $cmd as $k => $v) {
$result[$k] = $this->exec($server_info, $v);
}
return $result;
}
$data = false;
if (DEBUG_MODE) {
$time_start = microtime(true);
}
// execute a command
if ($this->DRIVER == 'phpseclib') {
$data = $con->exec($cmd);
if (false === $data) {
trigger_error('SSH: failed to execute remote command', E_USER_WARNING);
return false;
}
} elseif ($this->DRIVER == 'pecl_ssh2') {
if ( ! ($stream = ssh2_exec($con, $cmd, false))) {
trigger_error('SSH: failed to execute remote command', E_USER_WARNING);
return false;
}
// collect returning data from command
stream_set_blocking($stream, true);
$data = '';
while ($buf = fgets($stream)) {
$data .= $buf;
}
fclose($stream);
}
if (DEBUG_MODE) {
$exec_time = microtime(true) - $time_start;
$debug_info .= '<b>' . common()->_format_time_value($exec_time) . ' sec</b>,' . PHP_EOL;
$debug_info .= 'func: <b>' . __FUNCTION__ . '</b>, server: ' . $server_info['base_ip'] . ',' . PHP_EOL;
$debug_info .= "cmd: \"<b style='color:blue;'>" . $cmd . '</b>" ' . ($this->LOG_FULL_EXEC ? ", <b>response</b>:<br />\n <pre><small>" . trim($data) . "</small></pre>\n" : '') . '<br />';
$this->_debug['exec'][] = $debug_info;
$this->_debug['time_sum'] += $exec_time;
}
$this->_log($server_info, __FUNCTION__, $cmd);
return $data;
}
/**
* Remote shell exec.
* @param mixed $server_info
* @param mixed $cmd
*/
public function shell_exec($server_info = [], $cmd = '')
{
if ( ! $this->_INIT_OK || ! $cmd || ! $server_info) {
return false;
}
if ( ! ($con = $this->connect($server_info))) {
return false;
}
// Execute several commands per one call ($cmd as array)
if (is_array($cmd)) {
$result = [];
foreach ((array) $cmd as $k => $v) {
$result[$k] = $this->shell_exec($server_info, $v);
}
return $result;
}
$data = false;
if (DEBUG_MODE) {
$time_start = microtime(true);
}
// execute a command
if ($this->DRIVER == 'phpseclib') {
// Really not supported by lib, but should work as wrapper for exec
$data = $con->exec($cmd);
if (false === $data) {
trigger_error('SSH: failed to execute remote command', E_USER_WARNING);
return false;
}
} elseif ($this->DRIVER == 'pecl_ssh2') {
if ( ! isset($this->shell)) {
$this->shell = ssh2_shell($con, 'xterm');
}
if ( ! (fwrite($this->shell, $cmd . PHP_EOL))) {
trigger_error('SSH: failed to execute remote command', E_USER_WARNING);
return false;
}
// collect returning data from command
stream_set_blocking($this->shell, true);
$data = '';
while ($buf = fgets($this->shell)) {
$data .= $buf;
}
fclose($this->shell);
}
if (DEBUG_MODE) {
$exec_time = microtime(true) - $time_start;
$debug_info .= '<b>' . common()->_format_time_value($exec_time) . " sec</b>,\n";
$debug_info .= 'func: <b>' . __FUNCTION__ . '</b>, server: ' . $server_info['base_ip'] . ",\n";
$debug_info .= "cmd: \"<b style='color:blue;'>" . $cmd . '</b>" ' . ($this->LOG_FULL_EXEC ? ", <b>response</b>:<br />\n <pre><small>" . trim($data) . "</small></pre>\n" : '') . '<br />';
$this->_debug['exec'][] = $debug_info;
$this->_debug['time_sum'] += $exec_time;
}
$this->_log($server_info, __FUNCTION__, $cmd);
return $data;
}
/**
* Read remote file.
* @param mixed $server_info
* @param mixed $remote_file
* @param mixed $local_file
*/
public function read_file($server_info = [], $remote_file = '', $local_file = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $remote_file, $local_file);
}
/**
* Write local file into remote file.
* @param mixed $server_info
* @param mixed $local_file
* @param mixed $remote_file
*/
public function write_file($server_info = [], $local_file = '', $remote_file = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $local_file, $remote_file);
}
/**
* Write string into remote file.
* @param mixed $server_info
* @param mixed $string
* @param mixed $remote_file
*/
public function write_string($server_info = [], $string = '', $remote_file = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $string, $remote_file);
}
/**
* Check if file exists remotely.
* @param mixed $server_info
* @param mixed $path
*/
public function file_exists($server_info = [], $path = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path);
}
/**
* Get selected file info.
* @param mixed $server_info
* @param mixed $path
*/
public function file_info($server_info = [], $path = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path);
}
/**
* Resolve full path for the given file, dir or link.
* @param mixed $server_info
* @param mixed $path
*/
public function realpath($server_info = [], $path = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path);
}
/**
* Scan remote dir and return array of files details.
* @param mixed $server_info
* @param mixed $start_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param mixed $level
* @param mixed $single_file
*/
public function scan_dir($server_info = [], $start_dir = '', $pattern_include = '', $pattern_exclude = '', $level = 0, $single_file = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $start_dir, $pattern_include, $pattern_exclude, $level, $single_file);
}
/**
* Alias for the mkdir_m.
* @param mixed $server_info
* @param mixed $dir_name
* @param mixed $dir_mode
* @param mixed $create_index_htmls
* @param mixed $start_folder
*/
public function mkdir($server_info = [], $dir_name = '', $dir_mode = 755, $create_index_htmls = 0, $start_folder = '')
{
return $this->mkdir_m($server_info, $dir_name, $dir_mode, $create_index_htmls, $start_folder);
}
/**
* Create multiple dirs at one time (eg. mkdir_m("some_dir1/some_dir2/some_dir3")).
* @param mixed $server_info
* @param mixed $dir_name
* @param mixed $dir_mode
* @param mixed $create_index_htmls
* @param mixed $start_folder
*/
public function mkdir_m($server_info = [], $dir_name = '', $dir_mode = 755, $create_index_htmls/*!not implemented here!*/ = 0, $start_folder = '/')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $dir_name, $dir_mode, $create_index_htmls, $start_folder);
}
/**
* Remove remote dir.
* @param mixed $server_info
* @param mixed $path
*/
public function rmdir($server_info = [], $path = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path);
}
/**
* Unlink remote file or link.
* @param mixed $server_info
* @param mixed $path
*/
public function unlink($server_info = [], $path = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path);
}
/**
* Chmod remote file.
* @param mixed $server_info
* @param mixed $path
* @param null|mixed $new_mode
* @param mixed $recursively
*/
public function chmod($server_info = [], $path = '', $new_mode = null, $recursively = false)
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path, $new_mode, $recursively);
}
/**
* Chown remote file.
* @param mixed $server_info
* @param mixed $path
* @param mixed $new_owner
* @param mixed $new_group
* @param mixed $recursively
*/
public function chown($server_info = [], $path = '', $new_owner = '', $new_group = '', $recursively = false)
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $path, $new_owner, $new_group, $recursively);
}
/**
* Rename remote file, dir or link.
* @param mixed $server_info
* @param mixed $old_name
* @param mixed $new_name
*/
public function rename($server_info = [], $old_name = '', $new_name = '')
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $old_name, $new_name);
}
/**
* Copy remote dir structure into local one (bulk method).
* @param mixed $server_info
* @param mixed $remote_dir
* @param mixed $local_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param null|mixed $level
*/
public function download_dir($server_info = [], $remote_dir = '', $local_dir = '', $pattern_include = '', $pattern_exclude = '', $level = null)
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $remote_dir, $local_dir, $pattern_include, $pattern_exclude, $level);
}
/**
* Copy local dir structure into remote one (bulk method).
* @param mixed $server_info
* @param mixed $local_dir
* @param mixed $remote_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param null|mixed $level
*/
public function upload_dir($server_info = [], $local_dir = '', $remote_dir = '', $pattern_include = '', $pattern_exclude = '', $level = null)
{
$f = __FUNCTION__;
return _class('ssh_files', 'classes/ssh/')->$f($server_info, $local_dir, $remote_dir, $pattern_include, $pattern_exclude, $level);
}
/**
* Recursively scanning directory structure (including subdirectories) //.
* @param mixed $path
* @param mixed $_type
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function _skip_by_pattern($path = '', $_type = 'f', $pattern_include = '', $pattern_exclude = '')
{
if ( ! $path) {
return false;
}
if ( ! $pattern_include && ! $pattern_exclude) {
return false;
}
if ( ! $type || ! in_array($type, 'f', 'd', 'l')) {
return false;
}
$_path_clean = trim(str_replace('//', '/', str_replace('\\', '/', $path)));
// Include files only if they match the mask
if ($_type == 'd') {
$_index = 0;
$_path_clean = rtrim($_path_clean, '/');
} elseif ($_type == 'f') {
$_index = 1;
} elseif ($_type == 'l') {
$_index = 2;
}
if (is_array($pattern_include)) {
$pattern_include = $pattern_include[$_index];
}
if (is_array($pattern_include)) {
$pattern_exclude = $pattern_exclude[$_index];
}
if ( ! empty($pattern_include) && is_string($pattern_include)) {
// Matching file type (pattern like "-d")
if ($pattern_include[0] == '-') {
if ($_type != $pattern_include[1]) {
return true;
}
}
// Regex searching
if ( ! preg_match($pattern_include . 'ims', $_path_clean)) {
return true;
}
}
// Exclude files from list by mask
if ( ! empty($pattern_exclude) && is_string($pattern_exclude)) {
// Matching file type (pattern like "-d")
if ($pattern_exclude[0] == '-') {
if ($_type == $pattern_exclude[1]) {
return true;
}
}
// Regex searching
if (preg_match($pattern_exclude . 'ims', $_path_clean)) {
return true;
}
}
return false;
}
/**
* Compress files to tar archive (local).
* @param mixed $files_list
* @param mixed $archive_path
*/
public function _local_make_tar($files_list = [], $archive_path = '')
{
$f = __FUNCTION__;
return _class('ssh_tar', 'classes/ssh/')->$f($files_list, $archive_path);
}
/**
* Extract files from tar archive (local).
* @param mixed $archive_path
* @param mixed $extract_path
*/
public function _local_extract_tar($archive_path = '', $extract_path = '')
{
$f = __FUNCTION__;
return _class('ssh_tar', 'classes/ssh/')->$f($files_list, $archive_path);
}
/**
* Clean path from SFTP prefix (usually for pretty output for user).
* @param mixed $path
*/
public function clean_path($path = '')
{
$pattern = '#^(ssh2\.sftp://Resource id \#[0-9]+)#ims';
if (is_array($path)) {
// Get current resource string
$cur = current($path);
if (is_array($cur)) {
$cur = current($cur);
}
preg_match($pattern, $cur, $m);
return str_replace($m[1], '', $path);
}
return preg_replace($pattern, '', $path);
}
/**
* Prepare path, Prevent some hacks and misuses.
* @param mixed $path
*/
public function _prepare_path($path = '')
{
if (is_array($path)) {
foreach ((array) $path as $k => $v) {
$path[$k] = $this->_prepare_path($v);
}
return $path;
}
$bad_chars = ['`', '"', "'", '..', '~', ' ', "\t", "\r", "\n", '|', '<', '>', '&'];
$result = str_replace($bad_chars, '', rtrim(str_replace(['\\', '//', '///'], '/', trim($path)), '/'));
return $result ? $result : '/';
}
/**
* Prepare text for using inside (grep '%text%') or similar commands.
* @param mixed $text
*/
public function _prepare_text($text = '')
{
if (is_array($text)) {
foreach ((array) $path as $k => $v) {
$text[$k] = $this->_prepare_text($v);
}
return $text;
}
$text = preg_replace('/[\x0A-\xFF]/i', '', $text);
$replace = [
'\\' => '\\\\',
'`' => '\\`',
'"' => '\\"',
"'" => "\\'",
'|' => '\\|',
'<' => '\\<',
'>' => '\\>',
'&' => '\\&',
"\t" => '',
"\r" => '',
"\n" => '',
];
$text = str_replace(array_keys($replace), array_values($replace), $text);
return $text;
}
/**
* Log internal action (Currently we store here successful actions, not errors for debug).
* @param mixed $server_info
* @param mixed $action
* @param mixed $comment
*/
public function _log($server_info = [], $action = '', $comment = '')
{
if ( ! $this->LOG_ACTIONS) {
return false;
}
$SERVER_ID = $this->_get_server_id($server_info);
$sql_array = [
'server_id' => _es($SERVER_ID),
'microtime' => _es(str_replace(',', '.', microtime(true))),
'init_type' => _es(MAIN_TYPE),
'action' => _es($action),
'comment' => _es($comment),
'get_object' => _es($_GET['object']),
'get_action' => _es($_GET['action']),
'user_id' => (int) ($_SESSION['user_id']),
'user_group' => (int) ($_SESSION['user_group']),
'ip' => _es(common()->get_ip()),
];
return db()->INSERT('log_ssh_action', $sql_array);
}
/**
* Convert string permission output to numerical.
* @param mixed $perm
*/
public function _perm_str2num($perm = '')
{
$perm_len = strlen(trim($perm));
if ($perm_len > 10 && $perm_len < 9) {
return false;
}
if ($perm_len == 10) {
$perm = substr($perm, 1);
}
// Compatibility with sticky bit, setuid, setgid (http://en.wikipedia.org/wiki/File_system_permissions)
$perm = str_replace(['s', 'S', 't', 'T'], ['x', '-', 'x', '-'], $perm);
foreach ((array) str_split($perm) as $k => $v) {
if ($v == '-') {
continue;
}
// Owner
if ($k == 0) {
$own += 4;
}
if ($k == 1) {
$own += 2;
}
if ($k == 2) {
$own += 1;
}
// Group
if ($k == 3) {
$grp += 4;
}
if ($k == 4) {
$grp += 2;
}
if ($k == 5) {
$grp += 1;
}
// Others
if ($k == 6) {
$oth += 4;
}
if ($k == 7) {
$oth += 2;
}
if ($k == 8) {
$oth += 1;
}
}
return '0' . $own . '' . $grp . '' . $oth;
}
}