Bearsampp 2026.9.23
Loading...
Searching...
No Matches
Win32Native Class Reference

Static Public Member Functions

static countFilesFolders ($path)
static countFilesFoldersCOM ($path)
static createShortcut ($shortcutPath, $targetPath, $workingDir='', $description='', $iconPath='')
static findProcessesByName ($name, $properties=[])
static getCurrentPid ()
static getDefaultBrowser ()
static getInstalledBrowsers ()
static getProcessInfo ($pid, $properties=[])
static getProcessList ($properties=[])
static getServiceInfo ($serviceName, $properties=[])
static getServiceState ($serviceName)
static getSpecialFolderPath ($folderName)
static killProcess ($pid)
static listServices ($properties=[])
static processExists ($pid)
static registryDeleteKey ($hive, $key)
static registryDeleteValue ($hive, $key, $value)
static registryExists ($hive, $key, $value=null)
static registryGetValue ($hive, $key, $value='')
static registrySetValue ($hive, $key, $value, $data, $type='REG_SZ')
static resetConnections ()
static serviceExists ($serviceName)

Static Private Member Functions

static countFilesFoldersManual ($path)
static countFolderItemsCOM ($fso, $path)
static extractBrowserExecutablePath ($commandPath)
static getWmiCimv2 ()
static getWmiStdRegProv ()
static getWscriptShell ()
static mapRegistryHive ($hive)

Static Private Attributes

static COM $wmiCimv2 = null
static COM $wmiStdRegProv = null
static COM $wscriptShell = null

Detailed Description

Class Win32Native

This class provides native Windows operations using PHP COM extension. Replaces VBScript operations with direct COM/WMI access from PHP. Uses Windows Management Instrumentation (WMI) and WScript.Shell COM objects.

Definition at line 16 of file class.win32native.php.

Member Function Documentation

◆ countFilesFolders()

countFilesFolders ( $path)
static

Counts files and folders recursively using native PHP. Replaces VBS with native PHP (faster than COM FileSystemObject).

Parameters
string$pathThe path to count files and folders in
Returns
int|false The count of files and folders, or false on failure

Definition at line 792 of file class.win32native.php.

793 {
794 Log::debug('countFilesFolders: Counting in ' . $path . ' (Native PHP)');
795
796 $startTime = microtime(true);
797
798 try {
799 if (!is_dir($path)) {
800 Log::error('countFilesFolders: Path is not a directory: ' . $path);
801
802 return false;
803 }
804
805 $count = 0;
806
807 // Use RecursiveDirectoryIterator for efficient recursive counting
808 try {
809 $iterator = new RecursiveIteratorIterator(
810 new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
811 RecursiveIteratorIterator::SELF_FIRST
812 );
813
814 foreach ($iterator as $item) {
815 $count++;
816 }
817 } catch (Exception $e) {
818 // If RecursiveIterator fails, fall back to manual recursion
819 Log::debug('countFilesFolders: RecursiveIterator failed, using manual recursion');
820 $count = self::countFilesFoldersManual($path);
821 }
822
823 $duration = round((microtime(true) - $startTime) * 1000, 2);
824 Log::debug('countFilesFolders: Counted ' . $count . ' items in ' . $duration . 'ms (Native PHP)');
825
826 return $count;
827 } catch (Exception $e) {
828 Log::error('countFilesFolders: Exception: ' . $e->getMessage());
829
830 return false;
831 }
832 }
static debug($data, $file=null)
static error($data, $file=null)
static countFilesFoldersManual($path)

References countFilesFoldersManual(), Log\debug(), and Log\error().

Here is the call graph for this function:

◆ countFilesFoldersCOM()

countFilesFoldersCOM ( $path)
static

Counts files and folders recursively using COM FileSystemObject. Alternative COM-based implementation (slower than native PHP).

Parameters
string$pathThe path to count files and folders in
Returns
int|false The count of files and folders, or false on failure

Definition at line 881 of file class.win32native.php.

882 {
883 Log::debug('countFilesFoldersCOM: Counting in ' . $path . ' (COM/FSO)');
884
885 $startTime = microtime(true);
886
887 try {
888 $fso = new COM("Scripting.FileSystemObject");
889
890 if (!$fso->FolderExists($path)) {
891 Log::error('countFilesFoldersCOM: Path does not exist: ' . $path);
892
893 return false;
894 }
895
896 $count = self::countFolderItemsCOM($fso, $path);
897
898 $duration = round((microtime(true) - $startTime) * 1000, 2);
899 Log::debug('countFilesFoldersCOM: Counted ' . $count . ' items in ' . $duration . 'ms (COM/FSO)');
900
901 return $count;
902 } catch (Exception $e) {
903 Log::error('countFilesFoldersCOM: COM exception: ' . $e->getMessage());
904
905 return false;
906 }
907 }
static countFolderItemsCOM($fso, $path)

References countFolderItemsCOM(), Log\debug(), and Log\error().

Here is the call graph for this function:

◆ countFilesFoldersManual()

countFilesFoldersManual ( $path)
staticprivate

Manual recursive file/folder counting (fallback method). Helper method for countFilesFolders.

Parameters
string$pathThe path to count
Returns
int The count of files and folders

Definition at line 842 of file class.win32native.php.

843 {
844 $count = 0;
845
846 try {
847 $items = @scandir($path);
848
849 if ($items === false) {
850 return 0;
851 }
852
853 foreach ($items as $item) {
854 if ($item === '.' || $item === '..') {
855 continue;
856 }
857
858 $fullPath = $path . DIRECTORY_SEPARATOR . $item;
859 $count++; // Count this item
860
861 if (is_dir($fullPath)) {
862 // Recursively count subdirectory
863 $count += self::countFilesFoldersManual($fullPath);
864 }
865 }
866 } catch (Exception $e) {
867 // Silently handle errors (permission denied, etc.)
868 }
869
870 return $count;
871 }

References countFilesFoldersManual().

Referenced by countFilesFolders(), and countFilesFoldersManual().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ countFolderItemsCOM()

countFolderItemsCOM ( $fso,
$path )
staticprivate

Recursive helper for COM-based file/folder counting. Helper method for countFilesFoldersCOM.

Parameters
COM$fsoFileSystemObject instance
string$pathThe path to count
Returns
int The count of files and folders

Definition at line 918 of file class.win32native.php.

919 {
920 try {
921 $folder = $fso->GetFolder($path);
922
923 // Count files and subfolders in this folder
924 $count = $folder->Files->Count + $folder->SubFolders->Count;
925
926 // Recursively count subfolders
927 foreach ($folder->SubFolders as $subFolder) {
928 $count += self::countFolderItemsCOM($fso, $subFolder->Path);
929 }
930
931 return $count;
932 } catch (Exception $e) {
933 // Silently handle errors (permission denied, etc.)
934 return 0;
935 }
936 }

References countFolderItemsCOM().

Referenced by countFilesFoldersCOM(), and countFolderItemsCOM().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ createShortcut()

createShortcut ( $shortcutPath,
$targetPath,
$workingDir = '',
$description = '',
$iconPath = '' )
static

Creates a Windows shortcut using COM. Replaces VBS with direct COM access.

Parameters
string$shortcutPathFull path where to save the shortcut (.lnk file)
string$targetPathPath to the target executable
string$workingDirWorking directory for the shortcut
string$descriptionShortcut description
string$iconPathPath to icon file
Returns
bool True on success, false on failure

Definition at line 738 of file class.win32native.php.

739 {
740 Log::debug('createShortcut: Creating shortcut at ' . $shortcutPath . ' (COM)');
741
742 $startTime = microtime(true);
743
744 try {
745 $shell = self::getWscriptShell();
746
747 // Create the shortcut object
748 $shortcut = $shell->CreateShortcut($shortcutPath);
749
750 // Set shortcut properties
751 $shortcut->TargetPath = $targetPath;
752
753 if (!empty($workingDir)) {
754 $shortcut->WorkingDirectory = $workingDir;
755 }
756
757 if (!empty($description)) {
758 $shortcut->Description = $description;
759 }
760
761 if (!empty($iconPath)) {
762 $shortcut->IconLocation = $iconPath;
763 }
764
765 // Save the shortcut
766 $shortcut->Save();
767
768 $duration = round((microtime(true) - $startTime) * 1000, 2);
769 Log::debug('createShortcut: Successfully created shortcut in ' . $duration . 'ms (COM)');
770
771 return true;
772 } catch (Exception $e) {
774 Log::error('createShortcut: COM exception: ' . $e->getMessage());
775
776 return false;
777 }
778 }
static resetConnections()
static getWscriptShell()

References Log\debug(), Log\error(), getWscriptShell(), and resetConnections().

Referenced by Util\enableLaunchStartup().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ extractBrowserExecutablePath()

extractBrowserExecutablePath ( $commandPath)
staticprivate

Extracts the executable path from a browser command string. Helper method for browser detection.

Parameters
string$commandPathThe command path string from registry
Returns
string|false The extracted executable path, or false on failure

Definition at line 1282 of file class.win32native.php.

1283 {
1284 if (empty($commandPath)) {
1285 return false;
1286 }
1287
1288 // Method 1: Extract path from quotes
1289 // Format: "C:\Program Files\Browser\browser.exe" --arguments
1290 if (preg_match('/"([^"]+\\.exe)"/i', $commandPath, $matches)) {
1291 return $matches[1];
1292 }
1293
1294 // Method 2: Extract path without quotes but with .exe
1295 // Format: C:\Program Files\Browser\browser.exe --arguments
1296 if (preg_match('/^([^\\s]+\\.exe)/i', trim($commandPath), $matches)) {
1297 return $matches[1];
1298 }
1299
1300 // Method 3: Handle paths with spaces but no quotes (rare)
1301 // Try to find .exe in the string
1302 if (preg_match('/([A-Z]:\\\\[^"]+\\.exe)/i', $commandPath, $matches)) {
1303 return $matches[1];
1304 }
1305
1306 // Method 4: Fallback - take everything before first space
1307 $parts = explode(' ', trim($commandPath));
1308 $path = str_replace('"', '', $parts[0]);
1309
1310 // Validate it looks like a path
1311 if (stripos($path, '.exe') !== false) {
1312 return $path;
1313 }
1314
1315 return false;
1316 }

Referenced by getInstalledBrowsers().

Here is the caller graph for this function:

◆ findProcessesByName()

findProcessesByName ( $name,
$properties = [] )
static

Finds processes by name.

Parameters
string$nameProcess name (e.g., 'notepad.exe')
array$propertiesProperties to retrieve
Returns
array Array of matching processes

Definition at line 303 of file class.win32native.php.

304 {
305 if (empty($name)) {
306 return [];
307 }
308
309 if (empty($properties)) {
310 $properties = ['Name', 'ProcessID', 'ExecutablePath'];
311 }
312
313 try {
314 $wmi = self::getWmiCimv2();
315 $selectClause = implode(', ', $properties);
316
317 // Sanitize the name parameter to prevent WQL injection
318 // Escape single quotes by doubling them (WQL standard)
319 $safeName = str_replace("'", "''", $name);
320
321 $query = "SELECT {$selectClause} FROM Win32_Process WHERE Name = '{$safeName}'";
322 $processes = $wmi->ExecQuery($query);
323
324 $result = [];
325 foreach ($processes as $proc) {
326 $process = [];
327 foreach ($properties as $prop) {
328 try {
329 $value = $proc->$prop;
330 $process[$prop] = $value ?? '';
331 } catch (Exception $e) {
332 $process[$prop] = '';
333 }
334 }
335 $result[] = $process;
336 }
337
338 return $result;
339 } catch (Exception $e) {
341 Log::error('findProcessesByName: COM exception: ' . $e->getMessage());
342
343 return [];
344 }
345 }
$result
$proc
Definition ajax.php:130

References $proc, $result, Log\error(), getWmiCimv2(), and resetConnections().

Here is the call graph for this function:

◆ getCurrentPid()

getCurrentPid ( )
static

Gets the current PHP process ID.

Returns
int Current process ID

Definition at line 352 of file class.win32native.php.

353 {
354 return getmypid();
355 }

◆ getDefaultBrowser()

getDefaultBrowser ( )
static

Gets the default browser's executable path using COM. Replaces VBS with direct COM registry access.

Returns
string|false The path to the default browser executable, or false on failure

Definition at line 1146 of file class.win32native.php.

1147 {
1148 Log::debug('getDefaultBrowser: Reading default browser (COM)');
1149
1150 $startTime = microtime(true);
1151
1152 // Try to read the default browser from registry
1153 $browserPath = self::registryGetValue('HKLM', 'SOFTWARE\\Classes\\http\\shell\\open\\command', '');
1154
1155 if ($browserPath === null) {
1156 Log::debug('getDefaultBrowser: No default browser found');
1157
1158 return false;
1159 }
1160
1161 $duration = round((microtime(true) - $startTime) * 1000, 2);
1162
1163 // Extract the executable path from the command
1164 // Format is usually: "C:\Program Files\Browser\browser.exe" -- "%1"
1165 if (preg_match('/"([^"]+)"/', $browserPath, $matches)) {
1166 $path = $matches[1];
1167 } else {
1168 // No quotes, take everything before the first space or use as-is
1169 $path = trim(explode(' ', $browserPath)[0]);
1170 $path = str_replace('"', '', $path);
1171 }
1172
1173 Log::debug('getDefaultBrowser: Found browser in ' . $duration . 'ms (COM)');
1174
1175 return $path;
1176 }
static registryGetValue($hive, $key, $value='')

References Log\debug(), and registryGetValue().

Referenced by ActionReload\__construct(), and ActionStartup\checkBrowser().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getInstalledBrowsers()

getInstalledBrowsers ( )
static

Gets a list of installed browsers using hybrid approach. Hybrid approach - known browsers + pattern matching (NO VBS!)

Returns
array An array of browser executable paths (empty array if none found)

Definition at line 1184 of file class.win32native.php.

1185 {
1186 Log::debug('getInstalledBrowsers: Enumerating installed browsers (Hybrid - No VBS)');
1187
1188 $startTime = microtime(true);
1189 $browsers = [];
1190
1191 // Known browser registry names (covers 99% of browsers)
1192 $knownBrowsers = [
1193 // Major browsers
1194 'Google Chrome',
1195 'Microsoft Edge',
1196 'Opera',
1197 'Brave',
1198 'Vivaldi',
1199 'Chromium',
1200
1201 // Firefox variants
1202 'Firefox',
1203 'Firefox-308046B0AF4A39CB', // Common Firefox GUID
1204 'Firefox Developer Edition',
1205 'Firefox Nightly',
1206
1207 // Other browsers
1208 'Safari',
1209 'Waterfox',
1210 'Pale Moon',
1211 'Yandex',
1212 'IEXPLORE.EXE',
1213 'Total Browser',
1214 'Maxthon',
1215 'Seamonkey',
1216 'K-Meleon',
1217 'Basilisk',
1218 'Tor Browser',
1219 'Slimjet',
1220 'Epic Privacy Browser',
1221 'Comodo Dragon',
1222 'SRWare Iron',
1223 'Cent Browser',
1224 '360 Browser',
1225 'UC Browser',
1226 'Avast Secure Browser',
1227 'AVG Secure Browser',
1228 ];
1229
1230 // Registry paths to check
1231 $registryPaths = [
1232 ['hive' => 'HKLM', 'key' => 'SOFTWARE\\WOW6432Node\\Clients\\StartMenuInternet'],
1233 ['hive' => 'HKLM', 'key' => 'SOFTWARE\\Clients\\StartMenuInternet'],
1234 ['hive' => 'HKCU', 'key' => 'SOFTWARE\\Clients\\StartMenuInternet'],
1235 ];
1236
1237 // Check each known browser in each registry path
1238 foreach ($registryPaths as $regPath) {
1239 $hive = $regPath['hive'];
1240 $basePath = $regPath['key'];
1241
1242 foreach ($knownBrowsers as $browserName) {
1243 try {
1244 // Try to read the browser's command path
1245 $commandPath = self::registryGetValue(
1246 $hive,
1247 $basePath . '\\' . $browserName . '\\shell\\open\\command',
1248 ''
1249 );
1250
1251 if ($commandPath !== null && !empty($commandPath)) {
1252 // Extract executable path
1253 $exePath = self::extractBrowserExecutablePath($commandPath);
1254
1255 if ($exePath && !in_array($exePath, $browsers)) {
1256 Log::debug('getInstalledBrowsers: Found ' . $browserName . ': ' . $exePath);
1257 $browsers[] = $exePath;
1258 }
1259 }
1260 } catch (Exception $e) {
1261 // Browser not found, continue
1262 continue;
1263 }
1264 }
1265 }
1266
1267 $duration = round((microtime(true) - $startTime) * 1000, 2);
1268 Log::debug('getInstalledBrowsers: Found ' . count($browsers) . ' browser(s) in ' . $duration . 'ms (Hybrid - No VBS)');
1269
1270 // Always return an array (possibly empty) to simplify call sites
1271 return $browsers;
1272 }
static extractBrowserExecutablePath($commandPath)

References Log\debug(), extractBrowserExecutablePath(), and registryGetValue().

Referenced by ActionChangeBrowser\__construct().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getProcessInfo()

getProcessInfo ( $pid,
$properties = [] )
static

Gets information about a specific process by PID.

Parameters
int$pidThe process ID
array$propertiesProperties to retrieve
Returns
array|false Process information or false if not found

Definition at line 256 of file class.win32native.php.

257 {
258 if (!is_numeric($pid) || $pid <= 0) {
259 return false;
260 }
261
262 if (empty($properties)) {
263 $properties = ['Name', 'ProcessID', 'ExecutablePath', 'CommandLine'];
264 }
265
266 try {
267 $wmi = self::getWmiCimv2();
268 $selectClause = implode(', ', $properties);
269 $query = "SELECT {$selectClause} FROM Win32_Process WHERE ProcessID = {$pid}";
270 $processes = $wmi->ExecQuery($query);
271
272 foreach ($processes as $proc) {
273 $result = [];
274 foreach ($properties as $prop) {
275 try {
276 $value = $proc->$prop;
277 $result[$prop] = $value ?? '';
278 } catch (Exception $e) {
279 $result[$prop] = '';
280 }
281 }
282
283 return $result;
284 }
285
286 return false;
287 } catch (Exception $e) {
289 Log::error('getProcessInfo: COM exception: ' . $e->getMessage());
290
291 return false;
292 }
293 }

References $proc, $result, Log\error(), getWmiCimv2(), and resetConnections().

Here is the call graph for this function:

◆ getProcessList()

getProcessList ( $properties = [])
static

Gets a list of running processes using COM/WMI. Replaces VBS WMI process query with direct PHP COM access.

Parameters
array$propertiesOptional array of properties to retrieve (e.g., ['Name', 'ProcessID', 'ExecutablePath'])
Returns
array Array of processes with requested information

Definition at line 97 of file class.win32native.php.

98 {
99 Log::debug('getProcessList: Listing processes (COM/WMI)');
100
101 $startTime = microtime(true);
102
103 try {
104 // Create WMI connection
105 $wmi = self::getWmiCimv2();
106
107 // Build WQL query
108 if (empty($properties)) {
109 $properties = ['Name', 'ProcessID', 'ExecutablePath'];
110 }
111
112 $selectClause = implode(', ', $properties);
113 $query = "SELECT {$selectClause} FROM Win32_Process";
114
115 // Execute query
116 $processes = $wmi->ExecQuery($query);
117
118 // Convert to array
119 $result = [];
120 foreach ($processes as $proc) {
121 $process = [];
122 foreach ($properties as $prop) {
123 // Handle property access
124 try {
125 $value = $proc->$prop;
126 $process[$prop] = $value ?? '';
127 } catch (Exception $e) {
128 $process[$prop] = '';
129 }
130 }
131 $result[] = $process;
132 }
133
134 $duration = round((microtime(true) - $startTime) * 1000, 2);
135 Log::debug('getProcessList: Found ' . count($result) . ' processes in ' . $duration . 'ms (COM/WMI)');
136
137 return $result;
138 } catch (Exception $e) {
140 Log::error('getProcessList: COM exception: ' . $e->getMessage());
141
142 return [];
143 }
144 }

References $proc, $result, Log\debug(), Log\error(), getWmiCimv2(), and resetConnections().

Referenced by Win32Ps\getListProcs().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getServiceInfo()

getServiceInfo ( $serviceName,
$properties = [] )
static

Gets information about a Windows service using COM/WMI. Replaces VBS with direct COM/WMI access.

Parameters
string$serviceNameThe name of the service
array$propertiesOptional array of properties to retrieve
Returns
array|false Service information array, or false on failure

Definition at line 951 of file class.win32native.php.

952 {
953 Log::debug('getServiceInfo: Getting info for service ' . $serviceName . ' (COM/WMI)');
954
955 $startTime = microtime(true);
956
957 try {
958 // Create WMI connection
959 $wmi = self::getWmiCimv2();
960
961 // Default properties if none specified
962 if (empty($properties)) {
963 $properties = [
964 'Name',
965 'DisplayName',
966 'State',
967 'Status',
968 'StartMode',
969 'PathName',
970 'ProcessId',
971 'Started',
972 'StartName',
973 'Description'
974 ];
975 }
976
977 // Build WQL query
978 $selectClause = implode(', ', $properties);
979 $safeServiceName = str_replace("'", "''", $serviceName);
980 $query = "SELECT {$selectClause} FROM Win32_Service WHERE Name = '{$safeServiceName}'";
981
982 // Execute query
983 $services = $wmi->ExecQuery($query);
984
985 // Get the first (and should be only) result
986 foreach ($services as $service) {
987 $result = [];
988 foreach ($properties as $prop) {
989 try {
990 $value = $service->$prop;
991 $result[$prop] = $value ?? '';
992 } catch (Exception $e) {
993 $result[$prop] = '';
994 }
995 }
996
997 $duration = round((microtime(true) - $startTime) * 1000, 2);
998 Log::debug('getServiceInfo: Found service in ' . $duration . 'ms (COM/WMI)');
999
1000 return $result;
1001 }
1002
1003 // Service not found
1004 Log::debug('getServiceInfo: Service not found');
1005
1006 return false;
1007 } catch (Exception $e) {
1009 Log::error('getServiceInfo: COM exception: ' . $e->getMessage());
1010
1011 return false;
1012 }
1013 }

References $result, Log\debug(), Log\error(), getWmiCimv2(), and resetConnections().

Referenced by Nssm\infos(), and Win32Service\infos().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getServiceState()

getServiceState ( $serviceName)
static

Gets the state of a Windows service. Additional helper method.

Parameters
string$serviceNameThe name of the service
Returns
string|false The service state (Running, Stopped, etc.), or false if not found

Definition at line 1112 of file class.win32native.php.

1113 {
1114 try {
1115 $wmi = self::getWmiCimv2();
1116 // Sanitize the serviceName parameter to prevent WQL injection
1117 // Escape single quotes by doubling them (WQL standard)
1118 $safeServiceName = str_replace("'", "''", $serviceName);
1119 $query = "SELECT State FROM Win32_Service WHERE Name = '{$safeServiceName}'";
1120
1121 // Execute query
1122 $services = $wmi->ExecQuery($query);
1123
1124 foreach ($services as $service) {
1125 return $service->State;
1126 }
1127
1128 return false;
1129 } catch (Exception $e) {
1131
1132 return false;
1133 }
1134 }

References getWmiCimv2(), and resetConnections().

Referenced by ActionLoading\checkAllServicesStarted().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getSpecialFolderPath()

getSpecialFolderPath ( $folderName)
static

Gets a Windows special folder path using COM. Replaces VBS with direct COM access.

Parameters
string$folderNameThe special folder name (Desktop, Startup, etc.)
Returns
string|false The folder path, or false on failure

Definition at line 693 of file class.win32native.php.

694 {
695 Log::debug('getSpecialFolderPath: Getting ' . $folderName . ' path (COM)');
696
697 $startTime = microtime(true);
698
699 try {
700 $shell = self::getWscriptShell();
701
702 // Get the special folder path
703 $path = $shell->SpecialFolders($folderName);
704
705 $duration = round((microtime(true) - $startTime) * 1000, 2);
706
707 if ($path && !empty($path)) {
708 // Convert to Unix-style path
709 $path = str_replace('\\', '/', $path);
710 Log::debug('getSpecialFolderPath: Found ' . $folderName . ' in ' . $duration . 'ms (COM)');
711
712 return $path;
713 } else {
714 Log::debug('getSpecialFolderPath: ' . $folderName . ' not found');
715
716 return false;
717 }
718 } catch (Exception $e) {
720 Log::error('getSpecialFolderPath: COM exception: ' . $e->getMessage());
721
722 return false;
723 }
724 }

References Log\debug(), Log\error(), getWscriptShell(), and resetConnections().

Referenced by Path\getStartupLnkPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getWmiCimv2()

getWmiCimv2 ( )
staticprivate

Returns the cached WMI cimv2 connection, creating it on first use.

Returns
COM The cached WMI cimv2 connection.

Definition at line 39 of file class.win32native.php.

39 : COM
40 {
41 if (self::$wmiCimv2 === null) {
42 self::$wmiCimv2 = new COM("winmgmts://./root/cimv2");
43 }
44
45 return self::$wmiCimv2;
46 }

Referenced by findProcessesByName(), getProcessInfo(), getProcessList(), getServiceInfo(), getServiceState(), killProcess(), listServices(), processExists(), and serviceExists().

Here is the caller graph for this function:

◆ getWmiStdRegProv()

getWmiStdRegProv ( )
staticprivate

Returns the cached WMI StdRegProv connection, creating it on first use.

Returns
COM The cached WMI StdRegProv connection.

Definition at line 53 of file class.win32native.php.

53 : COM
54 {
55 if (self::$wmiStdRegProv === null) {
56 self::$wmiStdRegProv = new COM("winmgmts://./root/default:StdRegProv");
57 }
58
59 return self::$wmiStdRegProv;
60 }

Referenced by registryExists().

Here is the caller graph for this function:

◆ getWscriptShell()

getWscriptShell ( )
staticprivate

Returns the cached WScript.Shell object, creating it on first use.

Returns
COM The cached WScript.Shell object.

Definition at line 67 of file class.win32native.php.

67 : COM
68 {
69 if (self::$wscriptShell === null) {
70 self::$wscriptShell = new COM("WScript.Shell");
71 }
72
73 return self::$wscriptShell;
74 }

Referenced by createShortcut(), getSpecialFolderPath(), registryDeleteKey(), registryDeleteValue(), registryExists(), registryGetValue(), and registrySetValue().

Here is the caller graph for this function:

◆ killProcess()

killProcess ( $pid)
static

Kills a process by PID using COM/WMI. Replaces VBS WMI process termination with direct PHP COM access.

Parameters
int$pidThe process ID to kill
Returns
bool True on success, false on failure

Definition at line 154 of file class.win32native.php.

155 {
156 // Validate PID
157 if (!is_numeric($pid) || $pid <= 0) {
158 Log::error('killProcess: Invalid PID: ' . $pid);
159
160 return false;
161 }
162
163 Log::debug('killProcess: Killing process PID ' . $pid . ' (COM/WMI)');
164
165 $startTime = microtime(true);
166
167 try {
168 // Create WMI connection
169 $wmi = self::getWmiCimv2();
170
171 // Query for specific process
172 $query = "SELECT * FROM Win32_Process WHERE ProcessID = {$pid}";
173 $processes = $wmi->ExecQuery($query);
174
175 // Terminate the process
176 $found = false;
177 $terminateResult = null;
178 foreach ($processes as $proc) {
179 $terminateResult = $proc->Terminate();
180 $found = true;
181 break;
182 }
183
184 $duration = round((microtime(true) - $startTime) * 1000, 2);
185
186 if (!$found) {
187 Log::debug('killProcess: Process ' . $pid . ' not found');
188
189 return false;
190 }
191
192 // Check if Terminate() returned success (0 = success)
193 if ($terminateResult !== 0) {
194 Log::error('killProcess: Terminate() failed with status code: ' . $terminateResult);
195
196 return false;
197 }
198
199 // Additional verification: check if process still exists after a short delay
200 usleep(100000); // Wait 100ms for termination to take effect
201 if (self::processExists($pid)) {
202 Log::error('killProcess: Process ' . $pid . ' still exists after termination attempt');
203
204 return false;
205 }
206
207 Log::debug('killProcess: Successfully killed process ' . $pid . ' in ' . $duration . 'ms (COM/WMI)');
208
209 return true;
210 } catch (Exception $e) {
212 Log::error('killProcess: COM exception: ' . $e->getMessage());
213
214 return false;
215 }
216 }

References $proc, Log\debug(), Log\error(), getWmiCimv2(), and resetConnections().

Referenced by Win32Ps\kill(), and ActionQuit\terminatePhpProcesses().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ listServices()

listServices ( $properties = [])
static

Lists all Windows services using COM/WMI. Additional helper method.

Parameters
array$propertiesOptional array of properties to retrieve
Returns
array Array of service information

Definition at line 1023 of file class.win32native.php.

1024 {
1025 Log::debug('listServices: Listing all services (COM/WMI)');
1026
1027 $startTime = microtime(true);
1028
1029 try {
1030 // Create WMI connection
1031 $wmi = self::getWmiCimv2();
1032
1033 // Default properties if none specified
1034 if (empty($properties)) {
1035 $properties = ['Name', 'DisplayName', 'State', 'StartMode'];
1036 }
1037
1038 // Build WQL query
1039 $selectClause = implode(', ', $properties);
1040 $query = "SELECT {$selectClause} FROM Win32_Service";
1041
1042 // Execute query
1043 $services = $wmi->ExecQuery($query);
1044
1045 // Convert to array
1046 $result = [];
1047 foreach ($services as $service) {
1048 $serviceInfo = [];
1049 foreach ($properties as $prop) {
1050 try {
1051 $value = $service->$prop;
1052 $serviceInfo[$prop] = $value ?? '';
1053 } catch (Exception $e) {
1054 $serviceInfo[$prop] = '';
1055 }
1056 }
1057 $result[] = $serviceInfo;
1058 }
1059
1060 $duration = round((microtime(true) - $startTime) * 1000, 2);
1061 Log::debug('listServices: Found ' . count($result) . ' services in ' . $duration . 'ms (COM/WMI)');
1062
1063 return $result;
1064 } catch (Exception $e) {
1066 Log::error('listServices: COM exception: ' . $e->getMessage());
1067
1068 return [];
1069 }
1070 }

References $result, Log\debug(), Log\error(), getWmiCimv2(), and resetConnections().

Referenced by Win32Service\getServices().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mapRegistryHive()

mapRegistryHive ( $hive)
staticprivate

Maps registry hive abbreviations to full names for WScript.Shell.

Parameters
string$hiveThe registry hive (HKLM, HKCU, HKCR, HKU)
Returns
string The full hive name

Definition at line 368 of file class.win32native.php.

369 {
370 $hiveMap = [
371 'HKLM' => 'HKLM',
372 'HKCU' => 'HKCU',
373 'HKCR' => 'HKCR',
374 'HKU' => 'HKU',
375 'HKEY_LOCAL_MACHINE' => 'HKLM',
376 'HKEY_CURRENT_USER' => 'HKCU',
377 'HKEY_CLASSES_ROOT' => 'HKCR',
378 'HKEY_USERS' => 'HKU',
379 ];
380
381 return isset($hiveMap[$hive]) ? $hiveMap[$hive] : $hive;
382 }

Referenced by registryDeleteKey(), registryDeleteValue(), registryExists(), registryGetValue(), and registrySetValue().

Here is the caller graph for this function:

◆ processExists()

processExists ( $pid)
static

Checks if a process with the given PID exists.

Parameters
int$pidThe process ID to check
Returns
bool True if process exists, false otherwise

Definition at line 225 of file class.win32native.php.

226 {
227 if (!is_numeric($pid) || $pid <= 0) {
228 return false;
229 }
230
231 try {
232 $wmi = self::getWmiCimv2();
233 $query = "SELECT ProcessID FROM Win32_Process WHERE ProcessID = {$pid}";
234 $processes = $wmi->ExecQuery($query);
235
236 foreach ($processes as $proc) {
237 return true;
238 }
239
240 return false;
241 } catch (Exception $e) {
243
244 return false;
245 }
246 }

References $proc, getWmiCimv2(), and resetConnections().

Here is the call graph for this function:

◆ registryDeleteKey()

registryDeleteKey ( $hive,
$key )
static

Deletes a registry key and all its subkeys using COM. Additional helper method for key deletion.

Parameters
string$hiveThe registry hive (HKLM, HKCU, etc.)
string$keyThe registry key path to delete
Returns
bool True on success, false on failure

Definition at line 648 of file class.win32native.php.

649 {
650 $hive = self::mapRegistryHive($hive);
651 $regPath = $hive . '\\' . $key . '\\';
652
653 Log::debug('registryDeleteKey: Deleting ' . $regPath . ' (COM)');
654
655 try {
656 $shell = self::getWscriptShell();
657
658 // Delete the key (note the trailing backslash)
659 $shell->RegDelete($regPath);
660
661 Log::debug('registryDeleteKey: Successfully deleted key (COM)');
662
663 return true;
664 } catch (Exception $e) {
665 // If the key doesn't exist, that's OK
666 $errorMsg = $e->getMessage();
667 if (strpos($errorMsg, 'Unable to remove') !== false ||
668 strpos($errorMsg, 'Invalid root') !== false) {
669 Log::debug('registryDeleteKey: Key does not exist (already deleted)');
670
671 return true;
672 }
673
675 Log::error('registryDeleteKey: COM exception: ' . $e->getMessage());
676
677 return false;
678 }
679 }
static mapRegistryHive($hive)

References Log\debug(), Log\error(), getWscriptShell(), mapRegistryHive(), and resetConnections().

Referenced by Registry\setValue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ registryDeleteValue()

registryDeleteValue ( $hive,
$key,
$value )
static

Deletes a value from the Windows registry using COM. Replaces VBS/reg.exe with direct COM access.

Parameters
string$hiveThe registry hive (HKLM, HKCU, etc.)
string$keyThe registry key path
string$valueThe value name to delete
Returns
bool True on success, false on failure

Definition at line 603 of file class.win32native.php.

604 {
605 $hive = self::mapRegistryHive($hive);
606 $regPath = $hive . '\\' . $key . '\\' . $value;
607
608 Log::debug('registryDeleteValue: Deleting ' . $regPath . ' (COM)');
609
610 $startTime = microtime(true);
611
612 try {
613 $shell = self::getWscriptShell();
614
615 // Delete the value
616 $shell->RegDelete($regPath);
617
618 $duration = round((microtime(true) - $startTime) * 1000, 2);
619 Log::debug('registryDeleteValue: Successfully deleted value in ' . $duration . 'ms (COM)');
620
621 return true;
622 } catch (Exception $e) {
623 // If the value doesn't exist, that's OK
624 $errorMsg = $e->getMessage();
625 if (strpos($errorMsg, 'Unable to remove') !== false ||
626 strpos($errorMsg, 'Invalid root') !== false) {
627 Log::debug('registryDeleteValue: Value does not exist (already deleted)');
628
629 return true;
630 }
631
633 Log::error('registryDeleteValue: COM exception: ' . $e->getMessage());
634
635 return false;
636 }
637 }

References Log\debug(), Log\error(), getWscriptShell(), mapRegistryHive(), and resetConnections().

Referenced by Registry\setValue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ registryExists()

registryExists ( $hive,
$key,
$value = null )
static

Checks if a registry key or value exists using COM. Replaces VBS/reg.exe with direct COM access.

Uses StdRegProv for key existence checks (more reliable than WScript.Shell::RegRead). Uses WScript.Shell::RegRead for value existence checks.

Parameters
string$hiveThe registry hive (HKLM, HKCU, etc.)
string$keyThe registry key path
string | null$valueThe value name (null to check key existence only)
Returns
bool True if exists, false otherwise

Definition at line 397 of file class.win32native.php.

398 {
399 $hive = self::mapRegistryHive($hive);
400 $regPath = $hive . '\\' . $key;
401
402 Log::debug('registryExists: Checking ' . $regPath . ($value !== null ? '\\' . $value : ' (key)') . ' (COM)');
403
404 try {
405 if ($value === null) {
406 // Check if the key itself exists
407 // Use StdRegProv::EnumKey for reliable key existence checking
408 // This avoids false negatives from checking for a default value that may not exist
409 try {
410 $wmi = self::getWmiStdRegProv();
411
412 // Map hive names to WMI constants
413 $hiveConstMap = [
414 'HKCR' => 0x80000000, // HKEY_CLASSES_ROOT
415 'HKCU' => 0x80000001, // HKEY_CURRENT_USER
416 'HKLM' => 0x80000002, // HKEY_LOCAL_MACHINE
417 'HKU' => 0x80000003, // HKEY_USERS
418 ];
419
420 $hConst = $hiveConstMap[$hive] ?? 0x80000002; // Default to HKLM
421
422 // EnumKey checks if parent key's subkeys contain the requested key
423 // For root-level checks, pass empty parent
424 $pathParts = explode('\\', $key);
425
426 if (count($pathParts) === 1) {
427 // Top-level key: parent is root
428 $parentKey = '';
429 $keyName = $pathParts[0];
430 } else {
431 // Nested key: split parent from key name
432 $keyName = array_pop($pathParts);
433 $parentKey = implode('\\', $pathParts);
434 }
435
436 $subKeys = null;
437 $rc = $wmi->EnumKey($hConst, $parentKey, $subKeys);
438
439 if ($rc !== 0 || !is_array($subKeys)) {
440 Log::debug('registryExists: Key not found (EnumKey failed)');
441
442 return false;
443 }
444
445 // Check if our key name is in the list of subkeys
446 $exists = false;
447 foreach ($subKeys as $subKey) {
448 if (strcasecmp($subKey, $keyName) === 0) {
449 $exists = true;
450 break;
451 }
452 }
453
454 if ($exists) {
455 Log::debug('registryExists: Key found');
456
457 return true;
458 } else {
459 Log::debug('registryExists: Key not found');
460
461 return false;
462 }
463 } catch (Exception $e) {
464 self::$wmiStdRegProv = null;
465 Log::error('registryExists: StdRegProv exception during key check: ' . $e->getMessage());
466
467 return false;
468 }
469 } else {
470 // Check if a specific value exists within the key
471 // Use WScript.Shell::RegRead for value existence
472 try {
473 $shell = self::getWscriptShell();
474 $valuePath = $regPath . '\\' . $value;
475 $shell->RegRead($valuePath);
476 Log::debug('registryExists: Value found');
477
478 return true;
479 } catch (Exception $e) {
480 Log::debug('registryExists: Value not found');
481
482 return false;
483 }
484 }
485 } catch (Exception $e) {
487 Log::error('registryExists: COM exception: ' . $e->getMessage());
488
489 return false;
490 }
491 }
static getWmiStdRegProv()

References Log\debug(), Log\error(), getWmiStdRegProv(), getWscriptShell(), mapRegistryHive(), and resetConnections().

Referenced by Registry\exists().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ registryGetValue()

registryGetValue ( $hive,
$key,
$value = '' )
static

Gets a value from the Windows registry using COM. Replaces VBS/reg.exe with direct COM access.

Parameters
string$hiveThe registry hive (HKLM, HKCU, etc.)
string$keyThe registry key path
string$valueThe value name (empty string for default value)
Returns
mixed|null The registry value data, or null if not found

Definition at line 503 of file class.win32native.php.

504 {
505 $hive = self::mapRegistryHive($hive);
506 $regPath = $hive . '\\' . $key;
507
508 if ($value !== '') {
509 $regPath .= '\\' . $value;
510 } else {
511 // For default value, append backslash
512 $regPath .= '\\';
513 }
514
515 Log::debug('registryGetValue: Reading ' . $regPath . ' (COM)');
516
517 $startTime = microtime(true);
518
519 try {
520 $shell = self::getWscriptShell();
521 $result = $shell->RegRead($regPath);
522
523 $duration = round((microtime(true) - $startTime) * 1000, 2);
524
525 // Convert result to appropriate PHP type
526 if (is_object($result)) {
527 // COM objects need special handling
528 $result = (string)$result;
529 }
530
531 Log::debug('registryGetValue: Found value in ' . $duration . 'ms (COM)');
532
533 return $result;
534 } catch (Exception $e) {
535 Log::debug('registryGetValue: Value not found');
536
537 return null;
538 }
539 }

References $result, Log\debug(), getWscriptShell(), and mapRegistryHive().

Referenced by Path\findExecutable(), getDefaultBrowser(), getInstalledBrowsers(), Registry\getValue(), and Registry\setValue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ registrySetValue()

registrySetValue ( $hive,
$key,
$value,
$data,
$type = 'REG_SZ' )
static

Sets a value in the Windows registry using COM. Replaces VBS/reg.exe with direct COM access.

Parameters
string$hiveThe registry hive (HKLM, HKCU, etc.)
string$keyThe registry key path
string$valueThe value name
mixed$dataThe data to write
string$typeThe registry type (REG_SZ, REG_EXPAND_SZ, REG_DWORD, REG_BINARY)
Returns
bool True on success, false on failure

Definition at line 553 of file class.win32native.php.

554 {
555 $hive = self::mapRegistryHive($hive);
556 $regPath = $hive . '\\' . $key . '\\' . $value;
557
558 // Validate type
559 $validTypes = ['REG_SZ', 'REG_EXPAND_SZ', 'REG_DWORD', 'REG_BINARY'];
560 if (!in_array($type, $validTypes)) {
561 Log::error('registrySetValue: Invalid type: ' . $type);
562
563 return false;
564 }
565
566 Log::debug('registrySetValue: Writing ' . $regPath . ' (' . $type . ') (COM)');
567
568 $startTime = microtime(true);
569
570 try {
571 $shell = self::getWscriptShell();
572
573 // Convert data based on type
574 if ($type === 'REG_DWORD') {
575 $data = (int)$data;
576 }
577
578 // Write the value
579 $shell->RegWrite($regPath, $data, $type);
580
581 $duration = round((microtime(true) - $startTime) * 1000, 2);
582 Log::debug('registrySetValue: Successfully wrote value in ' . $duration . 'ms (COM)');
583
584 return true;
585 } catch (Exception $e) {
587 Log::error('registrySetValue: COM exception: ' . $e->getMessage());
588
589 return false;
590 }
591 }

References Log\debug(), Log\error(), getWscriptShell(), mapRegistryHive(), and resetConnections().

Referenced by Registry\setValue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resetConnections()

resetConnections ( )
static

Clears all cached COM connections. Call this after a COM operation fails so the next call gets a fresh connection.

Returns
void

Definition at line 82 of file class.win32native.php.

82 : void
83 {
84 self::$wmiCimv2 = null;
85 self::$wmiStdRegProv = null;
86 self::$wscriptShell = null;
87 }

Referenced by createShortcut(), findProcessesByName(), getProcessInfo(), getProcessList(), getServiceInfo(), getServiceState(), getSpecialFolderPath(), killProcess(), listServices(), processExists(), registryDeleteKey(), registryDeleteValue(), registryExists(), registrySetValue(), and serviceExists().

Here is the caller graph for this function:

◆ serviceExists()

serviceExists ( $serviceName)
static

Checks if a Windows service exists. Additional helper method.

Parameters
string$serviceNameThe name of the service
Returns
bool True if service exists, false otherwise

Definition at line 1080 of file class.win32native.php.

1081 {
1082 try {
1083 $wmi = self::getWmiCimv2();
1084 // Sanitize the serviceName parameter to prevent WQL injection
1085 // Escape single quotes by doubling them (WQL standard)
1086 $safeServiceName = str_replace("'", "''", $serviceName);
1087 $query = "SELECT Name FROM Win32_Service WHERE Name = '{$safeServiceName}'";
1088
1089 // Execute query
1090 $services = $wmi->ExecQuery($query);
1091
1092 foreach ($services as $service) {
1093 return true;
1094 }
1095
1096 return false;
1097 } catch (Exception $e) {
1099
1100 return false;
1101 }
1102 }

References getWmiCimv2(), and resetConnections().

Here is the call graph for this function:

Field Documentation

◆ $wmiCimv2

COM $wmiCimv2 = null
staticprivate

Definition at line 26 of file class.win32native.php.

◆ $wmiStdRegProv

COM $wmiStdRegProv = null
staticprivate

Definition at line 29 of file class.win32native.php.

◆ $wscriptShell

COM $wscriptShell = null
staticprivate

Definition at line 32 of file class.win32native.php.


The documentation for this class was generated from the following file: