public void test_duplicated_keys_are_concatenated_in_same_section() { var parser = new ConcatenateDuplicatedKeysIniDataParser(); parser.Configuration.AllowDuplicateSections = true; var iniData = parser.Parse(iniFileStr); Assert.That(iniData["MySection"]["File"] == "a.txt;b.txt;c.txt;d.txt"); }
public void test_duplicated_keys_are_concatenated_with_different_string() { var parser = new ConcatenateDuplicatedKeysIniDataParser(); parser.Configuration.ConcatenateSeparator = "+"; parser.Configuration.AllowDuplicateSections = true; var inidata = parser.Parse(iniFileStr); Assert.That(inidata["MySection"]["File"] == "a.txt+b.txt+c.txt+d.txt"); }
public PhpDiagDialog(IServiceProvider provider, ServerManager server) : base(provider) { InitializeComponent(); var knownPhpVersions = new Dictionary <string, PhpVersion> { { "5.6", new PhpVersion("5.6", new DateTime(2018, 12, 31), new Version(11, 0)) }, { "7.0", new PhpVersion("7.0", new DateTime(2018, 12, 3), new Version(14, 0)) }, { "7.1", new PhpVersion("7.1", new DateTime(2019, 12, 1), new Version(14, 0)) }, { "7.2", new PhpVersion("7.2", new DateTime(2020, 11, 30), new Version(14, 11)) } }; var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnGenerate, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); try { Warn("IMPORTANT: This report might contain confidential information. Mask such before sharing to others."); Warn("-----"); Debug($"System Time: {DateTime.Now}"); Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}"); Debug($"OS: {Environment.OSVersion}"); Debug($"Server Type: {server.Mode.AsString(EnumFormat.Description)}"); Debug(string.Empty); var modules = new ModulesFeature((Module)provider); modules.Load(); Debug($"Scan {modules.Items.Count} installed module(s)."); if (modules.Items.All(item => item.Name != "FastCgiModule")) { Error($"FastCGI module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); return; } else { Debug("FastCGI module is installed."); } Debug(string.Empty); var handlers = new HandlersFeature((Module)provider); handlers.Load(); var foundPhpHandler = new List <HandlersItem>(); Debug($"Scan {handlers.Items.Count} registered handler(s)."); foreach (var item in handlers.Items) { if (item.Modules == "FastCgiModule") { Debug($"* Found FastCGI handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Handler: {item.TypeString}, Entry Type: {item.Flag} }}."); foundPhpHandler.Add(item); } } if (foundPhpHandler.Count == 0) { Error($"No FastCGI handler is registered for this web site."); Error($" * To run PHP on IIS, please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); Error($" * To run Python on IIS, please refer to https://pypi.org/project/wfastcgi/ or use HttpPlatformHandler https://docs.microsoft.com/en-us/iis/extensions/httpplatformhandler/httpplatformhandler-configuration-reference."); return; } Debug(string.Empty); var fastCgiFeature = new FastCgiFeature((Module)provider); fastCgiFeature.Load(); Debug($"Scan {fastCgiFeature.Items.Count} registered FastCGI application(s)."); var foundPhp = new List <FastCgiItem>(); foreach (var item in fastCgiFeature.Items) { var combination = string.IsNullOrWhiteSpace(item.Arguments) ? item.Path : item.Path + '|' + item.Arguments; foreach (var handler in foundPhpHandler) { if (string.Equals(combination, handler.ScriptProcessor, StringComparison.OrdinalIgnoreCase)) { Debug($"* Found FastCGI application registered as {{ Full path: {item.Path}, Arguments: {item.Arguments} }}."); foundPhp.Add(item); break; } } } if (foundPhp.Count == 0) { Error($"No suitable FastCGI appilcation is registered on this server."); Error($" * To run PHP on IIS, please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); Error($" * To run Python on IIS, please refer to https://pypi.org/project/wfastcgi/ or use HttpPlatformHandler https://docs.microsoft.com/en-us/iis/extensions/httpplatformhandler/httpplatformhandler-configuration-reference."); return; } Debug(Environment.NewLine); Debug($"Verify web stack installation versions."); foreach (var item in foundPhp) { var path = item.Path; if (path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase)) { // PHP var info = FileVersionInfo.GetVersionInfo(path); var version = $"{info.FileMajorPart}.{info.FileMinorPart}"; if (knownPhpVersions.ContainsKey(version)) { var matched = knownPhpVersions[version]; if (matched.ExpiringDate <= DateTime.Now) { Error($"* PHP {info.FileVersion} ({path}) is unknown or obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else if (matched.ExpiringDate > DateTime.Now && (matched.ExpiringDate - DateTime.Now).TotalDays < 180) { Warn($"* PHP {version} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else { Debug($"* PHP {version} ({path}) is supported."); } var x86 = new PeNet.PeFile(path).Is32Bit; var cppFile = Path.Combine( Environment.GetFolderPath(x86 ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System), $"msvcp{matched.CppVersion.Major}0.dll"); if (File.Exists(cppFile)) { var cpp = FileVersionInfo.GetVersionInfo(cppFile); if (cpp.FileMinorPart >= matched.CppVersion.Minor) { Debug($" Visual C++ runtime is detected (expected: {matched.CppVersion}, detected: {cpp.FileVersion})."); } else { Error($" Visual C++ runtime {matched.CppVersion} is not detected. Please install it following the tips on https://windows.php.net/download/."); } } else { Error($" Visual C++ {matched.CppVersion} runtime is not detected. Please install it following the tips on https://windows.php.net/download/."); } } else { Error($"* PHP {info.FileVersion} ({path}) is unknown or obsolete. Please refer to http://php.net/supported-versions.php for more details."); } } else if (path.TrimEnd('"').EndsWith("python.exe", StringComparison.OrdinalIgnoreCase)) { // Python } } Debug(string.Empty); var systemPath = Environment.GetEnvironmentVariable("Path"); Debug($"Windows Path environment variable: {systemPath}."); Debug(string.Empty); string[] paths = systemPath.Split(new char[1] { Path.PathSeparator }); foreach (var item in foundPhp) { var path = item.Path; if (path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase)) { var rootFolder = Path.GetDirectoryName(path); Debug($"[{rootFolder}]"); if (!Directory.Exists(rootFolder)) { Error("Invalid root folder is found. Skip."); continue; } var config = Path.Combine(rootFolder, "php.ini"); if (File.Exists(config)) { Info($"Found PHP config file {config}."); var parser = new ConcatenateDuplicatedKeysIniDataParser(); parser.Configuration.ConcatenateSeparator = " "; var data = parser.Parse(File.ReadAllText(config)); var extensionFolder = data["PHP"]["extension_dir"]; if (extensionFolder == null) { extensionFolder = "ext"; } var fullPath = Path.Combine(rootFolder, extensionFolder); Info($"PHP loadable extension folder: {fullPath}"); var extesionNames = data["PHP"]["extension"]; if (extesionNames == null) { Info("No extension to verify."); } else { var extensions = extesionNames.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Info($"Found {extensions.Length} extension(s) to verify."); var noError = true; foreach (var name in extensions) { var fileName = Path.Combine(fullPath, $"php_{name}.dll"); if (!File.Exists(fileName)) { Error($"* Extension {name} is listed, but on disk the file cannot be found {fileName}"); noError = false; } } if (noError) { Info("All extension(s) listed can be found on disk."); } } } else { Warn($"Cannot find PHP config file {config}. Default settings are used."); } var matched = false; foreach (var system in paths) { if (string.Equals(rootFolder, system, StringComparison.OrdinalIgnoreCase)) { matched = true; break; } } if (matched) { Debug($"PHP installation has been added to Windows Path environment variable."); } else { Error($"PHP installation is not yet added to Windows Path environment variable. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); Warn($"Restart Jexus Manager and rerun PHP Diagnostics after changing Windows Path environment variable."); } Debug(string.Empty); // TODO: verify other configuration in php.info. } else if (path.TrimEnd('"').EndsWith("python.exe", StringComparison.OrdinalIgnoreCase)) { } } } catch (Exception ex) { Debug(ex.ToString()); Rollbar.RollbarLocator.RollbarInstance.Error(ex); } })); container.Add( Observable.FromEventPattern <EventArgs>(btnSave, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var fileName = DialogHelper.ShowSaveFileDialog(null, "Text Files|*.txt|All Files|*.*"); if (string.IsNullOrEmpty(fileName)) { return; } File.WriteAllText(fileName, txtResult.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnVerify, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); })); }
public PhpDiagDialog(IServiceProvider provider, ServerManager server) : base(provider) { InitializeComponent(); var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnGenerate, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); try { Debug($"System Time: {DateTime.Now}"); Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}"); Debug($"OS: {Environment.OSVersion}"); Debug($"{server.Type}"); Debug(string.Empty); var handlers = new HandlersFeature((Module)provider); handlers.Load(); var foundPhpHandler = false; Debug($"Scan {handlers.Items.Count} registered handler(s)."); foreach (var item in handlers.Items) { if (string.Equals(item.Path, "*.php", StringComparison.OrdinalIgnoreCase)) { Debug($"* Found PHP handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Handler: {item.TypeString}, Entry Type: {item.Flag} }}."); foundPhpHandler = true; } } if (!foundPhpHandler) { Error($"No PHP handler is registered for this web site. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); return; } Debug(string.Empty); var fastCgiFeature = new FastCgiFeature((Module)provider); fastCgiFeature.Load(); Debug($"Scan {fastCgiFeature.Items.Count} registered FastCGI application(s)."); var foundPhp = new List <string>(); foreach (var item in fastCgiFeature.Items) { if (item.Path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase)) { Debug($"* Found PHP FastCGI application registered as {{ Full path: {item.Path}, Arguments: {item.Arguments} }}."); foundPhp.Add(item.Path); } } if (foundPhp.Count == 0) { Error($"No PHP FastCGI appilcation is registered on this server. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); return; } Debug(Environment.NewLine); Debug($"Verify PHP installation versions."); foreach (var path in foundPhp) { var info = FileVersionInfo.GetVersionInfo(path); if (info.FileMajorPart < 5) { Error($"* PHP {info.FileVersion} ({path}) is obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else if (info.FileMajorPart == 5) { if (info.FileMinorPart < 6) { Error($"* PHP {info.FileVersion} ({path}) is obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else if (info.FileMinorPart == 6) { Warn($"* PHP {info.FileVersion} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else { Error($"* PHP {info.FileVersion} ({path}) is unknown. Please refer to http://php.net/supported-versions.php for more details."); } } else if (info.FileMajorPart == 7) { if (info.FileMinorPart == 0) { Warn($"* PHP {info.FileVersion} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else { Debug($"* PHP {info.FileVersion} ({path}) is supported."); } } else { Error($"* PHP {info.FileVersion} ({path}) is unknown. Please refer to http://php.net/supported-versions.php for more details."); } } Debug(string.Empty); var systemPath = Environment.GetEnvironmentVariable("Path"); Debug($"Windows Path: {systemPath}."); Debug(string.Empty); string[] paths = systemPath.Split(new char[1] { Path.PathSeparator }); foreach (var path in foundPhp) { var rootFolder = Path.GetDirectoryName(path); Debug($"[{rootFolder}]"); var config = Path.Combine(rootFolder, "php.ini"); if (File.Exists(config)) { Info($"Found PHP config file {config}."); var parser = new ConcatenateDuplicatedKeysIniDataParser(); parser.Configuration.ConcatenateSeparator = " "; var data = parser.Parse(File.ReadAllText(config)); var extensionFolder = data["PHP"]["extension_dir"]; if (extensionFolder == null) { extensionFolder = "ext"; } var fullPath = Path.Combine(rootFolder, extensionFolder); Info($"PHP loadable extension folder: {fullPath}"); var extesionNames = data["PHP"]["extension"]; if (extesionNames == null) { Info("No extension to verify."); } else { var extensions = extesionNames.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Info($"Found {extensions.Length} extension(s) to verify."); var noError = true; foreach (var name in extensions) { var fileName = Path.Combine(fullPath, $"php_{name}.dll"); if (!File.Exists(fileName)) { Error($"* Extension {name} is listed, but on disk the file cannot be found {fileName}"); noError = false; } } if (noError) { Info("All extension(s) listed can be found on disk."); } } } else { Warn($"Cannot find PHP config file {config}. Default settings are used."); } var matched = false; foreach (var system in paths) { if (string.Equals(rootFolder, system, StringComparison.OrdinalIgnoreCase)) { matched = true; break; } } if (matched) { Debug($"PHP installation has been added to Windows Path environment."); } else { Error($"PHP installation is not yet added to Windows Path environment. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); } Debug(string.Empty); } // TODO: verify other configurations in php.info. } catch (Exception ex) { Debug(ex.ToString()); RollbarDotNet.Rollbar.Report(ex); } })); container.Add( Observable.FromEventPattern <EventArgs>(btnSave, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var fileName = DialogHelper.ShowSaveFileDialog(null, "Text Files|*.txt|All Files|*.*"); if (string.IsNullOrEmpty(fileName)) { return; } File.WriteAllText(fileName, txtResult.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnVerify, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); })); }