'Автостарт сервера в случае его падения (через cron)', 'SERVER_RCON_AUTOCHANGE' => 'Автоматическая смена rcon пароля, в случае если в админпанели и на сервере он не совпадает', ); var $server_settings = array(); var $commands = array(); // Команды, которые отправлялись на сервер var $errors = ''; // Строка с ошибкой (если имеются) function __construct() { // Call the Model constructor parent::__construct(); $this->load->helper('safety'); } function _strip_quotes($string) { $string = str_replace('"', '', $string); $string = str_replace('\'', '', $string); return $string; } //----------------------------------------------------------- /* * Проверяет директорию на необходимые права * * */ function _check_path($path) { if (!is_dir($path)) { /* Это не директория */ $this->errors = "Dir " . $path . " not found"; return FALSE; } return TRUE; } //----------------------------------------------------------- /* * Проверяет файл на необходимые права * * @param str - путь к локальному файлу * @return bool * */ function _check_file($file) { if (!file_exists($file)) { $this->errors = 'Error: ' . $file . ' file not found'; return FALSE; } if (!is_executable($file)) { $this->errors = 'Error: ' . $file . ' file not executable'; return FALSE; } return TRUE; } //----------------------------------------------------------- /* * Генерирует команду для отправки на сервер * * */ function command_generate($server_data, $type = 'start') { /* Получение команд из данных сервера */ switch($type){ case 'start': $command = $server_data['script_start']; break; case 'stop': $command = $server_data['script_stop']; break; case 'restart': $command = $server_data['script_restart']; break; case 'update': $command = $server_data['script_update']; break; case 'get_console': $command = $server_data['script_get_console']; break; default: return FALSE; } /*-------------------*/ /* Шаблонная замена */ /*-------------------*/ /* В случае использования Windows значение может быть пустым * и параметры собьются */ if(empty($server_data['screen_name'])) { $server_data['screen_name'] = 'null'; } $command = str_replace('{command}', $this->_strip_quotes($server_data['start_command']) , $command); // Команда запуска игрового сервера (напр. "hlds_run -game valve +ip 127.0.0.1 +port 27015 +map crossfire") $command = str_replace('{id}', $this->_strip_quotes($server_data['id']) , $command); // ID сервера $command = str_replace('{script_path}', $this->_strip_quotes($server_data['script_path']) , $command); $command = str_replace('{game_dir}', $this->_strip_quotes($server_data['dir']) , $command); // Директория с игрой $command = str_replace('{dir}', $this->_strip_quotes($server_data['script_path'] . '/' . $server_data['dir']) , $command); // Корневая директория (где скрипт запуска) $command = str_replace('{name}', $this->_strip_quotes($server_data['screen_name']) , $command); // Имя скрина $command = str_replace('{ip}', $this->_strip_quotes($server_data['server_ip']) , $command); // IP сервера для коннекта (может не совпадать с ip дедика) $command = str_replace('{port}', $this->_strip_quotes($server_data['server_port']) , $command); // Порт сервера для коннекта $command = str_replace('{game}', $this->_strip_quotes($server_data['start_code']) , $command); // Игра $command = str_replace('{user}', $this->_strip_quotes($server_data['su_user']) , $command); // Пользователь /*-------------------*/ /* Замена по алиасам */ /*-------------------*/ /* Допустимые алиасы */ $allowable_aliases = json_decode($server_data['aliases_list'], TRUE); /* Значения алиасов на сервере */ $server_aliases = json_decode($server_data['aliases'], TRUE); /* Прогон по алиасам */ if($allowable_aliases && !empty($allowable_aliases)){ foreach ($allowable_aliases as $alias) { if(isset($server_aliases[$alias['alias']]) && !empty($server_aliases[$alias['alias']])) { $command = str_replace('{' . $alias['alias'] . '}', $server_aliases[$alias['alias']] , $command); } } } return $command; } //----------------------------------------------------------- /* * Добавляет sudo к команде * * */ public function add_sudo($command, $server_data) { /* Если игровой сервер локальный, т.е. запущен на том же физическом сервере, что * и админпанель, то запускаться он будет от пользователя www-data, который сделать * это не сможет, для решения проблемы необходимо чтобы скрипт запускался из-под рута */ if(is_array($server_data)) { $os = $server_data['os']; } else { $os = $server_data; } switch(strtolower($os)){ case 'ubuntu': $command = 'sudo ' . $command; break; case 'debian': $command = 'sudo ' . $command; break; case 'linux': $command = 'sudo ' . $command; break; case 'centos': $command = 'sudo ' . $command; break; default: /* Для windows никаких sudo не требуется */ //$command = $command; break; } return $command; } //----------------------------------------------------------- /* * Функция отправляет команду на сервер */ function command($command, $server_data, $path = FALSE) { /* * Чтобы сервер успешно запустился через exec нужно: * выполнить: * sudo nano /etc/sudoers * добавить в конец: * www-data ALL = NOPASSWD: /путь/к/скрипту * * Условие проверяет, является ли сервер локальным, * если является то запускается простая команда exec * если является удаленным, то идет обращение к функции ssh_command * для отправки команды через ssh * */ /* ------------------- * Определяем путь * ------------------- */ if(!$path) { $path = $server_data['script_path']; } /* Добавляем команду в зависимости от ОС */ switch(strtolower($server_data['os'])) { case 'windows': /* Замена нормального линуксовского слеша * на ненормальный виндовый \ */ $path = str_replace('/', '\\', $path); $cd = "cd /D " . $path; break; default: $cd = "cd " . $path; break; } if($server_data['local_server']) { if (!$this->_check_path($path)) { return $this->errors; } if(is_array($command)) { $result = ''; foreach($command as $cmd_arr) { /* Проверка существования исполняемого файла и прав на выполнение */ $script_file = explode(' ', $cmd_arr); $script_file = $script_file[0]; $script_file = str_replace('./', '', $script_file); if (!$this->_check_file($path . '/' . $script_file)) { $result .= $this->errors; } if($result) { $result .= "\n---\n"; } $cmd_arr = $this->add_sudo($cmd_arr, $server_data['os']); $result .= exec($cd . ' && ' . $cmd_arr); $this->commands[] = $cd . ' && ' . $cmd_arr; } } else { /* Проверка существования исполняемого файла и прав на выполнение */ $script_file = explode(' ', $command); $script_file = $script_file[0]; $script_file = str_replace('./', '', $script_file); /* * Проверяем, существует ли файл * Проверяется файлы .sh, если это команда, например wget, то * проверки не будет */ if (strpos($command, '.sh') !== FALSE && !$this->_check_file($path . '/' . $script_file)) { return $this->errors; } $command = $this->add_sudo($command, $server_data['os']); $result = exec($cd . ' && ' . $command); $this->commands[] = $cd . ' && ' . $command; } } else { /* Удаленная машина */ if (strtolower($server_data['control_protocol']) == 'telnet') { /* Загрузка необходимой библиотеки */ $this->load->library('telnet'); //~ $result = $this->telnet_command($command, $server_data, $path); /* Получение данных для соединения */ $telnet_data = explode(':', $server_data['telnet_host']); $telnet_ip = $telnet_data['0']; if(!isset($telnet_data['1'])){ $telnet_port = 23; // Стандартный порт telnet }else{ $telnet_port = $telnet_data['1']; } $this->telnet->connect($telnet_ip, $telnet_port); $this->telnet->auth($server_data['telnet_login'], $server_data['telnet_password']); $result = ''; if(is_array($command)) { foreach($command as $cmd_arr) { //~ $this->telnet->write($cd . ' && ' . $cmd_arr . "\r\n"); $result .= $this->telnet->command($cd . ' && ' . $cmd_arr . "\r\n"); $result .= "\n/------------------------/\n\n"; $this->commands[] = $cd . ' && ' . $cmd_arr . "\r\n"; } } else { //~ $this->telnet->write($cd . ' && ' . $command . "\r\n"); $result = $this->telnet->command($cd . ' && ' . $command . "\r\n"); $this->commands[] = $cd . ' && ' . $command . "\r\n"; } } else { /* Загрузка необходимой библиотеки */ $this->load->library('ssh'); $result = ''; $ssh_data = explode(':', $server_data['ssh_host']); $ssh_ip = $ssh_data['0']; if(!isset($ssh_data['1'])){ $ssh_port = 22; }else{ $ssh_port = $ssh_data['1']; } $this->ssh->connect($ssh_ip, $ssh_port); if ($this->ssh->auth($server_data['ssh_login'], $server_data['ssh_password'])) { if(is_array($command)) { foreach($command as $cmd_arr) { //~ $stream[] = ssh2_exec($connection, $cd . ' && ' . $cmd_arr); $result .= $this->ssh->command($cd . ' && ' . $cmd_arr); $this->commands[] = $cd . ' && ' . $cmd_arr; $result = "\n/------------------------/\n\n"; } } else { //~ $stream[] = ssh2_exec($connection, $cd . ' && ' . $command); $result = $this->ssh->command($cd . ' && ' . $command); $this->commands[] = $cd . ' && ' . $command; } } } } if ($result) { return $result; }else{ return FALSE; } return FALSE; } /* * Запуск сервера * * @param array - данные сервера или его id * */ function start($server_data) { if(!is_array($server_data)) { // был передан id, получаем данные сервера $server_data = $this->get_server_data($server_data, FALSE, TRUE, TRUE); } $command = $this->command_generate($server_data, 'start'); $result = $this->command($command, $server_data); return $result; } //----------------------------------------------------------- /* * Остановка сервера * * @param array - данные сервера * */ function stop($server_data) { if(!is_array($server_data)) { // был передан id, получаем данные сервера $server_data = $this->get_server_data($server_data, FALSE, TRUE, TRUE); } $command = $this->command_generate($server_data, 'stop'); $result = $this->command($command, $server_data); return $result; } //----------------------------------------------------------- /* * Перезапуск сервера * * @param array - данные сервера * */ function restart($server_data) { if(!is_array($server_data)) { // был передан id, получаем данные сервера $server_data = $this->get_server_data($server_data, FALSE, TRUE, TRUE); } $command = $this->command_generate($server_data, 'restart'); $result = $this->command($command, $server_data); return $result; } //----------------------------------------------------------- /* * Перезапуск сервера * * @param array - данные сервера * */ function update($server_data) { if(!is_array($server_data)) { // был передан id, получаем данные сервера $server_data = $this->get_server_data($server_data, FALSE, TRUE, TRUE); } $command = $this->command_generate($server_data, 'update'); /* Определение пути до steamcmd */ if ($server_data['steamcmd_path']) { $steamcmd_path = $server_data['steamcmd_path']; } else { $steamcmd_path = FALSE; } $result = $this->command($command, $server_data, $steamcmd_path); return $result; } //----------------------------------------------------------- /* * Добавление нового сервера * * */ function add_game_server($data) { $this->load->helper('string'); $this->load->model('games'); /* Присваиваем имя scren */ $data['screen_name'] = (!isset($data['screen_name'])) ? $data['game'] . '_' . random_string('alnum', 6) . '_' . $data['server_port'] : $data['screen_name']; if ($this->db->insert('servers', $data)) { return TRUE; } else { return FALSE; } } //----------------------------------------------------------- /* * Редактирование сервера * * */ function edit_game_server($id, $data) { $this->db->where('id', $id); if($this->db->update('servers', $data)){ return TRUE; }else{ return FALSE; } } //----------------------------------------------------------- /* * Удаление сервера * * */ function delete_game_server($id) { if ($this->db->delete('servers', array('id' => $id))) { $this->db->delete('servers_privileges', array('server_id' => $id)); $this->db->delete('logs', array('server_id' => $id)); return TRUE; } else { return FALSE; } } //----------------------------------------------------------- /** * Получение списка серверов * * @param int - id пользователя для которого получаем серверы * @param str - привилегия пользователя * @param array - where для запроса sql * */ function get_server_list($user_id = FALSE, $privilege_name = 'VIEW', $where = array('enabled' => '1', 'installed' => '1', )) { return $this->get_servers_list($user_id, $privilege_name, $where); } //----------------------------------------------------------- /** * Получение списка серверов * * @param int - id пользователя для которого получаем серверы * @param str - привилегия пользователя * @param array - where для запроса sql * */ function get_servers_list($user_id = FALSE, $privilege_name = 'VIEW', $where = array('enabled' => '1', 'installed' => '1', )) { /* * Если user_id не задан, то получаем все серверы * Если задан, то получаем лишь серверы владельцем * которых является user_id */ if (!$user_id) { $this->db->where($where); $query = $this->db->get('servers'); } else { /* * Выбираются данные из таблицы servers_privileges * для пользователя $user_id со следующими привилегиями: * privilege_name = $privilege_name * privilege_value = 1 (разрешено) */ $query = $this->db->get_where('servers_privileges', array('user_id' => $user_id, 'privilege_name' => $privilege_name, 'privilege_value' => '1')); if($query->num_rows > 0){ $this->db->where($where); foreach ($query->result_array() as $privileges){ $servers[] = $privileges['server_id']; } $this->db->where_in('id', $servers); } else { /* Количество серверов = 0 */ /* * Чтобы избавиться от некоторых уязвимостей, связанных с бесправными пользователями * у которых нет серверов, но при этом они отображаются в списке */ $this->servers_list = array(); return NULL; } $query = $this->db->get('servers'); } if ($query->num_rows > 0) { $a = 0; foreach ($query->result_array() as $server_data) { $server_list[$a] = $server_data; if (!$server_data['query_port']) { $server_list[$a]['query_port'] = $server_data['server_port']; } if (!$server_data['rcon_port']) { $server_list[$a]['rcon_port'] = $server_data['server_port']; } $a++; } $this->servers_list = $server_list; return $this->servers_list; } else { /* Количество серверов = 0 */ /* * Чтобы избавиться от некоторых уязвимостей, связанных с бесправными пользователями * у которых нет серверов, но при этом они отображаются в списке */ $this->servers_list = array(); return NULL; } } //----------------------------------------------------------- /** * Получение данных сервера * * @param int - id сервера * @param bool - если TRUE, то данные выделенного сервера получены не будут * @param bool - если TRUE, то данные игры получены не будут * @param bool - если TRUE, то данные типа игры получены не будут * * @return array * */ function get_server_data($server_id, $no_get_ds = FALSE, $no_get_game = FALSE, $no_get_gt = FALSE) { // Загрузка необходимых моделей $this->load->model('servers/dedicated_servers'); $this->load->model('servers/games'); $this->load->model('servers/game_types'); $this->load->library('encrypt'); $return_data = array(); // Возвращаемые данные о сервере $query = $this->db->get_where('servers', array('id' => $server_id), 1); if($query->num_rows > 0) { $this->server_data = $query->row_array(); /* Записываем переменную в список */ $this->servers_list['0'] = $this->server_data; /* Расшифровываем RCON пароль */ $this->server_data['rcon'] = $this->encrypt->decode($this->server_data['rcon']); /* Получаем query и rcon порты */ if (!$this->server_data['query_port']) { $this->server_data['query_port'] = $this->server_data['server_port']; } if (!$this->server_data['rcon_port']) { $this->server_data['rcon_port'] = $this->server_data['server_port']; } /* * Получение информации об удаленном сервере * * Необходимо, чтобы был указан ds_id (ID выделенного сервере) * если он будет равен 0 или не будет указан, то сервер * принимается за локальный * */ if (!$no_get_ds && $this->server_data['ds_id']) { $where = array('id' => $this->server_data['ds_id']); $this->dedicated_servers->get_ds_list($where, 1); $this->server_ds_data = $this->dedicated_servers->ds_list['0']; // Данные для игрового сервера из машины $this->server_data['os'] = strtolower($this->server_ds_data['os']); $this->server_data['local_server'] = 0; switch (strtolower($this->server_ds_data['control_protocol'])) { case 'ssh': $this->server_data['control_protocol'] = 'ssh'; break; case 'telnet': $this->server_data['control_protocol'] = 'telnet'; break; default: if ($this->server_data['os'] == 'windows') { $this->server_data['control_protocol'] = 'telnet'; } else { $this->server_data['control_protocol'] = 'ssh'; } break; } $this->server_data['ssh_host'] = $this->server_ds_data['ssh_host']; $this->server_data['ssh_login'] = $this->server_ds_data['ssh_login']; $this->server_data['ssh_password'] = $this->server_ds_data['ssh_password']; $this->server_data['ssh_passwd'] = $this->server_ds_data['ssh_password']; $this->server_data['ssh_path'] = $this->server_ds_data['ssh_path']; $this->server_data['telnet_host'] = $this->server_ds_data['telnet_host']; $this->server_data['telnet_login'] = $this->server_ds_data['telnet_login']; $this->server_data['telnet_password'] = $this->server_ds_data['telnet_password']; $this->server_data['telnet_path'] = $this->server_ds_data['telnet_path']; $this->server_data['ftp_host'] = $this->server_ds_data['ftp_host']; $this->server_data['ftp_login'] = $this->server_ds_data['ftp_login']; $this->server_data['ftp_password'] = $this->server_ds_data['ftp_password']; $this->server_data['ftp_passwd'] = $this->server_ds_data['ftp_password']; $this->server_data['ftp_path'] = $this->server_ds_data['ftp_path']; /* Определение пути до скрипта и до steamcmd */ switch ($this->server_data['control_protocol']) { case 'local': $this->server_data['script_path'] = $this->config->config['local_script_path']; $this->server_data['steamcmd_path'] = $this->config->config['local_steamcmd_path']; break; case 'telnet': $this->server_data['script_path'] = $this->server_ds_data['telnet_path']; $this->server_data['steamcmd_path'] = $this->server_ds_data['steamcmd_path']; break; default: // По умолчанию SSH $this->server_data['script_path'] = $this->server_ds_data['ssh_path']; $this->server_data['steamcmd_path'] = $this->server_ds_data['steamcmd_path']; break; } //$this->server_data['control_protocol'] = $this->server_ds_data['control_protocol']; } else { $this->server_data['os'] = $this->config->config['local_os']; $this->server_data['control_protocol'] = 'local'; $this->server_data['script_path'] = $this->config->config['local_script_path']; $this->server_data['local_path'] = $this->config->config['local_script_path']; $this->server_data['steamcmd_path'] = $this->config->config['local_steamcmd_path']; $this->server_data['local_server'] = 1; } if (!$no_get_game && $this->server_data['game']) { $where = array('code' => $this->server_data['game']); $this->games->get_games_list($where, 1); $this->server_game_data = $this->games->games_list['0']; $this->server_data['start_code'] = $this->server_game_data['start_code']; $this->server_data['game_name'] = $this->server_game_data['name']; $this->server_data['engine'] = $this->server_game_data['engine']; $this->server_data['engine_version'] = $this->server_game_data['engine_version']; } else { /* Информация об игре не найдена */ } if (!$no_get_gt && $this->server_data['game_type']) { $where = array('id' => $this->server_data['game_type']); $this->game_types->get_gametypes_list($where, 1); $this->server_data['mod_name'] = $this->game_types->game_types_list['0']['name']; $this->server_data['config_files'] = $this->game_types->game_types_list['0']['config_files']; $this->server_data['content_dirs'] = $this->game_types->game_types_list['0']['content_dirs']; $this->server_data['log_dirs'] = $this->game_types->game_types_list['0']['log_dirs']; $this->server_data['fast_rcon'] = $this->game_types->game_types_list['0']['fast_rcon']; $this->server_data['aliases_list'] = $this->game_types->game_types_list['0']['aliases']; $this->server_data['disk_size'] = $this->game_types->game_types_list['0']['disk_size']; if(strtolower($this->server_data['os']) == 'windows') { $execfile_upd = 'steamcmd.exe'; $execfile = $this->game_types->game_types_list['0']['execfile_windows']; } else { $execfile_upd = './steamcmd.sh'; $execfile = $this->game_types->game_types_list['0']['execfile_linux']; /* Добавляем к линуксу ./ в случае необходимости */ if (stripos($execfile, './') === FALSE) { $execfile = './' . $execfile; } } $this->server_data['script_start'] = $execfile . ' ' . $this->game_types->game_types_list['0']['script_start']; $this->server_data['script_stop'] = $execfile . ' ' . $this->game_types->game_types_list['0']['script_stop']; $this->server_data['script_restart'] = $execfile . ' ' . $this->game_types->game_types_list['0']['script_restart']; $this->server_data['script_status'] = $execfile . ' ' . $this->game_types->game_types_list['0']['script_status']; $this->server_data['script_update'] = $execfile_upd . ' ' . $this->game_types->game_types_list['0']['script_update']; $this->server_data['script_get_console'] = $execfile . ' ' . $this->game_types->game_types_list['0']['script_get_console']; $this->server_data['kick_cmd'] = $this->game_types->game_types_list['0']['kick_cmd']; $this->server_data['ban_cmd'] = $this->game_types->game_types_list['0']['ban_cmd']; $this->server_data['chname_cmd'] = $this->game_types->game_types_list['0']['chname_cmd']; $this->server_data['srestart_cmd'] = $this->game_types->game_types_list['0']['srestart_cmd']; $this->server_data['chmap_cmd'] = $this->game_types->game_types_list['0']['chmap_cmd']; $this->server_data['sendmsg_cmd'] = $this->game_types->game_types_list['0']['sendmsg_cmd']; $this->server_data['passwd_cmd'] = $this->game_types->game_types_list['0']['passwd_cmd']; } else { /* Информация о модификации игры не найдена */ } } else { return FALSE; } return $this->server_data; } //----------------------------------------------------------- /** * Получение данных сервера для шаблона * (вырезаны ненужные данные - пароли и пр.) * * */ function tpl_data() { $num = -1; $tpl_data = array(); if (!isset($this->servers_list)) { $this->get_game_servers_list(); } foreach ($this->servers_list as $server_data){ $num++; $tpl_data[$num]['server_id'] = $server_data['id']; $tpl_data[$num]['server_game'] = $server_data['game']; $tpl_data[$num]['server_name'] = $server_data['name']; $tpl_data[$num]['server_ip'] = $server_data['server_ip']; $tpl_data[$num]['server_port'] = $server_data['server_port']; } return $tpl_data; } // ---------------------------------------------------------------- /** * Проверяет, существует ли сервер с данным id * * @return bool */ function server_live($server_id){ if($this->db->count_all_results('servers', array('id' => $server_id)) > 0){ return TRUE; }else{ return FALSE; } } // ---------------------------------------------------------------- /** * Проверяет, существует ли выделенный сервер с данным id * * @return bool */ function ds_server_live($server_id){ if($this->db->count_all_results('dedicated_servers', array('id' => $server_id)) > 0){ return TRUE; }else{ return FALSE; } } // ---------------------------------------------------------------- /** * Проверяет статус сервера * * @return bool */ function server_status($host = FALSE, $port = FALSE, $engine = FALSE, $engine_version = FALSE) { $this->load->driver('query'); if (!$host) { $host = $this->server_data['server_ip']; } if (!$port) { $port = $this->server_data['query_port']; } if (!$engine or !$engine_version) { if (!isset($this->games->games_list)) { $this->load->models('servers/games'); $this->games->get_games_list(); } /* Получение id игры в массиве */ $i = 0; $count = count($this->games->games_list); while($i < $count) { if ($this->server_data['game'] == $this->games->games_list[$i]['code']) { $game_arr_id = $i; break; } $i++; } } if (!$engine) { $engine = $this->games->games_list[$game_arr_id]['engine']; } if (!$engine_version) { $engine_version = $this->games->games_list[$game_arr_id]['engine_version']; } $this->query->set_engine($engine, $engine_version); if ($this->query->get_status($host, $port)) { return TRUE; }else{ return FALSE; } } //----------------------------------------------------------- /** * Получение списка игровых серверов * Функция аналогична get_servers_list за исключением того, что * ей можно задать любое условие, а не только id пользователей, * которым принадлежит игровой сервер. * * */ function get_game_servers_list($where = FALSE, $limit = 10000) { if(is_array($where)){ $query = $this->db->get_where('servers', $where, $limit); }else{ $query = $this->db->get('servers'); } if($query->num_rows > 0){ $this->servers_list = $query->result_array(); return $this->servers_list; }else{ return NULL; } } // ---------------------------------------------------------------- /** * Получает список файлов на локальном сервере * * @param array - данные сервера * @param string - каталог на сервере * @param bool - получать время о последней модификации файла * @param bool - получать размер файла * * @return array - возвращает список файлов с полным путем к файлу * */ function get_local_files($server_data, $dir, $file_time = FALSE, $file_size = FALSE) { if($dir) { $files_list = glob($dir); $num = -1; $files = array(); /* Перебор файлов */ if(!empty($files_list)) { foreach ($files_list as $file) { $num ++; $files[$num]['file_name'] = $file; if(($file_time OR $file_size) && $file_stat = stat($file)) { if($file_time){ $files[$num]['file_time'] = $file_stat['mtime']; } if($file_size){ $files[$num]['file_size'] = $file_stat['size']; } } } } return $files; }else{ return FALSE; } } // ---------------------------------------------------------------- /** * Получает список файлов на удаленном сервере в указанной директории * * @param array - данные сервера * @param string - каталог на сервере * @param bool - получать время о последней модификации файла * @param bool - получать размер файла * * @return array - возвращает список файлов с полным путем к файлу * */ function get_remote_files($server_data, $dir, $file_time = FALSE, $file_size = FALSE) { $connection = ftp_connect($server_data['ftp_host']); if(ftp_login($connection, $server_data['ftp_login'], $server_data['ftp_passwd'])){ $files_list = ftp_nlist($connection, $dir); $num = -1; $maps = array(); /* Перебор файлов, и удаление расширения файла */ if($files_list){ foreach ($files_list as $file) { $num++; $files[$num]['file_name'] = $file; if($file_time){ $files[$num]['file_time'] = ftp_mdtm($connection, $file); } if($file_size){ $files[$num]['file_size'] = ftp_size($connection, $file); } } }else{ return FALSE; } return $files; }else{ return FALSE; } } // ---------------------------------------------------------------- /** * Получает список карт * */ function get_server_maps() { $this->load->helper('path'); $time = time(); /* Получаем список карт из базы (своеобразный кеш)*/ $maps_cache = json_decode($this->server_data['maps_list'], TRUE); /* Если списку не более суток */ if($maps_cache && $maps_cache['time'] > $time - 86400){ unset ($maps_cache['time']); // Удаляем time элемент return $maps_cache; } /* Определение, является сервер локальным или удаленным */ if($this->server_data['local_server']){ // Сервер локальный, получаем данные для него $dir = set_realpath($this->server_data['local_path'] . '/' . $this->server_data['dir'] . '/' . $this->server_data['maps_path']); $files_list = $this->get_local_files($this->server_data, $dir . "*.bsp"); }else{ // Сервер удаленный $dir = set_realpath($this->server_data['ftp_path'] . '/' . $this->server_data['dir'] . '/' . $this->server_data['maps_path']); $files_list = $this->get_remote_files($this->server_data, $dir . "*.bsp", TRUE); } /* Сортировка массива с файлами по возрастанию * * Применена пользовательская сортировка по функции uasort_asc * которая чуть ниже. Сортировка происходит по file_name * в массиве */ if($files_list){ uasort($files_list, array('Servers','uasort_asc')); $num = -1; $maps = array(); /* Перебор карт, и удаление расширения файла */ foreach ($files_list as $file) { $num++; $maps[$num]['map_name'] = str_replace('.bsp', '', basename($file['file_name'])); } /* * Т.к получение карт процесс долгий, а в некоторых случаях * (когда количество карт на сервере очень большое), * то в этом случае список карт лучше отправлять в данные к серверу, * что ниже и происходит. */ $time_array = array('time' => $time); $server_data['maps_list'] = json_encode($maps + $time_array); $this->edit_game_server($this->server_data['id'], $server_data); return $maps; }else{ return NULL; } } // ---------------------------------------------------------------- /** * Сортировка массива по возрастанию */ function uasort_asc($a, $b) { if ($a['file_name'] === $b['file_name']) return 0; return $a['file_name'] > $b['file_name'] ? 1 : -1; } // ---------------------------------------------------------------- /** * Сортировка массива по убыванию */ function uasort_desc($a, $b) { if ($a['file_name'] === $b['file_name']) return 0; return $a['file_name'] < $b['file_name'] ? 1 : -1; } // ---------------------------------------------------------------- /** * Читает содержимое файла с локального сервера * * @param str * @return str */ function read_local_file($file){ if(file_exists($file)) { if(is_readable($file)) { $file_contents = file_get_contents($file); } else { $this->errors = 'Отсутствуют права на чтение файла'; return FALSE; } } else { $this->errors = 'Файл не найден'; return FALSE; } return $file_contents; } // ---------------------------------------------------------------- /** * Читает содержимое файла с удаленного сервера * * @param str * @return str * */ function read_remote_file($file){ $server_data = $this->server_data; $connection = ftp_connect($server_data['ftp_host']); if (ftp_login($connection, $server_data['ftp_login'], $server_data['ftp_passwd'])) { // Определяем временный файл $temp_file = tempnam(sys_get_temp_dir(), basename($file)); $handle = fopen($temp_file, 'r+'); // Производим скачивание файла if (@!ftp_fget($connection, $handle, $file, FTP_ASCII, 0)) { $this->errors = 'Файл не найден'; return FALSE; } $file_contents = file_get_contents($temp_file); fclose($handle); unlink($temp_file); return $file_contents; } else { return FALSE; } } // ---------------------------------------------------------------- /** * Записывает локальный файл * файл должен существовать * * @param str * @return str */ function write_local_file($file, $data = FALSE) { if(!$data) { return FALSE; } if(file_exists($file)) { if(is_writable($file)) { if(file_put_contents($file, $data)) { return TRUE; }else{ $this->errors = 'Неизвестная ошибка'; return FALSE; } } else { $this->errors = 'Отсутствуют права на запись файла'; return FALSE; } } else { $this->errors = 'Файл не найден'; return FALSE; } } // ---------------------------------------------------------------- /** * Загружает файл на удаленный сервер * * @param str * @param str * @return bool * */ function upload_remote_file($file, $remote_file, $mode = 0666){ $server_data = $this->server_data; $connection = ftp_connect($server_data['ftp_host']); if(!$connection) { $this->errors = 'Ошибка соединения с ftp сервером'; return FALSE; } if(ftp_login($connection, $server_data['ftp_login'], $server_data['ftp_passwd'])) { if (!ftp_put($connection, $remote_file, $file, FTP_BINARY)) { $this->errors = 'Ошибка записи файла'; ftp_close($connection); return FALSE; } else { @ftp_chmod($connection, $mode, $remote_file); ftp_close($connection); return TRUE; } } else { $this->errors = 'Ошибка авторизации FTP'; return FALSE; } } // ---------------------------------------------------------------- /** * Записывает данные в удаленный файл * * @param str * @return str * */ function write_remote_file($file, $data){ $server_data = $this->server_data; // Определяем временный файл $temp_file = tempnam(sys_get_temp_dir(), basename($file)); if (file_put_contents($temp_file, $data) === FALSE) { $this->errors = 'Ошибка записи временного файла'; return FALSE; } if($this->upload_remote_file($temp_file, $file)){ return TRUE; }else{ return FALSE; } } // ---------------------------------------------------------------- /** * Смена rcon пароля серверу * * @param str - новый RCON пароль * @pararm arr - * * @return bool */ function change_rcon($new_rcon, $server_data = FALSE) { if($server_data) { $this->server_data = $server_data; } /* Редактируем rcon в server.cfg */ switch (strtolower($this->servers->server_data['engine'])) { case 'goldsource': $servercfg_file = 'server.cfg'; break; case 'source': $servercfg_file = 'cfg/server.cfg'; break; default: return FALSE; break; } /* Получаем содержимое конфигурационного файла */ if(!$this->servers->server_data['ds_id']){ $file_contents = $this->servers->read_local_file($this->servers->server_data['local_path'] . '/' . $this->servers->server_data['dir'] . '/' . $this->servers->server_data['start_code'] . '/' . $servercfg_file ); }else{ $file_contents = $this->servers->read_remote_file($this->servers->server_data['ftp_path'] . '/' . $this->servers->server_data['dir'] . '/' . $this->servers->server_data['start_code'] . '/' . $servercfg_file ); } /* Ошибка чтения, либо файл не найден */ if(!$file_contents) { return FALSE; } $file_strings = explode("\n", $file_contents); $string_found = FALSE; $new_cfg_data = ''; $i = 0; $count_i = count($file_strings); while($i < $count_i) { preg_match('/([\s]*)rcon_password([\s]*)([\"]?)(.*)(\"?)(\\\\?)(.*)/si', $file_strings[$i], $matches); /* Найдены совпадения, поэтому меняем ркон */ if(!empty($matches)){ $file_strings[$i] = 'rcon_password "' . $new_rcon . '"'; $string_found = TRUE; // Строка rcon_password найдена } /* Записываем данные в переменную, которую потом запишем как новый конфиг */ $new_cfg_data .= $file_strings[$i] . "\n"; $i++; } if(!$string_found) { /* Строка rcon_password в конфиге не найдена, * поэтому добавляем ее */ $new_cfg_data .= 'rcon_password "' . $new_rcon . "\"\n"; } /* Записываем содержимое конфигурационного файла */ if(!$this->servers->server_data['ds_id']) { $dir = $this->servers->server_data['local_path'] . '/' . $this->servers->server_data['dir']; $this->servers->write_local_file($this->servers->server_data['local_path'] . '/' . $this->servers->server_data['dir'] . '/' . $this->servers->server_data['start_code'] . '/' . $servercfg_file, $new_cfg_data ); } else { $dir = $this->servers->server_data['ftp_path'] . '/' . $this->servers->server_data['dir']; $this->servers->write_remote_file($this->servers->server_data['ftp_path'] . '/' . $this->servers->server_data['dir'] . '/' . $this->servers->server_data['start_code'] . '/' . $servercfg_file, $new_cfg_data ); } /* Отправляем новый rcon пароль в консоль сервера*/ if($this->servers->server_status($this->server_data['server_ip'], $this->server_data['server_port'])) { $this->load->driver('rcon'); $this->rcon->set_variables( $this->server_data['server_ip'], $this->server_data['server_port'], $this->server_data['rcon'], $this->servers->server_data['engine'], $this->servers->server_data['engine_version'] ); $rcon_connect = $this->rcon->connect(); $this->rcon->command('rcon_password ' . $new_rcon); } $this->server_data['rcon'] = $new_rcon; return TRUE; } // ---------------------------------------------------------------- /** * Получение настроек сервера * * @param int - id сервера * @param int - id пользователя * * @return array */ function get_server_settings($server_id, $user_id = FALSE) { if(!$user_id) { $where = array('server_id' => $server_id); } else { $where = array('server_id' => $server_id, 'user_id' => $user_id); } $query = $this->db->get_where('settings', $where); $server_settings = array(); foreach ($query->result_array() as $settings) { if(array_key_exists($settings['sett_id'], $this->all_settings)) { $server_settings[$settings['sett_id']] = $settings['value']; } } // Заполнение пустых значений foreach ($this->all_settings as $key => $value) { if(!array_key_exists($key, $server_settings)) { $server_settings[$key] = 0; } } $this->server_settings = $server_settings; return $server_settings; } // ---------------------------------------------------------------- /** * Запись настроек * * @return bool */ function set_server_settings($sett_id, $value, $server_id, $user_id = FALSE) { $where = array('sett_id' => $sett_id, 'server_id' => $server_id); if($user_id) { $where['user_id'] = $user_id; } $query = $this->db->get_where('settings', $where); $data = array( 'sett_id' => $sett_id, 'server_id' => $server_id, 'value' => $value ); if($user_id) { $data['user_id'] = $user_id; } $this->db->where('sett_id', $sett_id); $this->db->where('server_id', $server_id); if($query->num_rows > 0){ /* Если привилегия уже есть в базе данных, то обновляем */ if($this->db->update('settings', $data)){ return TRUE; }else{ return FALSE; } }else{ /* Привилегии нет в базе данных, создаем новую строку */ if($this->db->insert('settings', $data)){ return TRUE; }else{ return FALSE; } } } }