Bearsampp 2026.5.5
Loading...
Searching...
No Matches
class.util.php
Go to the documentation of this file.
1<?php
2/*
3 *
4 * * Copyright (c) 2022-2025 Bearsampp
5 * * License: GNU General Public License version 3 or later; see LICENSE.txt
6 * * Website: https://bearsampp.com
7 * * Github: https://github.com/Bearsampp
8 *
9 */
10
35class Util
36{
41 private static $fileScanCache = null;
42
47 private static $fileScanCacheDuration = 3600;
48
53 private static $fileScanStats = [
54 'hits' => 0,
55 'misses' => 0,
56 'invalidations' => 0
57 ];
58
64 private static $cacheIntegrityKey = null;
65
74 public static function clearFolders($paths, $exclude = array())
75 {
76 $result = array();
77 foreach ($paths as $path) {
78 $result[$path] = self::clearFolder($path, $exclude);
79 }
80
81 return $result;
82 }
83
92 public static function clearFolder($path, $exclude = array())
93 {
94 $result = array();
95 $result['return'] = true;
96 $result['nb_files'] = 0;
97
98 $handle = @opendir($path);
99 if (!$handle) {
100 return null;
101 }
102
103 while (false !== ($file = readdir($handle))) {
104 if ($file == '.' || $file == '..' || in_array($file, $exclude)) {
105 continue;
106 }
107 if (is_dir($path . '/' . $file)) {
108 $r = self::clearFolder($path . '/' . $file);
109 if (!$r) {
110 $result['return'] = false;
111
112 return $result;
113 }
114 } else {
115 $r = @unlink($path . '/' . $file);
116 if ($r) {
117 $result['nb_files']++;
118 } else {
119 $result['return'] = false;
120
121 return $result;
122 }
123 }
124 }
125
126 closedir($handle);
127
128 return $result;
129 }
130
136 public static function deleteFolder($path)
137 {
138 if (is_dir($path)) {
139 if (substr($path, strlen($path) - 1, 1) != '/') {
140 $path .= '/';
141 }
142 $files = glob($path . '*', GLOB_MARK);
143 foreach ($files as $file) {
144 if (is_dir($file)) {
145 self::deleteFolder($file);
146 } else {
147 unlink($file);
148 }
149 }
150 rmdir($path);
151 }
152 }
153
162 private static function findFile($startPath, $findFile)
163 {
164 $result = false;
165
166 $handle = @opendir($startPath);
167 if (!$handle) {
168 return false;
169 }
170
171 while (false !== ($file = readdir($handle))) {
172 if ($file == '.' || $file == '..') {
173 continue;
174 }
175 if (is_dir($startPath . '/' . $file)) {
176 $result = self::findFile($startPath . '/' . $file, $findFile);
177 if ($result !== false) {
178 break;
179 }
180 } elseif ($file == $findFile) {
181 $result = UtilPath::formatUnixPath($startPath . '/' . $file);
182 break;
183 }
184 }
185
186 closedir($handle);
187
188 return $result;
189 }
190
198 public static function isValidIp($ip)
199 {
200 return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
201 || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
202 }
203
211 public static function isValidPort($port)
212 {
213 return is_numeric($port) && ($port > 0 && $port <= 65535);
214 }
215
222 public static function isAdmin()
223 {
224 // Only applicable on Windows
225 if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
226 // On non-Windows systems, check if running as root
227 if (function_exists('posix_geteuid')) {
228 return posix_geteuid() === 0;
229 }
230 // If we can't determine on non-Windows, assume true to avoid blocking
231 return true;
232 }
233
234 // Method 1: Try using shell_exec with 'net session' command
235 // This command only succeeds when run with admin privileges
236 $output = CommandRunner::shellExec('net session 2>&1');
237 if ($output !== null) {
238 // Check for access denied errors
239 if (stripos($output, 'Access is denied') !== false ||
240 stripos($output, 'System error 5') !== false ||
241 stripos($output, 'Zugriff verweigert') !== false) { // German
242 // Explicitly denied - not admin
243 return false;
244 }
245
246 // If we got output without errors, we likely have admin rights
247 if (stripos($output, 'There are no entries') !== false ||
248 stripos($output, 'These workstations') !== false ||
249 preg_match('/\\\\\\\\/', $output)) {
250 return true;
251 }
252 }
253
254 // Method 2: Check using whoami command (Windows Vista and later)
255 $output = CommandRunner::shellExec('whoami /groups 2>&1');
256 if ($output !== null && !empty($output)) {
257 // Look for the Administrators group or High Mandatory Level
258 if (stripos($output, 'S-1-16-12288') !== false || // High Mandatory Level
259 stripos($output, 'S-1-5-32-544') !== false) { // Administrators group
260 return true;
261 }
262
263 // If we got output but no admin indicators, we're not admin
264 if (stripos($output, 'S-1-16-8192') !== false) { // Medium Mandatory Level (not admin)
265 return false;
266 }
267 }
268
269 // Method 3: Try to write to a system directory
270 // This is a fallback method that checks if we can write to Windows directory
271 $testFile = getenv('SystemRoot') . '\\Temp\\bearsampp_admin_test_' . uniqid() . '.tmp';
272 $result = @file_put_contents($testFile, 'test');
273 if ($result !== false) {
274 @unlink($testFile);
275 return true;
276 }
277
278 // If all methods fail or indicate no admin, return false
279 return false;
280 }
281
289 public static function replaceDefine($path, $var, $value)
290 {
291 self::replaceInFile($path, array(
292 '/^define\‍((.*?)' . $var . '(.*?),/' => 'define(\'' . $var . '\', ' . (is_int($value) ? $value : '\'' . $value . '\'') . ');'
293 ));
294 }
295
302 public static function replaceInFile($path, $replaceList)
303 {
304 if (file_exists($path)) {
305 $lines = file($path);
306 $fp = fopen($path, 'w');
307 foreach ($lines as $nb => $line) {
308 $replaceDone = false;
309 foreach ($replaceList as $regex => $replace) {
310 if (preg_match($regex, $line, $matches)) {
311 $countParams = preg_match_all('/{{(\d+)}}/', $replace, $paramsMatches);
312 if ($countParams > 0 && $countParams <= count($matches)) {
313 foreach ($paramsMatches[1] as $paramsMatch) {
314 $replace = str_replace('{{' . $paramsMatch . '}}', $matches[$paramsMatch], $replace);
315 }
316 }
317 Log::trace('Replace in file ' . $path . ' :');
318 Log::trace('## line_num: ' . trim($nb));
319 Log::trace('## old: ' . trim($line));
320 Log::trace('## new: ' . trim($replace));
321 fwrite($fp, $replace . PHP_EOL);
322
323 $replaceDone = true;
324 break;
325 }
326 }
327 if (!$replaceDone) {
328 fwrite($fp, $line);
329 }
330 }
331 fclose($fp);
332 }
333 }
334
343 public static function getVersionList($path)
344 {
345 $result = array();
346
347 $handle = @opendir($path);
348 if (!$handle) {
349 return false;
350 }
351
352 $prefix = basename($path);
353
354 while (false !== ($file = readdir($handle))) {
355 $filePath = $path . '/' . $file;
356 if ($file != '.' && $file != '..' && is_dir($filePath) && $file != 'current') {
357 if (strpos($file, $prefix) === 0) {
358 $version = substr($file, strlen($prefix));
359 } else {
360 $version = $file;
361 }
362 $result[] = $version;
363 }
364 }
365
366 closedir($handle);
367 natcasesort($result);
368
369 return $result;
370 }
371
377 public static function getMicrotime()
378 {
379 list($usec, $sec) = explode(' ', microtime());
380
381 return ((float)$usec + (float)$sec);
382 }
383
384 public static function getAppBinsRegKey($fromRegistry = true)
385 {
386 global $bearsamppRegistry;
387
388 if ($fromRegistry) {
389 $value = $bearsamppRegistry->getValue(
393 );
394 Log::debug('App reg key from registry: ' . $value);
395 } else {
396 global $bearsamppBins, $bearsamppTools;
397 $value = '';
398 if ($bearsamppBins->getApache()->isEnable()) {
399 $value .= $bearsamppBins->getApache()->getSymlinkPath() . '/bin;';
400 }
401 if ($bearsamppBins->getPhp()->isEnable()) {
402 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . ';';
403 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/pear;';
404 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/deps;';
405 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/imagick;';
406 }
407 if ($bearsamppBins->getNodejs()->isEnable()) {
408 $value .= $bearsamppBins->getNodejs()->getSymlinkPath() . ';';
409 }
410 if ($bearsamppTools->getComposer()->isEnable()) {
411 $value .= $bearsamppTools->getComposer()->getSymlinkPath() . ';';
412 $value .= $bearsamppTools->getComposer()->getSymlinkPath() . '/vendor/bin;';
413 }
414 if ($bearsamppTools->getGhostscript()->isEnable()) {
415 $value .= $bearsamppTools->getGhostscript()->getSymlinkPath() . '/bin;';
416 }
417 if ($bearsamppTools->getGit()->isEnable()) {
418 $value .= $bearsamppTools->getGit()->getSymlinkPath() . '/bin;';
419 }
420 if ($bearsamppTools->getNgrok()->isEnable()) {
421 $value .= $bearsamppTools->getNgrok()->getSymlinkPath() . ';';
422 }
423 if ($bearsamppTools->getPerl()->isEnable()) {
424 $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/perl/site/bin;';
425 $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/perl/bin;';
426 $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/c/bin;';
427 }
428 if ($bearsamppTools->getPython()->isEnable()) {
429 $value .= $bearsamppTools->getPython()->getSymlinkPath() . '/bin;';
430 }
431 if ($bearsamppTools->getRuby()->isEnable()) {
432 $value .= $bearsamppTools->getRuby()->getSymlinkPath() . '/bin;';
433 }
434 $value = UtilPath::formatWindowsPath($value);
435 Log::debug('Generated app bins reg key: ' . $value);
436 }
437
438 return $value;
439 }
440
448 public static function setAppBinsRegKey($value)
449 {
450 global $bearsamppRegistry;
451
452 return $bearsamppRegistry->setStringValue(
456 $value
457 );
458 }
459
465 public static function getAppPathRegKey()
466 {
467 global $bearsamppRegistry;
468
469 return $bearsamppRegistry->getValue(
473 );
474 }
475
483 public static function setAppPathRegKey($value)
484 {
485 global $bearsamppRegistry;
486
487 return $bearsamppRegistry->setStringValue(
491 $value
492 );
493 }
494
500 public static function getSysPathRegKey()
501 {
502 global $bearsamppRegistry;
503
504 return $bearsamppRegistry->getValue(
508 );
509 }
510
518 public static function setSysPathRegKey($value)
519 {
520 global $bearsamppRegistry;
521
522 return $bearsamppRegistry->setExpandStringValue(
526 $value
527 );
528 }
529
535 public static function getProcessorRegKey()
536 {
537 global $bearsamppRegistry;
538
539 return $bearsamppRegistry->getValue(
543 );
544 }
545
551 public static function getStartupLnkPath()
552 {
553 $startupPath = Win32Native::getSpecialFolderPath('Startup');
554 return $startupPath ? $startupPath . '/' . APP_TITLE . '.lnk' : false;
555 }
556
562 public static function isLaunchStartup()
563 {
565 return $lnk ? file_exists($lnk) : false;
566 }
567
573 public static function enableLaunchStartup()
574 {
576
577 $shortcutPath = self::getStartupLnkPath();
578 if (!$shortcutPath) {
579 return false;
580 }
581
582 $targetPath = $bearsamppRoot->getExeFilePath();
583 $workingDir = $bearsamppRoot->getRootPath();
584 $description = APP_TITLE . ' ' . $bearsamppCore->getAppVersion();
585 $iconPath = $bearsamppCore->getIconsPath() . '/app.ico';
586
587 return Win32Native::createShortcut($shortcutPath, $targetPath, $workingDir, $description, $iconPath);
588 }
589
595 public static function disableLaunchStartup()
596 {
597 $startupLnkPath = self::getStartupLnkPath();
598
599 // Check if file exists before attempting to delete
600 if (file_exists($startupLnkPath)) {
601 return @unlink($startupLnkPath);
602 }
603
604 // Return true if the file doesn't exist (already disabled)
605 return true;
606 }
607
613 public static function getPowerShellPath()
614 {
615 if (is_dir('C:\Windows\System32\WindowsPowerShell')) {
616 return self::findFile('C:\Windows\System32\WindowsPowerShell', 'powershell.exe');
617 }
618
619 return false;
620 }
621
632 public static function findRepos($initPath, $startPath, $checkFile, $maxDepth = 1)
633 {
634 $depth = substr_count(str_replace($initPath, '', $startPath), '/');
635 $result = array();
636
637 $handle = @opendir($startPath);
638 if (!$handle) {
639 return $result;
640 }
641
642 while (false !== ($file = readdir($handle))) {
643 if ($file == '.' || $file == '..') {
644 continue;
645 }
646 if (is_dir($startPath . '/' . $file) && ($initPath == $startPath || $depth <= $maxDepth)) {
647 $tmpResults = self::findRepos($initPath, $startPath . '/' . $file, $checkFile, $maxDepth);
648 foreach ($tmpResults as $tmpResult) {
649 $result[] = $tmpResult;
650 }
651 } elseif (is_file($startPath . '/' . $checkFile) && !in_array($startPath, $result)) {
652 $result[] = UtilPath::formatUnixPath($startPath);
653 }
654 }
655
656 closedir($handle);
657
658 return $result;
659 }
660
668 public static function imgToBase64($path)
669 {
670 $type = pathinfo($path, PATHINFO_EXTENSION);
671 $data = file_get_contents($path);
672
673 return 'data:image/' . $type . ';base64,' . base64_encode($data);
674 }
675
684 public static function convertEncoding($data, $direction = 'to_cp1252')
685 {
686 if ($direction === 'to_utf8') {
687 return self::cp1252ToUtf8($data);
688 } else {
689 return self::utf8ToCp1252($data);
690 }
691 }
692
700 public static function utf8ToCp1252($data)
701 {
702 return iconv('UTF-8', 'WINDOWS-1252//IGNORE', $data);
703 }
704
712 public static function cp1252ToUtf8($data)
713 {
714 return iconv('WINDOWS-1252', 'UTF-8//IGNORE', $data);
715 }
716
720 public static function startLoading()
721 {
722 global $bearsamppCore, $bearsamppWinbinder;
723
724 Log::trace('startLoading() called');
725 Log::trace('PHP executable: ' . $bearsamppCore->getPhpExe());
726 Log::trace('Root file: ' . Core::isRoot_FILE);
727 Log::trace('Action: ' . Action::LOADING);
728
729 $command = Core::isRoot_FILE . ' ' . Action::LOADING;
730 Log::trace('Executing command: ' . $bearsamppCore->getPhpExe() . ' ' . $command);
731
732 $result = $bearsamppWinbinder->exec($bearsamppCore->getPhpExe(), $command);
733 Log::trace('exec() returned: ' . var_export($result, true));
734
735 Log::trace('startLoading() completed');
736 }
737
741 public static function stopLoading()
742 {
743 global $bearsamppCore;
744 if (file_exists($bearsamppCore->getLoadingPid())) {
745 $pids = file($bearsamppCore->getLoadingPid());
746 foreach ($pids as $pid) {
747 Win32Ps::kill($pid);
748 }
749 @unlink($bearsamppCore->getLoadingPid());
750 }
751
752 // Clean up status file
754 }
755
762 public static function updateLoadingText($text)
763 {
764 global $bearsamppCore;
765
766 $statusFile = $bearsamppCore->getTmpPath() . '/loading_status.txt';
767 file_put_contents($statusFile, json_encode(['text' => $text]));
768 }
769
773 public static function clearLoadingText()
774 {
775 global $bearsamppCore;
776
777 $statusFile = $bearsamppCore->getTmpPath() . '/loading_status.txt';
778 if (file_exists($statusFile)) {
779 @unlink($statusFile);
780 }
781 }
782
793 public static function getFilesToScan($path = null, $useCache = true, $forceRefresh = false)
794 {
795 // Generate cache key based on path parameter
796 $cacheKey = md5(serialize($path));
797
798 // Try to get from cache if enabled and not forcing refresh
799 if ($useCache && !$forceRefresh) {
800 $cachedResult = self::getFileScanCache($cacheKey);
801 if ($cachedResult !== false) {
802 self::$fileScanStats['hits']++;
803 Log::debug('File scan cache HIT (saved expensive scan operation)');
804 return $cachedResult;
805 }
806 }
807
808 self::$fileScanStats['misses']++;
809 Log::debug('File scan cache MISS (performing full scan)');
810
811 // Perform the actual scan
812 $startTime = self::getMicrotime();
813 $result = array();
814 $pathsToScan = !empty($path) ? $path : self::getPathsToScan();
815
816 foreach ($pathsToScan as $pathToScan) {
817 $pathStartTime = self::getMicrotime();
818 $findFiles = self::findFiles($pathToScan['path'], $pathToScan['includes'], $pathToScan['recursive']);
819 foreach ($findFiles as $findFile) {
820 $result[] = $findFile;
821 }
822 Log::debug($pathToScan['path'] . ' scanned in ' . round(self::getMicrotime() - $pathStartTime, 3) . 's');
823 }
824
825 $totalTime = round(self::getMicrotime() - $startTime, 3);
826 Log::info('Full file scan completed in ' . $totalTime . 's (' . count($result) . ' files found)');
827
828 // Store in cache if enabled
829 if ($useCache) {
831 }
832
833 return $result;
834 }
835
844 private static function getFileScanCache($cacheKey)
845 {
846 global $bearsamppRoot;
847
848 // Check if we have in-memory cache first
849 if (self::$fileScanCache !== null && isset(self::$fileScanCache[$cacheKey])) {
850 $cache = self::$fileScanCache[$cacheKey];
851
852 // Check if cache is still valid
853 if (time() - $cache['timestamp'] < self::$fileScanCacheDuration) {
854 return $cache['data'];
855 } else {
856 self::$fileScanStats['invalidations']++;
857 unset(self::$fileScanCache[$cacheKey]);
858 }
859 }
860
861 // Try to load from file cache
862 if (!isset($bearsamppRoot)) {
863 return false;
864 }
865
866 $cacheFile = $bearsamppRoot->getTmpPath() . '/filescan_cache_' . $cacheKey . '.dat';
867
868 if (file_exists($cacheFile)) {
869 $fileContents = @file_get_contents($cacheFile);
870
871 if ($fileContents === false) {
872 return false;
873 }
874
875 // Verify file integrity before unserializing
876 if (!self::verifyCacheIntegrity($fileContents, $cacheKey)) {
877 Log::warning('File scan cache integrity check failed for key: ' . $cacheKey . '. Possible tampering detected.');
878 @unlink($cacheFile);
879 return false;
880 }
881
882 $cacheData = @unserialize($fileContents);
883
884 if ($cacheData !== false && isset($cacheData['timestamp']) && isset($cacheData['data']) && isset($cacheData['hmac'])) {
885 // Check if file cache is still valid
886 if (time() - $cacheData['timestamp'] < self::$fileScanCacheDuration) {
887 // Store in memory cache for faster subsequent access
888 if (self::$fileScanCache === null) {
889 self::$fileScanCache = [];
890 }
891 self::$fileScanCache[$cacheKey] = $cacheData;
892
893 return $cacheData['data'];
894 } else {
895 // Cache expired, delete file
896 self::$fileScanStats['invalidations']++;
897 @unlink($cacheFile);
898 }
899 } else {
900 // Invalid cache structure, delete file
901 Log::warning('Invalid cache structure detected for key: ' . $cacheKey);
902 @unlink($cacheFile);
903 }
904 }
905
906 return false;
907 }
908
917 private static function setFileScanCache($cacheKey, $data)
918 {
919 global $bearsamppRoot;
920
921 // Generate HMAC for integrity verification
922 $hmac = self::generateCacheHMAC($data, $cacheKey);
923
924 $cacheData = [
925 'timestamp' => time(),
926 'data' => $data,
927 'hmac' => $hmac
928 ];
929
930 // Store in memory cache
931 if (self::$fileScanCache === null) {
932 self::$fileScanCache = [];
933 }
934 self::$fileScanCache[$cacheKey] = $cacheData;
935
936 // Store in file cache
937 if (isset($bearsamppRoot)) {
938 $cacheFile = $bearsamppRoot->getTmpPath() . '/filescan_cache_' . $cacheKey . '.dat';
939 @file_put_contents($cacheFile, serialize($cacheData), LOCK_EX);
940 Log::debug('File scan results cached to: ' . $cacheFile);
941 }
942 }
943
950 private static function getCacheIntegrityKey()
951 {
952 if (self::$cacheIntegrityKey === null) {
953 global $bearsamppRoot;
954
955 // Try to load existing key from session file
956 if (isset($bearsamppRoot)) {
957 $keyFile = $bearsamppRoot->getTmpPath() . '/cache_integrity.key';
958
959 if (file_exists($keyFile)) {
960 $key = @file_get_contents($keyFile);
961 if ($key !== false && strlen($key) === 64) {
962 self::$cacheIntegrityKey = $key;
963 return self::$cacheIntegrityKey;
964 }
965 }
966
967 // Generate new key if none exists or invalid
968 try {
969 self::$cacheIntegrityKey = bin2hex(random_bytes(32));
970 @file_put_contents($keyFile, self::$cacheIntegrityKey, LOCK_EX);
971 } catch (Exception $e) {
972 Log::error('Failed to generate cache integrity key: ' . $e->getMessage());
973 // Fallback to a less secure but functional key
974 self::$cacheIntegrityKey = hash('sha256', uniqid('bearsampp_cache_', true));
975 }
976 } else {
977 // Fallback if bearsamppRoot not available
978 try {
979 self::$cacheIntegrityKey = bin2hex(random_bytes(32));
980 } catch (Exception $e) {
981 self::$cacheIntegrityKey = hash('sha256', uniqid('bearsampp_cache_', true));
982 }
983 }
984 }
985
986 return self::$cacheIntegrityKey;
987 }
988
997 private static function generateCacheHMAC($data, $cacheKey)
998 {
1000 $message = serialize($data) . $cacheKey;
1001 return hash_hmac('sha256', $message, $key);
1002 }
1003
1012 private static function verifyCacheIntegrity($fileContents, $cacheKey)
1013 {
1014 $cacheData = @unserialize($fileContents);
1015
1016 if ($cacheData === false || !isset($cacheData['hmac']) || !isset($cacheData['data'])) {
1017 return false;
1018 }
1019
1020 $expectedHmac = self::generateCacheHMAC($cacheData['data'], $cacheKey);
1021
1022 // Use hash_equals to prevent timing attacks
1023 return hash_equals($expectedHmac, $cacheData['hmac']);
1024 }
1025
1031 public static function clearFileScanCache()
1032 {
1033 global $bearsamppRoot;
1034
1035 // Clear memory cache
1036 self::$fileScanCache = null;
1037
1038 // Clear file caches
1039 if (isset($bearsamppRoot)) {
1040 $tmpPath = $bearsamppRoot->getTmpPath();
1041 $cacheFiles = glob($tmpPath . '/filescan_cache_*.dat');
1042
1043 if ($cacheFiles !== false) {
1044 foreach ($cacheFiles as $cacheFile) {
1045 @unlink($cacheFile);
1046 }
1047 Log::info('Cleared ' . count($cacheFiles) . ' file scan cache files');
1048 }
1049 }
1050
1051 // Reset stats
1052 self::$fileScanStats = [
1053 'hits' => 0,
1054 'misses' => 0,
1055 'invalidations' => 0
1056 ];
1057 }
1058
1064 public static function getFileScanStats()
1065 {
1066 return self::$fileScanStats;
1067 }
1068
1076 public static function setFileScanCacheDuration($seconds)
1077 {
1078 if ($seconds > 0 && $seconds <= 86400) { // Max 24 hours
1079 self::$fileScanCacheDuration = $seconds;
1080 Log::debug('File scan cache duration set to ' . $seconds . ' seconds');
1081 }
1082 }
1083
1089 public static function getFileScanCacheDuration()
1090 {
1091 return self::$fileScanCacheDuration;
1092 }
1093
1118 private static function getPathsToScan()
1119 {
1120 global $bearsamppRoot, $bearsamppCore, $bearsamppBins, $bearsamppApps, $bearsamppTools;
1121 $paths = array();
1122
1123 // Alias
1124 $paths[] = array(
1125 'path' => $bearsamppRoot->getAliasPath(),
1126 'includes' => array(''),
1127 'recursive' => false
1128 );
1129
1130 // Vhosts
1131 $paths[] = array(
1132 'path' => $bearsamppRoot->getVhostsPath(),
1133 'includes' => array(''),
1134 'recursive' => false
1135 );
1136
1137 // OpenSSL
1138 $paths[] = array(
1139 'path' => $bearsamppCore->getOpenSslPath(),
1140 'includes' => array('openssl.cfg'),
1141 'recursive' => false
1142 );
1143
1144 // Homepage
1145 $paths[] = array(
1146 'path' => $bearsamppCore->getResourcesPath() . '/homepage',
1147 'includes' => array('alias.conf'),
1148 'recursive' => false
1149 );
1150
1151 // Apache
1152 $folderList = self::getFolderList($bearsamppBins->getApache()->getRootPath());
1153 foreach ($folderList as $folder) {
1154 $paths[] = array(
1155 'path' => $bearsamppBins->getApache()->getRootPath() . '/' . $folder,
1156 'includes' => array('.ini', '.conf'),
1157 'recursive' => true
1158 );
1159 }
1160
1161 // PHP
1162 $folderList = self::getFolderList($bearsamppBins->getPhp()->getRootPath());
1163 foreach ($folderList as $folder) {
1164 $paths[] = array(
1165 'path' => $bearsamppBins->getPhp()->getRootPath() . '/' . $folder,
1166 'includes' => array('.php', '.bat', '.ini', '.reg', '.inc'),
1167 'recursive' => true
1168 );
1169 }
1170
1171 // MySQL
1172 $folderList = self::getFolderList($bearsamppBins->getMysql()->getRootPath());
1173 foreach ($folderList as $folder) {
1174 $paths[] = array(
1175 'path' => $bearsamppBins->getMysql()->getRootPath() . '/' . $folder,
1176 'includes' => array('my.ini'),
1177 'recursive' => false
1178 );
1179 }
1180
1181 // MariaDB
1182 $folderList = self::getFolderList($bearsamppBins->getMariadb()->getRootPath());
1183 foreach ($folderList as $folder) {
1184 $paths[] = array(
1185 'path' => $bearsamppBins->getMariadb()->getRootPath() . '/' . $folder,
1186 'includes' => array('my.ini'),
1187 'recursive' => false
1188 );
1189 // Also scan data directory for my.ini (created during initialization)
1190 $dataPath = $bearsamppBins->getMariadb()->getRootPath() . '/' . $folder . '/data';
1191 if (is_dir($dataPath)) {
1192 $paths[] = array(
1193 'path' => $dataPath,
1194 'includes' => array('my.ini'),
1195 'recursive' => false
1196 );
1197 }
1198 }
1199
1200 // PostgreSQL
1201 $folderList = self::getFolderList($bearsamppBins->getPostgresql()->getRootPath());
1202 foreach ($folderList as $folder) {
1203 $paths[] = array(
1204 'path' => $bearsamppBins->getPostgresql()->getRootPath() . '/' . $folder,
1205 'includes' => array( '.conf', '.bat', '.ber'),
1206 'recursive' => true
1207 );
1208 }
1209
1210 // Node.js
1211 $folderList = self::getFolderList($bearsamppBins->getNodejs()->getRootPath());
1212 foreach ($folderList as $folder) {
1213 $paths[] = array(
1214 'path' => $bearsamppBins->getNodejs()->getRootPath() . '/' . $folder . '/etc',
1215 'includes' => array('npmrc'),
1216 'recursive' => true
1217 );
1218 $paths[] = array(
1219 'path' => $bearsamppBins->getNodejs()->getRootPath() . '/' . $folder . '/node_modules/npm',
1220 'includes' => array('npmrc'),
1221 'recursive' => false
1222 );
1223 }
1224
1225 // Composer
1226 $folderList = self::getFolderList($bearsamppTools->getComposer()->getRootPath());
1227 foreach ($folderList as $folder) {
1228 $paths[] = array(
1229 'path' => $bearsamppTools->getComposer()->getRootPath() . '/' . $folder,
1230 'includes' => array('giscus.json'),
1231 'recursive' => false
1232 );
1233 }
1234
1235 // PowerShell
1236 $folderList = self::getFolderList($bearsamppTools->getPowerShell()->getRootPath());
1237 foreach ($folderList as $folder) {
1238 $paths[] = array(
1239 'path' => $bearsamppTools->getPowerShell()->getRootPath() . '/' . $folder,
1240 'includes' => array('console.xml', '.ini', '.btm'),
1241 'recursive' => true
1242 );
1243 }
1244
1245 // Python
1246 $folderList = self::getFolderList($bearsamppTools->getPython()->getRootPath());
1247 foreach ($folderList as $folder) {
1248 $paths[] = array(
1249 'path' => $bearsamppTools->getPython()->getRootPath() . '/' . $folder . '/bin',
1250 'includes' => array('.bat'),
1251 'recursive' => false
1252 );
1253 $paths[] = array(
1254 'path' => $bearsamppTools->getPython()->getRootPath() . '/' . $folder . '/settings',
1255 'includes' => array('winpython.ini'),
1256 'recursive' => false
1257 );
1258 }
1259
1260 // Ruby
1261 $folderList = self::getFolderList($bearsamppTools->getRuby()->getRootPath());
1262 foreach ($folderList as $folder) {
1263 $paths[] = array(
1264 'path' => $bearsamppTools->getRuby()->getRootPath() . '/' . $folder . '/bin',
1265 'includes' => array('!.dll', '!.exe'),
1266 'recursive' => false
1267 );
1268 }
1269
1270 return $paths;
1271 }
1272
1282 private static function findFiles($startPath, $includes = array(''), $recursive = true)
1283 {
1284 $result = array();
1285
1286 $handle = @opendir($startPath);
1287 if (!$handle) {
1288 return $result;
1289 }
1290
1291 while (false !== ($file = readdir($handle))) {
1292 if ($file == '.' || $file == '..') {
1293 continue;
1294 }
1295 if (is_dir($startPath . '/' . $file) && $recursive) {
1296 $tmpResults = self::findFiles($startPath . '/' . $file, $includes);
1297 foreach ($tmpResults as $tmpResult) {
1298 $result[] = $tmpResult;
1299 }
1300 } elseif (is_file($startPath . '/' . $file)) {
1301 foreach ($includes as $include) {
1302 if (UtilString::startWith($include, '!')) {
1303 $include = ltrim($include, '!');
1304 if (UtilString::startWith($file, '.') && !UtilString::endWith($file, $include)) {
1305 $result[] = UtilPath::formatUnixPath($startPath . '/' . $file);
1306 } elseif ($file != $include) {
1307 $result[] = UtilPath::formatUnixPath($startPath . '/' . $file);
1308 }
1309 } elseif (UtilString::endWith($file, $include) || $file == $include || empty($include)) {
1310 $result[] = UtilPath::formatUnixPath($startPath . '/' . $file);
1311 }
1312 }
1313 }
1314 }
1315
1316 closedir($handle);
1317
1318 return $result;
1319 }
1320
1329 public static function changePath($filesToScan, $rootPath = null)
1330 {
1332
1333 $result = array(
1334 'countChangedOcc' => 0,
1335 'countChangedFiles' => 0
1336 );
1337
1338 $rootPath = $rootPath != null ? $rootPath : $bearsamppRoot->getRootPath();
1339 $unixOldPath = UtilPath::formatUnixPath($bearsamppCore->getLastPathContent());
1340 $windowsOldPath = UtilPath::formatWindowsPath($bearsamppCore->getLastPathContent());
1341 $unixCurrentPath = UtilPath::formatUnixPath($rootPath);
1342 $windowsCurrentPath = UtilPath::formatWindowsPath($rootPath);
1343
1344 foreach ($filesToScan as $fileToScan) {
1345 $tmpCountChangedOcc = 0;
1346 $fileContentOr = file_get_contents($fileToScan);
1347 $fileContent = $fileContentOr;
1348
1349 // old path
1350 preg_match('#' . $unixOldPath . '#i', $fileContent, $unixMatches);
1351 if (!empty($unixMatches)) {
1352 $fileContent = str_replace($unixOldPath, $unixCurrentPath, $fileContent, $countChanged);
1353 $tmpCountChangedOcc += $countChanged;
1354 }
1355 preg_match('#' . str_replace('\\', '\\\\', $windowsOldPath) . '#i', $fileContent, $windowsMatches);
1356 if (!empty($windowsMatches)) {
1357 $fileContent = str_replace($windowsOldPath, $windowsCurrentPath, $fileContent, $countChanged);
1358 $tmpCountChangedOcc += $countChanged;
1359 }
1360
1361 // placeholders
1362 preg_match('#' . Core::PATH_LIN_PLACEHOLDER . '#i', $fileContent, $unixMatches);
1363 if (!empty($unixMatches)) {
1364 $fileContent = str_replace(Core::PATH_LIN_PLACEHOLDER, $unixCurrentPath, $fileContent, $countChanged);
1365 $tmpCountChangedOcc += $countChanged;
1366 }
1367 preg_match('#' . Core::PATH_WIN_PLACEHOLDER . '#i', $fileContent, $windowsMatches);
1368 if (!empty($windowsMatches)) {
1369 $fileContent = str_replace(Core::PATH_WIN_PLACEHOLDER, $windowsCurrentPath, $fileContent, $countChanged);
1370 $tmpCountChangedOcc += $countChanged;
1371 }
1372
1373 if ($fileContentOr != $fileContent) {
1374 $result['countChangedOcc'] += $tmpCountChangedOcc;
1375 $result['countChangedFiles'] += 1;
1376 file_put_contents($fileToScan, $fileContent);
1377 }
1378 }
1379
1380 Log::debug('changePath() completed: ' . $result['countChangedFiles'] . ' files changed, ' . $result['countChangedOcc'] . ' total occurrences');
1381
1382 return $result;
1383 }
1384
1392 public static function getLatestVersion($url)
1393 {
1394 $responseData = self::getApiJson($url);
1395
1396 if (empty($responseData)) {
1397 Log::error('Cannot retrieve latest github info: empty result or error');
1398 return null;
1399 }
1400
1401 // Now decode the JSON string
1402 $resultArray = json_decode($responseData, true);
1403
1404 if (isset($resultArray['tag_name']) && isset($resultArray['assets'][0]['browser_download_url'])) {
1405 $tagName = $resultArray['tag_name'];
1406 $downloadUrl = $resultArray['assets'][0]['browser_download_url'];
1407 $name = $resultArray['name'];
1408 Log::debug('Latest version tag name: ' . $tagName);
1409 Log::debug('Download URL: ' . $downloadUrl);
1410 Log::debug('Name: ' . $name);
1411
1412 return ['version' => $tagName, 'html_url' => $downloadUrl, 'name' => $name];
1413 } else {
1414 Log::error('Tag name, download URL, or name not found in the response');
1415 return null;
1416 }
1417 }
1418
1428 public static function getWebsiteUrl($path = '', $fragment = '', $utmSource = true)
1429 {
1430 global $bearsamppCore;
1431
1432 $url = APP_WEBSITE;
1433 if (!empty($path)) {
1434 $url .= '/' . ltrim($path, '/');
1435 }
1436 if ($utmSource) {
1437 $url = rtrim($url, '/') . '/?utm_source=bearsampp-' . $bearsamppCore->getAppVersion();
1438 }
1439 if (!empty($fragment)) {
1440 $url .= $fragment;
1441 }
1442
1443 return $url;
1444 }
1445
1454 public static function getWebsiteUrlNoUtm($path = '', $fragment = '')
1455 {
1456 return self::getWebsiteUrl($path, $fragment, false);
1457 }
1458
1466 public static function getChangelogUrl($utmSource = true)
1467 {
1468 return self::getWebsiteUrl('doc/changelog', null, $utmSource);
1469 }
1470
1479 public static function getRemoteFilesize($url, $humanFileSize = true)
1480 {
1481 $size = 0;
1482
1483 $data = get_headers($url, true);
1484 if (isset($data['Content-Length'])) {
1485 $size = intval($data['Content-Length']);
1486 }
1487
1488 return $humanFileSize ? self::humanFileSize($size) : $size;
1489 }
1490
1499 public static function humanFileSize($size, $unit = '')
1500 {
1501 if ((!$unit && $size >= 1 << 30) || $unit == 'GB') {
1502 return number_format($size / (1 << 30), 2) . 'GB';
1503 }
1504 if ((!$unit && $size >= 1 << 20) || $unit == 'MB') {
1505 return number_format($size / (1 << 20), 2) . 'MB';
1506 }
1507 if ((!$unit && $size >= 1 << 10) || $unit == 'KB') {
1508 return number_format($size / (1 << 10), 2) . 'KB';
1509 }
1510
1511 return number_format($size) . ' bytes';
1512 }
1513
1519 public static function is32BitsOs()
1520 {
1521 $processor = self::getProcessorRegKey();
1522
1523 return UtilString::contains($processor, 'x86');
1524 }
1525
1539 public static function getHeaders($host, $port, $ssl = false)
1540 {
1541 $result = array();
1542 $context = stream_context_create(array(
1543 'ssl' => array(
1544 'verify_peer' => true,
1545 'verify_peer_name' => true,
1546 'allow_self_signed' => false,
1547 )
1548 ));
1549
1550 $fp = @stream_socket_client(($ssl ? 'ssl://' : '') . $host . ':' . $port, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $context);
1551 if ($fp) {
1552 $out = fgets($fp);
1553 $result = explode(PHP_EOL, $out);
1554 @fclose($fp);
1555 }
1556
1557 if (!empty($result)) {
1558 $rebuildResult = array();
1559 foreach ($result as $row) {
1560 $row = trim($row);
1561 if (!empty($row)) {
1562 $rebuildResult[] = $row;
1563 }
1564 }
1565 $result = $rebuildResult;
1566
1567 Log::debug('getHeaders:');
1568 foreach ($result as $header) {
1569 Log::debug('-> ' . $header);
1570 }
1571 }
1572
1573 return $result;
1574 }
1575
1583 public static function getApiJson($url)
1584 {
1586
1587 if (isset($result['error'])) {
1588 return null;
1589 }
1590
1591 return isset($result['data']) ? $result['data'] : null;
1592 }
1593
1601 public static function isPortInUse($port)
1602 {
1603 // Set localIP statically
1604 $localIP = '127.0.0.1';
1605
1606 // Save current error reporting level
1607 $errorReporting = error_reporting();
1608
1609 // Disable error reporting temporarily
1610 error_reporting(0);
1611
1612 $connection = @fsockopen($localIP, $port);
1613
1614 // Restore original error reporting level
1615 error_reporting($errorReporting);
1616
1617 if (is_resource($connection)) {
1618 fclose($connection);
1620
1621 return $process != null ? $process : 'N/A';
1622 }
1623
1624 return false;
1625 }
1626
1634 public static function isValidDomainName($domainName)
1635 {
1636 // This will return the string if valid, or FALSE if not.
1637 // It checks syntax rules (RFC 1034/1035) but doesn't check if the domain is "real."
1638 $isValidSyntax = filter_var($domainName, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
1639
1640 return $isValidSyntax;
1641 }
1642
1653 public static function installService($bin, $port, $syntaxCheckCmd, $showWindow = false)
1654 {
1655 global $bearsamppLang, $bearsamppWinbinder;
1656
1657 if (method_exists($bin, 'initData')) {
1658 $bin->initData();
1659 }
1660
1661 $name = $bin->getName();
1662 $service = $bin->getService();
1663 $boxTitle = sprintf($bearsamppLang->getValue(Lang::INSTALL_SERVICE_TITLE), $name);
1664
1665 $isPortInUse = self::isPortInUse($port);
1666 if ($isPortInUse === false) {
1667 if (!$service->isInstalled()) {
1668 $service->create();
1669 if ($service->start()) {
1670 Log::info(sprintf('%s service successfully installed. (name: %s ; port: %s)', $name, $service->getName(), $port));
1671 if ($showWindow) {
1672 $bearsamppWinbinder->messageBoxInfo(
1673 sprintf($bearsamppLang->getValue(Lang::SERVICE_INSTALLED), $name, $service->getName(), $port),
1674 $boxTitle
1675 );
1676 }
1677
1678 return true;
1679 } else {
1680 $serviceError = sprintf($bearsamppLang->getValue(Lang::SERVICE_INSTALL_ERROR), $name);
1681 $serviceErrorLog = sprintf('Error during the installation of %s service', $name);
1682 if (!empty($syntaxCheckCmd)) {
1683 $cmdSyntaxCheck = $bin->getCmdLineOutput($syntaxCheckCmd);
1684 if (!$cmdSyntaxCheck['syntaxOk']) {
1685 $serviceError .= PHP_EOL . sprintf($bearsamppLang->getValue(Lang::STARTUP_SERVICE_SYNTAX_ERROR), $cmdSyntaxCheck['content']);
1686 $serviceErrorLog .= sprintf(' (conf errors detected : %s)', $cmdSyntaxCheck['content']);
1687 }
1688 }
1689 Log::error($serviceErrorLog);
1690 if ($showWindow) {
1691 $bearsamppWinbinder->messageBoxError($serviceError, $boxTitle);
1692 }
1693 }
1694 } else {
1695 Log::warning(sprintf('%s service already installed', $name));
1696 if ($showWindow) {
1697 $bearsamppWinbinder->messageBoxWarning(
1698 sprintf($bearsamppLang->getValue(Lang::SERVICE_ALREADY_INSTALLED), $name),
1699 $boxTitle
1700 );
1701 }
1702
1703 return true;
1704 }
1705 } elseif ($service->isRunning()) {
1706 Log::warning(sprintf('%s service already installed and running', $name));
1707 if ($showWindow) {
1708 $bearsamppWinbinder->messageBoxWarning(
1709 sprintf($bearsamppLang->getValue(Lang::SERVICE_ALREADY_INSTALLED), $name),
1710 $boxTitle
1711 );
1712 }
1713
1714 return true;
1715 } else {
1716 Log::error(sprintf('Port %s is used by an other application : %s', $port, $isPortInUse));
1717 if ($showWindow) {
1718 $bearsamppWinbinder->messageBoxError(
1719 sprintf($bearsamppLang->getValue(Lang::PORT_NOT_USED_BY), $port, $isPortInUse),
1720 $boxTitle
1721 );
1722 }
1723 }
1724
1725 return false;
1726 }
1727
1736 public static function removeService($service, $name)
1737 {
1738 if (!($service instanceof Win32Service)) {
1739 Log::error('$service not an instance of Win32Service');
1740
1741 return false;
1742 }
1743
1744 if ($service->isInstalled()) {
1745 if ($service->delete()) {
1746 Log::info(sprintf('%s service successfully removed', $name));
1747
1748 return true;
1749 } else {
1750 Log::error(sprintf('Error during the uninstallation of %s service', $name));
1751
1752 return false;
1753 }
1754 } else {
1755 Log::warning(sprintf('%s service does not exist', $name));
1756 }
1757
1758 return true;
1759 }
1760
1770 public static function startService($bin, $syntaxCheckCmd, $showWindow = false)
1771 {
1772 global $bearsamppLang, $bearsamppWinbinder;
1773
1774 if (method_exists($bin, 'initData')) {
1775 $bin->initData();
1776 }
1777
1778 $name = $bin->getName();
1779 $service = $bin->getService();
1780 $boxTitle = sprintf($bearsamppLang->getValue(Lang::START_SERVICE_TITLE), $name);
1781
1782 if (!$service->start()) {
1783 $serviceError = sprintf($bearsamppLang->getValue(Lang::START_SERVICE_ERROR), $name);
1784 $serviceErrorLog = sprintf('Error while starting the %s service', $name);
1785 if (!empty($syntaxCheckCmd)) {
1786 $cmdSyntaxCheck = $bin->getCmdLineOutput($syntaxCheckCmd);
1787 if (!$cmdSyntaxCheck['syntaxOk']) {
1788 $serviceError .= PHP_EOL . sprintf($bearsamppLang->getValue(Lang::STARTUP_SERVICE_SYNTAX_ERROR), $cmdSyntaxCheck['content']);
1789 $serviceErrorLog .= sprintf(' (conf errors detected : %s)', $cmdSyntaxCheck['content']);
1790 }
1791 }
1792 Log::error($serviceErrorLog);
1793 if ($showWindow) {
1794 $bearsamppWinbinder->messageBoxError($serviceError, $boxTitle);
1795 }
1796
1797 return false;
1798 }
1799
1800 return true;
1801 }
1802
1813 public static function getGithubUrl($type = 'user', $user = APP_GITHUB_USER, $repo = null, $branch = null, $path = null) {
1814 if (empty($user) || !is_string($user)) {
1815 return false;
1816 }
1817
1818 // Encode as URL path segment (not query encoding)
1819 $user = rawurlencode($user);
1820
1821 switch ($type) {
1822 case 'user':
1823 return "https://github.com/{$user}";
1824
1825 case 'repo':
1826 if (empty($repo) || !is_string($repo)) {
1827 return false;
1828 }
1829 $repo = rawurlencode($repo);
1830 return "https://github.com/{$user}/{$repo}";
1831
1832 case 'raw':
1833 if (empty($repo) || empty($branch) || empty($path) || !is_string($repo) || !is_string($branch) || !is_string($path)) {
1834 return false;
1835 }
1836 $repo = rawurlencode($repo);
1837 $branch = rawurlencode($branch);
1838
1839 $path = ltrim($path, '/');
1840 $segments = array_map('rawurlencode', explode('/', $path));
1841 $pathEncoded = implode('/', $segments);
1842
1843 return "https://raw.githubusercontent.com/{$user}/{$repo}/{$branch}/{$pathEncoded}";
1844
1845 default:
1846 return false;
1847 }
1848 }
1849
1855 public static function getGithubUserUrl()
1856 {
1857 return self::getGithubUrl('user', APP_GITHUB_USER);
1858 }
1859
1867 public static function getFolderList($path)
1868 {
1869 $result = array();
1870
1871 $handle = @opendir($path);
1872 if (!$handle) {
1873 return false;
1874 }
1875
1876 while (false !== ($file = readdir($handle))) {
1877 $filePath = $path . '/' . $file;
1878 if ($file != '.' && $file != '..' && is_dir($filePath) && $file != 'current') {
1879 $result[] = $file;
1880 }
1881 }
1882
1883 closedir($handle);
1884 natcasesort($result);
1885
1886 return $result;
1887 }
1888
1897 public static function openFileContent($caption, $content)
1898 {
1900
1901 $tmpFile = $bearsamppCore->getTmpPath() . '/' . $caption . '.txt';
1902 file_put_contents($tmpFile, $content);
1903
1904 // Open the file with the configured editor from bearsampp.conf
1905 $editor = $bearsamppConfig->getNotepad();
1906 $bearsamppCore->getWinbinder()->exec($editor, '"' . $tmpFile . '"');
1907 }
1908}
$result
global $bearsamppBins
global $bearsamppLang
global $bearsamppRoot
$port
global $bearsamppCore
const LOADING
static getProcessUsingPort($port)
static shellExec(string $command)
const isRoot_FILE
const PATH_LIN_PLACEHOLDER
const PATH_WIN_PLACEHOLDER
static getApiJson($url, $headers=array())
const START_SERVICE_ERROR
const START_SERVICE_TITLE
const SERVICE_INSTALLED
const INSTALL_SERVICE_TITLE
const STARTUP_SERVICE_SYNTAX_ERROR
const SERVICE_INSTALL_ERROR
const SERVICE_ALREADY_INSTALLED
const PORT_NOT_USED_BY
static info($data, $file=null)
static debug($data, $file=null)
static warning($data, $file=null)
static trace($data, $file=null)
static error($data, $file=null)
const SYSPATH_REG_ENTRY
const PROCESSOR_REG_SUBKEY
const HKEY_LOCAL_MACHINE
const PROCESSOR_REG_ENTRY
const APP_PATH_REG_ENTRY
const APP_BINS_REG_ENTRY
static findRepos($initPath, $startPath, $checkFile, $maxDepth=1)
static isLaunchStartup()
static installService($bin, $port, $syntaxCheckCmd, $showWindow=false)
static getWebsiteUrlNoUtm($path='', $fragment='')
static $fileScanStats
static disableLaunchStartup()
static getRemoteFilesize($url, $humanFileSize=true)
static getGithubUrl($type='user', $user=APP_GITHUB_USER, $repo=null, $branch=null, $path=null)
static getMicrotime()
static deleteFolder($path)
static getHeaders($host, $port, $ssl=false)
static removeService($service, $name)
static setFileScanCacheDuration($seconds)
static isValidPort($port)
static cp1252ToUtf8($data)
static setAppPathRegKey($value)
static imgToBase64($path)
static getVersionList($path)
static utf8ToCp1252($data)
static isValidDomainName($domainName)
static getLatestVersion($url)
static getFolderList($path)
static getAppBinsRegKey($fromRegistry=true)
static getAppPathRegKey()
static getGithubUserUrl()
static getChangelogUrl($utmSource=true)
static openFileContent($caption, $content)
static $cacheIntegrityKey
static getCacheIntegrityKey()
static getFileScanStats()
static getFileScanCacheDuration()
static $fileScanCache
static humanFileSize($size, $unit='')
static clearLoadingText()
static $fileScanCacheDuration
static clearFileScanCache()
static getPathsToScan()
static startLoading()
static changePath($filesToScan, $rootPath=null)
static getWebsiteUrl($path='', $fragment='', $utmSource=true)
static isAdmin()
static isPortInUse($port)
static getApiJson($url)
static generateCacheHMAC($data, $cacheKey)
static findFiles($startPath, $includes=array(''), $recursive=true)
static getFilesToScan($path=null, $useCache=true, $forceRefresh=false)
static replaceDefine($path, $var, $value)
static clearFolder($path, $exclude=array())
static isValidIp($ip)
static convertEncoding($data, $direction='to_cp1252')
static stopLoading()
static is32BitsOs()
static setFileScanCache($cacheKey, $data)
static clearFolders($paths, $exclude=array())
static startService($bin, $syntaxCheckCmd, $showWindow=false)
static findFile($startPath, $findFile)
static getFileScanCache($cacheKey)
static updateLoadingText($text)
static enableLaunchStartup()
static getStartupLnkPath()
static setSysPathRegKey($value)
static replaceInFile($path, $replaceList)
static getSysPathRegKey()
static getPowerShellPath()
static getProcessorRegKey()
static setAppBinsRegKey($value)
static verifyCacheIntegrity($fileContents, $cacheKey)
static formatWindowsPath($path)
static formatUnixPath($path)
static contains($string, $search)
static startWith($string, $search)
static endWith($string, $search)
static createShortcut($shortcutPath, $targetPath, $workingDir='', $description='', $iconPath='')
static getSpecialFolderPath($folderName)
static kill($pid)
global $bearsamppConfig
Definition homepage.php:41
const APP_WEBSITE
Definition root.php:14
const APP_GITHUB_USER
Definition root.php:16
const APP_TITLE
Definition root.php:13