【原创】博主分享自用的基于PHP的驻留服务管理脚本webservice.php--改进版V3

blogdaren 2015-05-29 抢沙发 2628人次
效果图在文末哈
================================================================================

     全站服务管理脚本使用说明

     (1). 首先需要根据实际环境对 /path/to/webservice/config.php 脚本进行配置, 请参考 Config::getServiceConfig() 方法

     (2). 调用方法:/path/to/php /path/to/webservice.php [--help|--check|--force-reboot-all|...] [>> /tmp/webservice.log &]

     (3). 参数说明:
        --help                    打印脚本使用说明
        --check                   检测服务运行情况
        --check-server-name       检测 server-name 服务运行情况
        --human                   启用交互模式操作服务
        --human-server-name       启用交互模式检测 server-name 服务运行情况
        --start-server-name       启动 server-name 服务
        --stop-server-name        停止 server-name 服务
        --reboot-server-name      重启 server-name 服务
        --force-reboot-all        强制重启所有服务 
        --force-stop-all          强制停止所有服务 

     (4). 每一个服务进程都有对应的运行日志记录, 存放路径请参考 LOG_PATH 定义段

     (5). 可用的服务列表【取决于配置服务】: 

       【项目名称】      【服务名称】
        blogdaren          default-test-blogdaren1
        blogdaren          default-test-blogdaren2  
=================================================================================

第1步贴出服务脚本的源代码: webservice.php

#!/usr/bin/env php

<?php
/**
 * @file webservice.php
 * 
 * 网站服务管理脚本说明
 *
 * 1. 首先需要根据实际环境对脚本进行配置,请参考 config.php 文件的 Config::getServiceConfig() 方法
 * 2. 调用方法: /path/to/php /path/to/webservice/webservice.php [--help|--force-reboot-all|--force-stop-all] [>> /tmp/webservice.log &]
 * 
 * @author lgh_2002@163.com
 * @version v3(修正)
 * @date 2014-11-04
 */

class websiteService
{ 
    /**
     *  单例模式
     *  @string public
     */
    static public $_instance = NULL;

    /**
     *  参数命令
     *  @string public
     */
    public $command = "";

    /**
     *  脚本运行环境:dev|branches|trunk
     *  @access protected
     */
    protected $_env = "";

    /**
     *  脚本执行绝对路径
     *  @access protected
     */
    protected $_script_path = "";

    /**
     *  服务进程标识符
     *  @access protected
     */
    protected $_service_process = "";

    /**
     *  应用名称
     *  @access protected
     */
    protected $_app_name = "blogdaren";

    /**
     *  是否显示签名
     *  @access public  
     */
    public $show_signature = true;

    /**
     *  某个服务
     *  @access protected
     */
    public $one_service = '';

    /**
     * 构造函数  
     *
     * @return  
     */
    public function __construct($command = "", $show_signature = true)
    {
        $this->command = $command;
        $this->show_signature = $show_signature;
    }

    /**
     * 析构函数 
     *
     * @return
     */
    public function __destruct()
    {
        $this->command = '';
    }

    /**
     * 脚本运行入口 
     *
     * @return null 
     */
    public function execute()
    {
        //签名
        if($this->show_signature) self::showSignature();

        //命令使用帮助
        if(empty($this->command) || "--help" === $this->command) $this->showHelp();

        $now_time = self::getNowTime();
        $msg = $now_time . "\033[33m脚本运行开始......\033[33m";
        $this->showMsg($msg);

        //校验执行锁: 对于写操作-脚本本身必须以单例模式运行
        if("--check" != $this->command)
        {
            $lock_exist = $this->isLockExist();

            if($lock_exist)
            {
                $msg = "检测到有【webservice.php】进程在运行, 请核实...拒绝服务...";
                $this->showMsg($msg, false, true); 
            }
        }

        //创建必须的日志目录
        try{
            if(!file_exists(LOG_PATH) || !is_dir(LOG_PATH)) self::createMultiDirectory(LOG_PATH);
        }catch(Exception $e){
            $msg ='日志目录' . LOG_PATH . "不可写,请提供可写的日志目录!!!";
            $this->showMsg($msg, false, true);
        }

        $config = $this->washConfig();
        if(empty($config) || !is_array($config))
        {
            $msg = "检测到异常:无效操作,配置文件内容无效或提供的命令参数无效";
            $this->showMsg($msg, false, true); 
        }

        foreach($config as $app => $data)
        {
            $now_time = self::getNowTime();
            $msg = $now_time . "\033[33m开始检测项目【" . $app . "】上的服务......\033[33m";
            $this->showMsg($msg);
            $this->_app_name = $app;
            sleep(1);

            foreach($data as $k => $arg)
            {
                $index = $k + 1;
                $now_time = self::getNowTime();

                if(empty($arg['env']))
                {
                    $this->_env = "";
                    $cn_env = "【默认】环境";
                }
                else
                {
                    $this->_env = $arg['env'];
                    $cn_env = "【" . $arg['env'] . "】环境";
                }

                $this->_script_path = $arg['path'];
                $this->_service_process = trim($arg['process']);
                $msg = $now_time . "\033[33m正在检测" . $cn_env . "第(" . $index . ")项服务:【" . $this->_service_process . "】\033[33m";
                $this->showMsg($msg, true);

                if(!is_file($this->_script_path) || !file_exists($this->_script_path))
                {
                    $tmp_script_path = empty($this->_script_path) ? '' : "【" . $this->_script_path . "】";
                    $msg = $now_time . "\033[33m检测结果: 所需脚本文件" . $tmp_script_path. "不存在\033[33m";
                    $this->showMsg($msg, true);
                    continue;
                }

                //检测服务进程
                $pids = $this->_checkService();

                //是否有强制行为
                if(in_array($this->command, array('--force-reboot-all', '--force-stop-all')))
                {
                    '--force-stop-all' === $this->command && $action = 2;
                    '--force-reboot-all' === $this->command && $action = 3;
                }
                else
                {
                    $now_time = self::getNowTime();

                    if(empty($pids)) {
                        $msg = $now_time . "\033[33m检测结果:服务没有启动:【" . $this->_service_process. "】\033[33m";
                    } else {
                        $msg = $now_time . "\033[33m检测结果: 服务正常【" . $this->_service_process . "】\033[33m";
                    }

                    $this->showMsg($msg, true);

                    if('--check' === $this->command)
                    {
                        continue;
                    }

                    if(false !== strpos($this->command, "--human"))
                    {
                        echo "\r\n" . SPACE . "确定要继续操作吗? 【y|n】";

                        $op = trim($this->confirm());

                        //如果拒绝继续操作,则校验下一个服务
                        if('y' != $op) 
                        {
                            echo "\r\n";
                            continue;
                        }

                        echo "\r\n" . SPACE . "请选择操作行为:【1/2/3/4】\r\n\r\n";
                        $action = trim($this->selectAction()->confirm());
                    }
                    else
                    {
                        $action = $this->getAction();
                    }
                }

                switch($action)
                {
                    case 1:
                        //正常启动
                        $now_time = self::getNowTime();
                        $pid = $this->startService();
                        $msg = "启动服务失败:【" . $this->_service_process . "】, 跳过操作......";
                        $pid && $msg = "已成功启动服务:【" . $this->_service_process. "】-【" . $pid . "】";
                        $this->showMsg($msg, true);
                        break;
                    case 2:
                        //停止
                        $this->stopMultiService();
                        break;
                    case 3:
                        //重启
                        $this->stopMultiService();
                        $msg = "准备重新启动服务:【" . $this->_service_process. "】";
                        $pid = $this->showMsg($msg, true)->startService();
                        $msg = "重新启动服务失败:【" . $this->_service_process. "】";
                        $pid && $msg = "重新启动服务成功:【" . $this->_service_process. "】-【" . $pid . "】";
                        $this->showMsg($msg, true);
                        break;
                    case 4:
                        //退出
                        $msg = "退出行为,跳过操作......";
                        $this->showMsg($msg, true);
                        break;
                    default:
                        //默认
                        $msg = "无效操作,跳过操作......";
                        $this->showMsg($msg, true);
                        break;
                }

                //休眠2秒
                $sleep_time = 2;
                $msg = "系统正在休眠,请等待{$sleep_time}秒......";
                $this->showMsg($msg, true);
                sleep($sleep_time);
                echo "\r\n";
            }
        }

        $now_time = self::getNowTime();
        $msg = $now_time . "\033[33m脚本运行结束, 安全退出......\033[33m";
        $this->showMsg($msg, false, true);
    }

    /**
     * 获取命令行为
     *
     * @return int
     */
    public function getAction()
    {
        if(false !== strpos ($this->command, "start")){
            $action = 1;
        }else if(false !== strpos ($this->command, "stop")){
            $action = 2;
        }else if(false !== strpos ($this->command, "reboot")){
            $action = 3;
        }else{
            $action = 0;
        }

        return $action;
    }

    /**
     * 启动服务 
     *
     * @return int 
     */
    public function startService()
    {
        $output = $this->_checkService();

        if(empty($output) || !is_array($output)) 
        {
            $cmd = "nohup " . PHP_BIN . " $this->_script_path  $this->_service_process >> " . LOG_PATH . "{$this->_service_process}.log 2>&1 & ";
            exec($cmd);

            $output = $this->_checkService();
        }

        $pid = empty($output) ? 0 : (int)trim($output[0]);

        return $pid;
    }

    /**
     * 停止服务 
     *
     * @return bool 
     */
    public function stopService($pid)
    {
        if($pid <= 0) return false;

        $cmd = "kill -9 {$pid} > /dev/null &";

        exec($cmd, $output, $status);

        if(0 === $status) return true;

        return false;
    }

    /**
     * 停止多个服务 
     *
     * @return mixed 
     */
    public function stopMultiService()
    {
        $pids = $this->_checkService();

        if(empty($pids) || !is_array($pids))
        {
            $msg = "停止服务失败,检测到服务没有启动:【" . $this->_service_process. "】";
            $this->showMsg($msg, true);
            return false;
        }

        foreach($pids as $k => $pid)
        {
            $msg = "当前进程操作无效:【" . $this->_service_process. "】" . "-" . "【" . $pid. "】";
            $rs = $this->stopService($pid);

            if($rs)
            {
                $msg = "当前进程已杀死:【" . $this->_service_process. "】" . "-" . "【" . $pid. "】";
            }

            $this->showMsg($msg, true);
        }
    }

    /**
     * 检测服务进程: 返回进程ID集合
     *
     * @return array 
     */
    protected function _checkService()
    {
        //注意!!!:防止进程没有及时退出,这里必须休眠一会儿
        sleep(2);

        $enviroment = empty($this->_env) ? "" : "| grep " . $this->_env;
        $cmd = "ps aux | grep " . $this->_app_name . "| grep " . $this->_service_process . $enviroment . "| grep -v grep | awk '{print $2}'";

        /*
         *$msg = "执行命令如下:" . $cmd;
         *$this->showMsg($msg);
         */

        exec($cmd, $pids);

        return $pids;
    }

    /**
     * 消息弹窗
     *
     * @param  int  $msg
     * @param  int  $indent
     * @param  int  $exit
     *
     * @return mixed
     */
    public function showMsg($msg, $indent = false, $exit = false)
    {
        empty($msg) && $msg = "unknow msg....";
        !is_string($msg) && $msg = json_encode($msg);
        $indent_content = "";
        $indent && $indent_content = SPACE;
        $sign = str_repeat("-", 110);
        echo START_COLOR . $indent_content . $sign . END_COLOR;
        echo START_COLOR . $indent_content . $msg . END_COLOR;

        if($exit) 
        {
            echo START_COLOR . $indent_content . $sign . END_COLOR;
            exit;
        }

        return $this;
    }

    /**
     * 消息确认: 流 
     *
     * @return string  
     */
    public function confirm()
    {
        $fp = fopen('php://stdin', 'r');
        $input = fgets($fp, 255);
        fclose($fp);

        return $input;
    }

    /**
     * 操作行为分支 
     *
     * @return  object 
     */
    public function selectAction()
    {
        $a = "start";
        $b = "stop";
        $c = "reboot";
        $d = "exit";

        echo START_COLOR . SPACE . "==================================================" . END_COLOR;
        echo START_COLOR . SPACE . "(1) $a" . END_COLOR;
        echo START_COLOR . SPACE . "(2) $b" . END_COLOR;
        echo START_COLOR . SPACE . "(3) $c" . END_COLOR;
        echo START_COLOR . SPACE . "(4) $d" . END_COLOR;
        echo START_COLOR . SPACE . "==================================================" . END_COLOR;
        echo "\r\n";

        return $this;
    }

    /**
     * 获取当前系统时间 
     *
     * @return string
     */
    public function getNowTime()
    {
        $now_time = date("Y-m-d H:i:s");
        $now_time = "\033[33m【" . $now_time . "】\033[33m";

        return $now_time;
    }

    /**
     * 单进程执行锁
     *
     * @return bool
     */
    public function isLockExist()
    {
        $cmd = "ps aux | grep -i 'webservice.php' | grep -v grep | grep -v vim | wc -l";
        exec($cmd, $result);

        //运行锁
        if(!empty($result) && $result[0] > 1)
        {
            return true;
        }

        return false;
    }


    /**  
     * 创建多级目录
     *
     * @param  string  $dir 层级目录: a/b/c
     * @param  string  $mode 权限
     *
     * @return boolean
     */
    static public function createMultiDirectory($dir, $mode = 0777)
    {    
        if(is_dir($dir))
        {    
            return true;
        }    

        if(!self::createMultiDirectory(dirname($dir), $mode))
        {    
            return false;
        }    

        return mkdir($dir, $mode);
    }

    /**
     * 脚本使用帮助信息
     *
     * @return exit
     */
    public function showHelp()
    {
        $config = Config::getServiceConfig();

        $head = SERVICE_SPACE . "【项目名称】      【服务名称】\r\n";
        $service_list = SERVICE_SPACE;
        foreach($config as $app => $v)
        {
            foreach($v as $k1 => $v1)
            {
                $service_list .= " {$app}" . SERVICE_SPACE . $v1['process'] . "\r\n" . SERVICE_SPACE;
            }
        }
        $service_list = $head . $service_list;

        $self_script = $_SERVER['PHP_SELF'];
        $sign = str_repeat("=", 136) . "\r\n";
        echo $sign;
        echo "\r\n";
        echo "     全站服务管理脚本使用说明\r\n";
        echo "\r\n";
        echo "     1. 首先请根据实际环境对 /path/to/webservice/config.php 脚本进行配置, 请参考 Config::getServiceConfig() 方法\r\n";
        echo "\r\n";
        echo "     2. 调用方法:/path/to/php /path/to/" . $self_script . " [--help|--check|--force-reboot-all|--force-stop-all] [>> /tmp/webservice.log &]\r\n";
        echo "\r\n";
        echo "     3. 每一个服务进程都有对应的运行日志记录, 存放路径请参考 LOG_PATH 定义段 \r\n";
        echo "\r\n";
        echo "     4. 参数说明:\r\n";
        echo "\r\n";
        echo "        --help                    打印脚本使用说明\r\n";
        echo "        --check                   检测所有配合服务运行情况 \r\n";
        echo "        --check-server-name       检测 server-name 服务运行情况 \r\n";
        echo "        --human                   启用交互模式操作服务\r\n";
        echo "        --human-server-name       启用交互模式操作 server-name 服务\r\n";
        echo "        --start-server-name       启动 server-name 服务\r\n";
        echo "        --stop-server-name        停止 server-name 服务\r\n";
        echo "        --reboot-server-name      启动 server-name 服务\r\n";
        echo "        --force-reboot-all        强制重启所有服务 \r\n";
        echo "        --force-stop-all          强制停止所有服务 \r\n";
        echo "\r\n";
        echo "     5. 可用的服务列表: \r\n";
        echo "\r\n";
        echo $service_list;
        echo "\r\n";
        echo $sign;
        echo "\r\n";
        exit;
    }

    /**
     * 签名 
     *
     * @return string
     */
    static public function showSignature()
    {
        $timer = 0;
        $data = '';
        $total = 48;
        while($timer <= $total)
        {
            $data = $timer == $total/2 ? "全站服务管理【http://www.blogdaren.com】" : "▆";
            echo $data;
            usleep(10000);
            $timer++;
        }
        echo "\r\n";
    }

    /**
     * 清洗配置文件
     *
     * @return  
     */
    public function washConfig()
    {
        $config = array();

        //读取配置文件
        $_config = Config::getServiceConfig();

        if(in_array($this->command, array('--force-reboot-all', '--force-stop-all', '--check', '--human')))
        {
            return $_config;
        }

        //重新清洗配置文件
        $pos = strpos($this->command, "-", 2);
        $command = substr($this->command, $pos+1);
        foreach($_config as $k => $v)
        {
            foreach($v as $k1 => $v1)
            {
                if($command == $v1['process'])
                {
                    $config[$k][$k1] = $v1;
                }
            }
        }

        return $config;
    }

    /**
     * 获取单例
     *
     * @return object 
     */
    static public function getInstance($command = '', $show_signature = true)
    {
        if(!self::$_instance instanceof self)
        {
            self::$_instance = new self($command, $show_signature);
        }

        return self::$_instance;
    }  }  

//加载配置文件
if(!file_exists(dirname(__FILE__) . "/config.php")) exit("配置文件加载失败......, 不存在?请检查下!!!\n\n");
require(dirname(__FILE__) . "/config.php");

//开始执行脚本
$command = isset($argv[1]) ? $argv[1] : "";
websiteService::getInstance($command, SHOW_SIGNATURE)->execute(); 
==========================华丽的分隔线=============================

第2步贴出配置脚本的源代码: config.php

<?php
/**
 * @file config.php
 * 
 * @author lgh_2002@163.com
 * @version v3
 * @date 2014-11-04
 */
PHP_SAPI == 'cli' or die('拒绝访问!!');
set_time_limit(0);
ignore_user_abort(true);
date_default_timezone_set('Asia/Shanghai');

define("WEBSERVICE_ROOT_PATH", dirname(__FILE__));
define("START_COLOR", "\033[32m");
define("END_COLOR", "\033[0m\r\n");
define("SPACE", "                  ");
define("SERVICE_SPACE", "         ");
define("PHP_BIN", "/usr/bin/php ");
!defined("SHOW_SIGNATURE") && define("SHOW_SIGNATURE", true);
!defined("LOG_PATH") && define("LOG_PATH", "/tmp/websiteService/");

class Config
{
    /**
     *  获取配置信息 
     *
     * @return array 
     */
    static public function getServiceConfig()
    {
        //注意:脚本路径一定要配置正确
        $path = array(
            "p1" => "/path/to/sbin/cli.php",
        );

        //暂定10个脚本路径
        $number = range(1, 10);
        foreach($number as $k => $v)
        {
            $key = "p" . $v;
            empty($path[$key]) && $path[$key] = '';
        }

        $config = array(
            'blogdaren' => array(
                array(
                    "env"   => "",
                    "path"  => $path['p1'],
                    "process" => "default-test-blogdaren1",
                ),
                array(
                    "env"   => "",
                    "path"  => $path['p1'],
                    "process" => "default-test-blogdaren2",
                ),
            ),

            'blogdaren2' => array(
                array(
                    "env"   => "dev",
                    "path"  => $path['p2'],
                    "process" => "default-test-blogdaren3",
                ),
                array(
                    "env"   => "dev",
                    "path"  => $path['p2'],
                    "process" => "default-test-blogdaren4",
                ),
            ),
        );

        return $config;
    }
} 


==========================华丽的分隔线=============================

1.jpg



5.jpg


4.jpg


3.jpg


2.jpg





#php服务管理脚本#

版权声明:除非注明,本文由( blogdaren )原创,转载请保留文章出处。

本文链接:【原创】博主分享自用的基于PHP的驻留服务管理脚本webservice.php--改进版V3

发表评论:

您的昵称:
电子邮件:
个人主页:

Free Web Hosting