From c9870f840ecc86d06df78cc1953283cdade05977 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Fri, 24 Jul 2015 11:26:11 +0400 Subject: [PATCH] Add. Support windows services. --- app/services/resources/classes/lib_win.php | 227 +++++++++++++++++++++ app/services/service_edit.php | 6 + app/services/services.php | 116 ++++++++--- 3 files changed, 318 insertions(+), 31 deletions(-) create mode 100644 app/services/resources/classes/lib_win.php diff --git a/app/services/resources/classes/lib_win.php b/app/services/resources/classes/lib_win.php new file mode 100644 index 0000000000..6368893376 --- /dev/null +++ b/app/services/resources/classes/lib_win.php @@ -0,0 +1,227 @@ +'CONTINUE_PENDING', + WIN32_SERVICE_PAUSE_PENDING =>'PAUSE_PENDING', + WIN32_SERVICE_PAUSED =>'PAUSED', + WIN32_SERVICE_RUNNING =>'RUNNING', + WIN32_SERVICE_START_PENDING =>'START_PENDING', + WIN32_SERVICE_STOP_PENDING =>'STOP_PENDING', + WIN32_SERVICE_STOPPED =>'STOPPED', + ); + + private static $win_error = array( + WIN32_NO_ERROR => 'NO_ERROR', + WIN32_ERROR_ACCESS_DENIED => 'ACCESS_DENIED', + WIN32_ERROR_CIRCULAR_DEPENDENCY => 'CIRCULAR_DEPENDENCY', + WIN32_ERROR_DATABASE_DOES_NOT_EXIST => 'DATABASE_DOES_NOT_EXIST', + WIN32_ERROR_DEPENDENT_SERVICES_RUNNING => 'DEPENDENT_SERVICES_RUNNING', + WIN32_ERROR_DUPLICATE_SERVICE_NAME => 'DUPLICATE_SERVICE_NAME', + WIN32_ERROR_FAILED_SERVICE_CONTROLLER_CONNECT => 'FAILED_SERVICE_CONTROLLER_CONNECT', + WIN32_ERROR_INSUFFICIENT_BUFFER => 'INSUFFICIENT_BUFFER', + WIN32_ERROR_INVALID_DATA => 'INVALID_DATA', + WIN32_ERROR_INVALID_HANDLE => 'INVALID_HANDLE', + WIN32_ERROR_INVALID_LEVEL => 'INVALID_LEVEL', + WIN32_ERROR_INVALID_NAME => 'INVALID_NAME', + WIN32_ERROR_INVALID_PARAMETER => 'INVALID_PARAMETER', + WIN32_ERROR_INVALID_SERVICE_ACCOUNT => 'INVALID_SERVICE_ACCOUNT', + WIN32_ERROR_INVALID_SERVICE_CONTROL => 'INVALID_SERVICE_CONTROL', + WIN32_ERROR_PATH_NOT_FOUND => 'PATH_NOT_FOUND', + WIN32_ERROR_SERVICE_ALREADY_RUNNING => 'SERVICE_ALREADY_RUNNING', + WIN32_ERROR_SERVICE_CANNOT_ACCEPT_CTRL => 'SERVICE_CANNOT_ACCEPT_CTRL', + WIN32_ERROR_SERVICE_DATABASE_LOCKED => 'SERVICE_DATABASE_LOCKED', + WIN32_ERROR_SERVICE_DEPENDENCY_DELETED => 'SERVICE_DEPENDENCY_DELETED', + WIN32_ERROR_SERVICE_DEPENDENCY_FAIL => 'SERVICE_DEPENDENCY_FAIL', + WIN32_ERROR_SERVICE_DISABLED => 'SERVICE_DISABLED', + WIN32_ERROR_SERVICE_DOES_NOT_EXIST => 'SERVICE_DOES_NOT_EXIST', + WIN32_ERROR_SERVICE_EXISTS => 'SERVICE_EXISTS', + WIN32_ERROR_SERVICE_LOGON_FAILED => 'SERVICE_LOGON_FAILED', + WIN32_ERROR_SERVICE_MARKED_FOR_DELETE => 'SERVICE_MARKED_FOR_DELETE', + WIN32_ERROR_SERVICE_NO_THREAD => 'SERVICE_NO_THREAD', + WIN32_ERROR_SERVICE_NOT_ACTIVE => 'SERVICE_NOT_ACTIVE', + WIN32_ERROR_SERVICE_REQUEST_TIMEOUT => 'SERVICE_REQUEST_TIMEOUT', + WIN32_ERROR_SHUTDOWN_IN_PROGRESS => 'SHUTDOWN_IN_PROGRESS' + ); + + private static function val2val($val,$map,$default){ + if(isset($map[$val])) return $map[$val]; + return $default; + } + + var $status; + var $last_error; + var $name; + var $description; + var $machine; + + function win_service($srvname, $machine=null){ + $this->name = $srvname; + $this->machine = $machine; + $this->status = null; + $this->last_error = WIN32_NO_ERROR; + } + + function refresh_status(){ + $status = win32_query_service_status($this->name,$this->machine); + if(is_array($status)){ + $this->status = (object)$status; + $this->last_error = WIN32_NO_ERROR; + return true; + } + $this->status = null; + $last_error = $status; + return false; + } + + function start(){ + $this->last_error = win32_start_service($this->name, $this->machine); + return ($this->last_error === WIN32_NO_ERROR) or ($this->last_error === WIN32_ERROR_SERVICE_ALREADY_RUNNING); + } + + function stop(){ + $this->last_error = win32_stop_service($this->name, $this->machine); + return $this->last_error === WIN32_NO_ERROR; + } + + function last_error($as_string = true){ + if($as_string){ + return self::val2val( + $this->last_error, self::$win_error, $this->last_error + ); + } + return $this->last_error; + } + + function state($as_string = true){ + if((!$this->status)and(!$this->refresh_status())) return false; + if($as_string){ + return self::val2val( + $this->status->CurrentState, self::$service_state, 'UNKNOWN' + ); + } + return $this->status->CurrentState; + } + + function pid(){ + if((!$this->status)and(!$this->refresh_status())) return false; + return $this->status->ProcessId; + } + + } + +} + +if(function_exists('reg_open_key')){ + + class win_reg_key{ + + private static $HK = array( + HKEY_CLASSES_ROOT => "HKCR", + HKEY_CURRENT_USER => "HKCU", + HKEY_LOCAL_MACHINE => "HKLM", + HKEY_USERS => "HKU", + HKEY_CURRENT_CONFIG => "HKCC", + ); + + function __construct($haiv, $key){ + $this->h = $haiv; + $this->k = $key; + $this->r = reg_open_key($this->h, $this->k); + $this->shell = new COM('WScript.Shell'); + if(!$this->shell){ + throw new Exception("Cannot create shell object."); + } + if(!$this->r){ + throw new Exception("Cannot access registry."); + } + $this->path = self::$HK[$this->h] . '\\' . $this->k; + } + + function __destruct(){ + if($this->r){ + reg_close_key($this->r); + $this->r = false; + } + } + + function keys(){ + return reg_enum_key($this->r); + } + + function values($as_hash = false){ + $values = reg_enum_value($this->r); + if(!$as_hash) return $values; + $result = Array(); + foreach($values as $key){ + $result[$key] = reg_get_value($this->r, $key); + } + return $result; + } + + function value($key){ + return reg_get_value($this->r, $key); + } + + function exists($key){ + $v = $this->value($key); + if($v === NULL) return false; + if($v === false) return false; + return true; + } + + private function write_raw($key, $type, $value){ + return reg_set_value($this->r, $key, $type, $value); + } + + function write_dword($key, $value){ + return $this->write_raw($key, REG_DWORD, $value); + } + + function write_string($key, $value){ + return $this->write_raw($key, REG_SZ, $value); + } + + function remove_value($key){ + if(!$this->exists($key)) return; + $key = $this->path . '\\' . $key; + $this->shell->RegDelete($key); + } + + } + +} diff --git a/app/services/service_edit.php b/app/services/service_edit.php index cb64aaac3a..aaaf09c584 100644 --- a/app/services/service_edit.php +++ b/app/services/service_edit.php @@ -221,6 +221,12 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { else { echo " \n"; } + if ($service_type == "svc") { + echo " \n"; + } + else { + echo " \n"; + } echo " \n"; echo "
\n"; echo $text['description-type']."\n"; diff --git a/app/services/services.php b/app/services/services.php index 9a1799550c..dc970bf43e 100644 --- a/app/services/services.php +++ b/app/services/services.php @@ -34,6 +34,18 @@ else { exit; } +global $IS_WINDOWS; + +if ($IS_WINDOWS == null) { + if (stristr(PHP_OS, 'WIN')) { $IS_WINDOWS = true; } else { $IS_WINDOWS = false; } +} + +$HAS_WIN_SVC = false; +if($IS_WINDOWS){ + require_once "resources/classes/lib_win.php"; + $HAS_WIN_SVC = class_exists('win_service'); +} + //add multi-lingual support $language = new text; $text = $language->get(); @@ -63,13 +75,28 @@ if (strlen($_GET["a"]) > 0) { } unset ($prep_statement); - if ($_GET["a"] == "stop") { - $_SESSION["message"] = $text['message-stopping'].': '.$service_name; - shell_exec($service_cmd_stop); + if($service_type == 'svc'){ + if($HAS_WIN_SVC){ + $svc = new win_service($service_data); + if ($_GET["a"] == "stop") { + $_SESSION["message"] = $text['message-stopping'].': '.$service_name; + $svc->stop(); + } + if ($_GET["a"] == "start") { + $_SESSION["message"] = $text['message-starting'].': '.$service_name; + $svc->start(); + } + } } - if ($_GET["a"] == "start") { - $_SESSION["message"] = $text['message-starting'].': '.$service_name; - shell_exec($service_cmd_start); + else { + if ($_GET["a"] == "stop") { + $_SESSION["message"] = $text['message-stopping'].': '.$service_name; + shell_exec($service_cmd_stop); + } + if ($_GET["a"] == "start") { + $_SESSION["message"] = $text['message-starting'].': '.$service_name; + shell_exec($service_cmd_start); + } } header("Location: services.php"); return; @@ -152,42 +179,69 @@ if (strlen($_GET["a"]) > 0) { } echo " \n"; echo " \n"; - if ($row[service_type] == "pid" || $row[service_type] == "pid_file") { - $pid = file_get_contents($row[service_data]); - if (is_process_running($pid)) { + $service_running = false; + + if ($row[service_type] == "svc") { + if ($HAS_WIN_SVC) { + $service_data = $row[service_data]; + $svc = new win_service($service_data); + $svc_state = $svc->state() or $svc->last_error(); + if(!$svc_state){ + $svc_state = 'NOT_INSTALL'; + } + $service_running = (($svc_state == 'RUNNING') || ($svc_state == 'START_PENDING')); + + echo "$svc_state"; + + echo "\n"; + echo " \n"; + if ($svc_state == 'NOT_INSTALL') { + echo "$svc_state"; + } + else { + if ($service_running) { + echo " ".$text['label-stop'].""; + } + else { + echo " ".$text['label-start'].""; + } + } + } + else{ + echo "UNSUPPORT"; + echo "\n"; + echo " \n"; + echo "UNSUPPORT"; + } + } + else { + if ($row[service_type] == "pid" || $row[service_type] == "pid_file") { + $pid = file_get_contents($row[service_data]); + $service_running = is_process_running($pid); + } + if ($row[service_type] == "file") { + $service_data = $row[service_data]; + $service_running = file_exists($service_data); + } + + if ($service_running) { echo "".$text['label-running'].""; } else { echo "".$text['label-stopped'].""; } - } - if ($row[service_type] == "file") { - $service_data = $row[service_data]; - if (file_exists($service_data)) { - echo "".$text['label-running'].""; - } - else { - echo "".$text['label-stopped'].""; - } - } - echo "\n"; - echo " \n"; - if ($row[service_type] == "pid" || $row[service_type] == "pid_file") { - if (is_process_running($pid)) { - echo " ".$text['label-stop'].""; - } - else { - echo " ".$text['label-start'].""; - } - } - if ($row[service_type] == "file") { - if (file_exists($service_data)) { + + echo "\n"; + echo " \n"; + if ($service_running) { echo " ".$text['label-stop'].""; } else { echo " ".$text['label-start'].""; } } + + echo "\n"; echo " ".$row[service_description]." \n"; echo " ";