Windows 上界面美观的 PHP 集成环境软件

界面展示一下:

clipboard.png

源码:SalamanderWnmp
集成包下载 http://ongd1spyv.bkt.clouddn.com/Salamande...
喜欢的童鞋star一个哦

原因

平常工作中用Nginx比较多,网上虽然也有wnmp集成环境,但是感觉界面不好看,用起来不舒服,所有决定自己做一个吧。

原料

软件用的是C#,GUI框架是WPF(这个做出来更好看一点),先去官网下载PHP,用的是NTS版本的(因为这里PHP是以CGi的形式跑的),再去下载Windows版的NginxMysql

代码

基类

public class WnmpProgram: INotifyPropertyChanged
    {
        public TextBlock statusLabel { get; set; } // Label that shows the programs status
        public string exeName { get; set; }    // Location of the executable file
        public string procName { get; set; }   // Name of the process
        public string progName { get; set; }   // User-friendly name of the program 
        public string workingDir { get; set; }   // working directory
        public Log.LogSection progLogSection { get; set; } // LogSection of the program
        public string startArgs { get; set; }  // Start Arguments
        public string stopArgs { get; set; }   // Stop Arguments if KillStop is false
        public bool killStop { get; set; }     // Kill process instead of stopping it gracefully
        public string confDir { get; set; }    // Directory where all the programs configuration files are
        public string logDir { get; set; }     // Directory where all the programs log files are
        public Ini Settings { get; set; }
        //public ContextMenuStrip configContextMenu { get; set; } // Displays all the programs config files in |confDir|
        //public ContextMenuStrip logContextMenu { get; set; }    // Displays all the programs log files in |logDir|

        public Process ps = new Process();

        public event PropertyChangedEventHandler PropertyChanged;
        // 是否在运行
        private bool running = false;

        public bool Running
        {
            get
            {
                return this.running;
            }
            set
            {
                this.running = value;
                if(PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Running"));
                }
            }
        }

        public WnmpProgram()
        {
            //configContextMenu = new ContextMenuStrip();
            //logContextMenu = new ContextMenuStrip();
            //configContextMenu.ItemClicked += configContextMenu_ItemClicked;
            //logContextMenu.ItemClicked += logContextMenu_ItemClicked;
        }

        /// <summary>
        /// 设置状态
        /// </summary>
        public void SetStatus()
        {
            if (this.IsRunning() == true)
            {
                this.Running = true;
            }
            else
            {
                this.Running = false;
            }

        }

        public void StartProcess(string exe, string args, bool wait = false)
        {
            ps.StartInfo.FileName = exe;
            ps.StartInfo.Arguments = args;
            ps.StartInfo.UseShellExecute = false;
            ps.StartInfo.RedirectStandardOutput = true;
            ps.StartInfo.WorkingDirectory = workingDir;
            ps.StartInfo.CreateNoWindow = true;
            ps.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            ps.Start();

            if (wait) {
                ps.WaitForExit();
            }
        }
        public virtual void Start()
        {
            if(IsRunning())
            {
                return;
            }
            try {
                StartProcess(exeName, startArgs);
                Log.wnmp_log_notice("Started " + progName, progLogSection);
            } catch (Exception ex) {
                Log.wnmp_log_error("Start(): " + ex.Message, progLogSection);
            }
        }

        public virtual void Stop()
        {
            if(!IsRunning())
            {
                return;
            }
            if (killStop == false)
                StartProcess(exeName, stopArgs, true);
            var processes = Process.GetProcessesByName(procName);
            foreach (var process in processes) {
                    process.Kill();
            }
            Log.wnmp_log_notice("Stopped " + progName, progLogSection);
        }

        public void Restart()
        {
            this.Stop();
            this.Start();
            Log.wnmp_log_notice("Restarted " + progName, progLogSection);
        }

        //public void ConfigButton(object sender)
        //{
        //    var btnSender = (Button)sender;
        //    var ptLowerLeft = new Point(0, btnSender.Height);
        //    ptLowerLeft = btnSender.PointToScreen(ptLowerLeft);
        //    configContextMenu.Show(ptLowerLeft);
        //}

        //private void logContextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        //{
        //    try {
        //        Process.Start(Settings.Editor.Value, frmMain.StartupPath + logDir + e.ClickedItem.Text);
        //    } catch (Exception ex) {
        //        Log.wnmp_log_error(ex.Message, progLogSection);
        //    }
        //}

        public bool IsRunning()
        {
            var processes = Process.GetProcessesByName(procName);

            return (processes.Length != 0);
        }
    }

开启mysql代码:

class MysqlProgram : WnmpProgram
    {
        private readonly ServiceController MysqlController = new ServiceController();
        public const string ServiceName = "mysql-salamander";

        public MysqlProgram()
        {
            MysqlController.MachineName = Environment.MachineName;
            MysqlController.ServiceName = ServiceName;
        }

        public void RemoveService()
        {
            StartProcess("cmd.exe", stopArgs, true);
        }

        public void InstallService()
        {
            StartProcess(exeName, startArgs, true);
        }

        public bool ServiceExists()
        {
            ServiceController[] services = ServiceController.GetServices();
            foreach (var service in services) {
                if (service.ServiceName == ServiceName)
                    return true;
            }
            return false;
        }

        public override void Start()
        {
            if(MysqlController.Status == ServiceControllerStatus.Running)
            {
                return;
            }
            try {
                MysqlController.Start();
                MysqlController.WaitForStatus(ServiceControllerStatus.Running);
                Log.wnmp_log_notice("Started " + progName, progLogSection);
            } catch (Exception ex) {
                Log.wnmp_log_error("Start(): " + ex.Message, progLogSection);
            }
        }

        public override void Stop()
        {
            if(MysqlController.Status == ServiceControllerStatus.Stopped)
            {
                return;
            }
            try {
                MysqlController.Stop();
                MysqlController.WaitForStatus(ServiceControllerStatus.Stopped);
                Log.wnmp_log_notice("Stopped " + progName, progLogSection);
            } catch (Exception ex) {
                Log.wnmp_log_notice("Stop(): " + ex.Message, progLogSection);
            }
        }

    }

开启php代码:

class PHPProgram : WnmpProgram
    {
        public PHPProgram()
        {
            ps.StartInfo.EnvironmentVariables.Add("PHP_FCGI_MAX_REQUESTS", "0"); // Disable auto killing PHP
        }

        private string GetPHPIniPath()
        {
            return MainWindow.StartupPath + "/" + Settings.PHPDirName.Value + "/php.ini";
        }

        public override void Start()
        {
            if(this.IsRunning())
            {
                return;
            }
            uint ProcessCount = Settings.PHP_Processes.Value;
            short port = Settings.PHP_Port.Value;
            string phpini = GetPHPIniPath();

            try {
                for (var i = 1; i <= ProcessCount; i++) {
                    StartProcess(exeName, String.Format("-b localhost:{0} -c {1}", port, phpini));
                    Log.wnmp_log_notice("Starting PHP " + i + "/" + ProcessCount + " on port: " + port, progLogSection);
                    port++;
                }
                Log.wnmp_log_notice("PHP started", progLogSection);
            } catch (Exception ex) {
                Log.wnmp_log_error("StartPHP(): " + ex.Message, progLogSection);
            }
        }

    }

开启nginx

#######这里要注意WorkingDirectory属性设置成nginx目录,这里是setup代码

   private readonly WnmpProgram nginx = new WnmpProgram();

   private void SetupNginx()
        {
            nginx.Settings = Settings;
            nginx.exeName = StartupPath + String.Format("{0}/nginx.exe", Settings.NginxDirName.Value);
            nginx.procName = "nginx";
            nginx.progName = "Nginx";
            nginx.workingDir = StartupPath + Settings.NginxDirName.Value;
            nginx.progLogSection = Log.LogSection.WNMP_NGINX;
            nginx.startArgs = "";
            nginx.stopArgs = "-s stop";
            nginx.killStop = false;
            nginx.statusLabel = lblNginx;
            nginx.confDir = "/conf/";
            nginx.logDir = "/logs/";
        }

其他功能

配置nginx,php,mysql目录名,管理php扩展

clipboard.png

clipboard.png

编程语言面板

clipboard.png

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!