2024.8.23
Loading...
Searching...
No Matches
class.util.php
Go to the documentation of this file.
1<?php
2/*
3 * Copyright (c) 2021-2024 Bearsampp
4 * License: GNU General Public License version 3 or later; see LICENSE.txt
5 * Author: Bear
6 * Website: https://bearsampp.com
7 * Github: https://github.com/Bearsampp
8 */
9
10/**
11 * Utility class providing a wide range of static methods for various purposes including:
12 * - Cleaning and retrieving command line, GET, and POST variables based on type specifications.
13 * - String manipulation methods to check if strings contain, start with, or end with specified substrings.
14 * - File and directory management functions for deleting, clearing, or finding files and directories.
15 * - Logging functionalities tailored for different levels of verbosity (ERROR, WARNING, INFO, DEBUG, TRACE).
16 * - System utilities for handling registry operations, managing environment variables, and executing system commands.
17 * - Network utilities to validate IPs, domains, and manage HTTP requests.
18 * - Helper functions for encoding, decoding, and file operations.
19 *
20 * This class is designed to be used as a helper or utility class where methods are accessed statically.
21 * This means you do not need to instantiate it to use the methods, but can simply call them using the Util::methodName() syntax.
22 *
23 * Usage Example:
24 * ```
25 * $cleanedData = Util::cleanGetVar('data', 'text');
26 * Util::logError('An error occurred');
27 * $isAvailable = Util::isValidIp('192.168.1.1');
28 * ```
29 *
30 * Each method is self-contained and provides specific functionality, making this class a central point for
31 * common utility operations needed across a PHP application, especially in environments like web servers or command-line interfaces.
32 */
33class Util
34{
35 /**
36 * This code snippet defines constants for logging levels.
37 */
38 const LOG_ERROR = 'ERROR';
39 const LOG_WARNING = 'WARNING';
40 const LOG_INFO = 'INFO';
41 const LOG_DEBUG = 'DEBUG';
42 const LOG_TRACE = 'TRACE';
43
44 /**
45 * Cleans and returns a specific command line argument based on the type specified.
46 *
47 * @param string $name The index of the argument in the $_SERVER['argv'] array.
48 * @param string $type The type of the argument to return: 'text', 'numeric', 'boolean', or 'array'.
49 *
50 * @return mixed Returns the cleaned argument based on the type or false if the argument is not set.
51 */
52 public static function cleanArgv($name, $type = 'text')
53 {
54 if ( isset( $_SERVER['argv'] ) ) {
55 if ( $type == 'text' ) {
56 return (isset( $_SERVER['argv'][$name] ) && !empty( $_SERVER['argv'][$name] )) ? trim( $_SERVER['argv'][$name] ) : '';
57 }
58 elseif ( $type == 'numeric' ) {
59 return (isset( $_SERVER['argv'][$name] ) && is_numeric( $_SERVER['argv'][$name] )) ? intval( $_SERVER['argv'][$name] ) : '';
60 }
61 elseif ( $type == 'boolean' ) {
62 return (isset( $_SERVER['argv'][$name] )) ? true : false;
63 }
64 elseif ( $type == 'array' ) {
65 return (isset( $_SERVER['argv'][$name] ) && is_array( $_SERVER['argv'][$name] )) ? $_SERVER['argv'][$name] : array();
66 }
67 }
68
69 return false;
70 }
71
72 /**
73 * Cleans and returns a specific $_GET variable based on the type specified.
74 *
75 * @param string $name The name of the $_GET variable.
76 * @param string $type The type of the variable to return: 'text', 'numeric', 'boolean', or 'array'.
77 *
78 * @return mixed Returns the cleaned $_GET variable based on the type or false if the variable is not set.
79 */
80 public static function cleanGetVar($name, $type = 'text')
81 {
82 if ( is_string( $name ) ) {
83 if ( $type == 'text' ) {
84 return (isset( $_GET[$name] ) && !empty( $_GET[$name] )) ? stripslashes( $_GET[$name] ) : '';
85 }
86 elseif ( $type == 'numeric' ) {
87 return (isset( $_GET[$name] ) && is_numeric( $_GET[$name] )) ? intval( $_GET[$name] ) : '';
88 }
89 elseif ( $type == 'boolean' ) {
90 return (isset( $_GET[$name] )) ? true : false;
91 }
92 elseif ( $type == 'array' ) {
93 return (isset( $_GET[$name] ) && is_array( $_GET[$name] )) ? $_GET[$name] : array();
94 }
95 }
96
97 return false;
98 }
99
100 /**
101 * Cleans and returns a specific $_POST variable based on the type specified.
102 *
103 * @param string $name The name of the $_POST variable.
104 * @param string $type The type of the variable to return: 'text', 'number', 'float', 'boolean', 'array', or 'content'.
105 *
106 * @return mixed Returns the cleaned $_POST variable based on the type or false if the variable is not set.
107 */
108 public static function cleanPostVar($name, $type = 'text')
109 {
110 if ( is_string( $name ) ) {
111 if ( $type == 'text' ) {
112 return (isset( $_POST[$name] ) && !empty( $_POST[$name] )) ? stripslashes( trim( $_POST[$name] ) ) : '';
113 }
114 elseif ( $type == 'number' ) {
115 return (isset( $_POST[$name] ) && is_numeric( $_POST[$name] )) ? intval( $_POST[$name] ) : '';
116 }
117 elseif ( $type == 'float' ) {
118 return (isset( $_POST[$name] ) && is_numeric( $_POST[$name] )) ? floatval( $_POST[$name] ) : '';
119 }
120 elseif ( $type == 'boolean' ) {
121 return (isset( $_POST[$name] )) ? true : false;
122 }
123 elseif ( $type == 'array' ) {
124 return (isset( $_POST[$name] ) && is_array( $_POST[$name] )) ? $_POST[$name] : array();
125 }
126 elseif ( $type == 'content' ) {
127 return (isset( $_POST[$name] ) && !empty( $_POST[$name] )) ? trim( $_POST[$name] ) : '';
128 }
129 }
130
131 return false;
132 }
133
134 /**
135 * Checks if a string contains a specified substring.
136 *
137 * @param string $string The string to search in.
138 * @param string $search The substring to search for.
139 *
140 * @return bool Returns true if the substring is found in the string, otherwise false.
141 */
142 public static function contains($string, $search)
143 {
144 if ( !empty( $string ) && !empty( $search ) ) {
145 $result = stripos( $string, $search );
146 if ( $result !== false ) {
147 return true;
148 }
149 else {
150 return false;
151 }
152 }
153 else {
154 return false;
155 }
156 }
157
158 /**
159 * Checks if a string starts with a specified substring.
160 *
161 * @param string $string The string to check.
162 * @param string $search The substring to look for at the start of the string.
163 *
164 * @return bool Returns true if the string starts with the search substring, otherwise false.
165 */
166 public static function startWith($string, $search)
167 {
168 $length = strlen( $search );
169
170 return (substr( $string, 0, $length ) === $search);
171 }
172
173 /**
174 * Checks if a string ends with a specified substring.
175 *
176 * This method trims the right side whitespace of the input string before checking
177 * if it ends with the specified search substring.
178 *
179 * @param string $string The string to check.
180 * @param string $search The substring to look for at the end of the string.
181 *
182 * @return bool Returns true if the string ends with the search substring, otherwise false.
183 */
184 public static function endWith($string, $search)
185 {
186 $length = strlen( $search );
187 $start = $length * -1;
188
189 return (substr( $string, $start ) === $search);
190 }
191
192 /**
193 * Generates a random string of specified length and character set.
194 *
195 * @param int $length The length of the random string to generate.
196 * @param bool $withNumeric Whether to include numeric characters in the random string.
197 *
198 * @return string Returns the generated random string.
199 */
200 public static function random($length = 32, $withNumeric = true)
201 {
202 $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
203 if ( $withNumeric ) {
204 $characters .= '0123456789';
205 }
206
207 $randomString = '';
208 for ( $i = 0; $i < $length; $i++ ) {
209 $randomString .= $characters[rand( 0, strlen( $characters ) - 1 )];
210 }
211
212 return $randomString;
213 }
214
215 /**
216 * Recursively deletes files from a specified directory while excluding certain files.
217 *
218 * @param string $path The path to the directory to clear.
219 * @param array $exclude An array of filenames to exclude from deletion.
220 *
221 * @return array Returns an array with the status of the operation and the number of files deleted.
222 */
223 public static function clearFolders($paths, $exclude = array())
224 {
225 $result = array();
226 foreach ( $paths as $path ) {
227 $result[$path] = self::clearFolder( $path, $exclude );
228 }
229
230 return $result;
231 }
232
233 /**
234 * Recursively clears all files and directories within a specified directory, excluding specified items.
235 *
236 * @param string $path The path of the directory to clear.
237 * @param array $exclude An array of filenames to exclude from deletion.
238 *
239 * @return array|null Returns an array with the operation status and count of files deleted, or null if the directory cannot be opened.
240 */
241 public static function clearFolder($path, $exclude = array())
242 {
243 $result = array();
244 $result['return'] = true;
245 $result['nb_files'] = 0;
246
247 $handle = @opendir( $path );
248 if ( !$handle ) {
249 return null;
250 }
251
252 while ( false !== ($file = readdir( $handle )) ) {
253 if ( $file == '.' || $file == '..' || in_array( $file, $exclude ) ) {
254 continue;
255 }
256 if ( is_dir( $path . '/' . $file ) ) {
257 $r = self::clearFolder( $path . '/' . $file );
258 if ( !$r ) {
259 $result['return'] = false;
260
261 return $result;
262 }
263 }
264 else {
265 $r = @unlink( $path . '/' . $file );
266 if ( $r ) {
267 $result['nb_files']++;
268 }
269 else {
270 $result['return'] = false;
271
272 return $result;
273 }
274 }
275 }
276
277 closedir( $handle );
278
279 return $result;
280 }
281
282 /**
283 * Recursively deletes a directory and all its contents.
284 *
285 * @param string $path The path of the directory to delete.
286 */
287 public static function deleteFolder($path)
288 {
289 if ( is_dir( $path ) ) {
290 if ( substr( $path, strlen( $path ) - 1, 1 ) != '/' ) {
291 $path .= '/';
292 }
293 $files = glob( $path . '*', GLOB_MARK );
294 foreach ( $files as $file ) {
295 if ( is_dir( $file ) ) {
296 self::deleteFolder( $file );
297 }
298 else {
299 unlink( $file );
300 }
301 }
302 rmdir( $path );
303 }
304 }
305
306 /**
307 * Recursively searches for a file starting from a specified directory.
308 *
309 * @param string $startPath The directory path to start the search.
310 * @param string $findFile The filename to search for.
311 *
312 * @return string|false Returns the path to the file if found, or false if not found.
313 */
314 private static function findFile($startPath, $findFile)
315 {
316 $result = false;
317
318 $handle = @opendir( $startPath );
319 if ( !$handle ) {
320 return false;
321 }
322
323 while ( false !== ($file = readdir( $handle )) ) {
324 if ( $file == '.' || $file == '..' ) {
325 continue;
326 }
327 if ( is_dir( $startPath . '/' . $file ) ) {
328 $result = self::findFile( $startPath . '/' . $file, $findFile );
329 if ( $result !== false ) {
330 break;
331 }
332 }
333 elseif ( $file == $findFile ) {
334 $result = self::formatUnixPath( $startPath . '/' . $file );
335 break;
336 }
337 }
338
339 closedir( $handle );
340
341 return $result;
342 }
343
344 /**
345 * Validates an IP address.
346 *
347 * @param string $ip The IP address to validate.
348 *
349 * @return bool Returns true if the IP address is valid, otherwise false.
350 */
351 public static function isValidIp($ip)
352 {
353 return filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 )
354 || filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 );
355 }
356
357 /**
358 * Validates a port number.
359 *
360 * @param int $port The port number to validate.
361 *
362 * @return bool Returns true if the port number is valid and within the range of 1 to 65535, otherwise false.
363 */
364 public static function isValidPort($port)
365 {
366 return is_numeric( $port ) && ($port > 0 || $port <= 65535);
367 }
368
369 /**
370 * Replaces a defined constant in a file with a new value.
371 *
372 * @param string $path The file path where the constant is defined.
373 * @param string $var The name of the constant.
374 * @param mixed $value The new value for the constant.
375 */
376 public static function replaceDefine($path, $var, $value)
377 {
378 self::replaceInFile( $path, array(
379 '/^define\‍((.*?)' . $var . '(.*?),/' => 'define(\'' . $var . '\', ' . (is_int( $value ) ? $value : '\'' . $value . '\'') . ');'
380 ) );
381 }
382
383 /**
384 * Performs replacements in a file based on a list of regular expression patterns.
385 *
386 * @param string $path The path to the file where replacements are to be made.
387 * @param array $replaceList An associative array where keys are regex patterns and values are replacement strings.
388 */
389 public static function replaceInFile($path, $replaceList)
390 {
391 if ( file_exists( $path ) ) {
392 $lines = file( $path );
393 $fp = fopen( $path, 'w' );
394 foreach ( $lines as $nb => $line ) {
395 $replaceDone = false;
396 foreach ( $replaceList as $regex => $replace ) {
397 if ( preg_match( $regex, $line, $matches ) ) {
398 $countParams = preg_match_all( '/{{(\d+)}}/', $replace, $paramsMatches );
399 if ( $countParams > 0 && $countParams <= count( $matches ) ) {
400 foreach ( $paramsMatches[1] as $paramsMatch ) {
401 $replace = str_replace( '{{' . $paramsMatch . '}}', $matches[$paramsMatch], $replace );
402 }
403 }
404 self::logTrace( 'Replace in file ' . $path . ' :' );
405 self::logTrace( '## line_num: ' . trim( $nb ) );
406 self::logTrace( '## old: ' . trim( $line ) );
407 self::logTrace( '## new: ' . trim( $replace ) );
408 fwrite( $fp, $replace . PHP_EOL );
409
410 $replaceDone = true;
411 break;
412 }
413 }
414 if ( !$replaceDone ) {
415 fwrite( $fp, $line );
416 }
417 }
418 fclose( $fp );
419 }
420 }
421
422 /**
423 * Retrieves a list of version directories within a specified path.
424 *
425 * @param string $path The path to search for version directories.
426 *
427 * @return array|false Returns a sorted array of version names, or false if the directory cannot be opened.
428 */
429 public static function getVersionList($path)
430 {
431 $result = array();
432
433 $handle = @opendir( $path );
434 if ( !$handle ) {
435 return false;
436 }
437
438 while ( false !== ($file = readdir( $handle )) ) {
439 $filePath = $path . '/' . $file;
440 if ( $file != "." && $file != ".." && is_dir( $filePath ) && $file != 'current' ) {
441 $result[] = str_replace( basename( $path ), '', $file );
442 }
443 }
444
445 closedir( $handle );
446 natcasesort( $result );
447
448 return $result;
449 }
450
451 /**
452 * Gets the current Unix timestamp with microseconds.
453 *
454 * @return float Returns the current Unix timestamp combined with microseconds.
455 */
456 public static function getMicrotime()
457 {
458 list( $usec, $sec ) = explode( " ", microtime() );
459
460 return ((float) $usec + (float) $sec);
461 }
462
463 public static function getAppBinsRegKey($fromRegistry = true)
464 {
465 global $bearsamppRegistry;
466
467 if ( $fromRegistry ) {
468 $value = $bearsamppRegistry->getValue(
472 );
473 self::logDebug( 'App reg key from registry: ' . $value );
474 }
475 else {
476 global $bearsamppBins, $bearsamppTools;
477 $value = '';
478 if ( $bearsamppBins->getApache()->isEnable() ) {
479 $value .= $bearsamppBins->getApache()->getSymlinkPath() . '/bin;';
480 }
481 if ( $bearsamppBins->getPhp()->isEnable() ) {
482 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . ';';
483 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/pear;';
484 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/deps;';
485 $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/imagick;';
486 }
487 if ( $bearsamppBins->getNodejs()->isEnable() ) {
488 $value .= $bearsamppBins->getNodejs()->getSymlinkPath() . ';';
489 }
490 if ( $bearsamppTools->getComposer()->isEnable() ) {
491 $value .= $bearsamppTools->getComposer()->getSymlinkPath() . ';';
492 $value .= $bearsamppTools->getComposer()->getSymlinkPath() . '/vendor/bin;';
493 }
494 if ( $bearsamppTools->getGhostscript()->isEnable() ) {
495 $value .= $bearsamppTools->getGhostscript()->getSymlinkPath() . '/bin;';
496 }
497 if ( $bearsamppTools->getGit()->isEnable() ) {
498 $value .= $bearsamppTools->getGit()->getSymlinkPath() . '/bin;';
499 }
500 if ( $bearsamppTools->getNgrok()->isEnable() ) {
501 $value .= $bearsamppTools->getNgrok()->getSymlinkPath() . ';';
502 }
503 if ( $bearsamppTools->getPerl()->isEnable() ) {
504 $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/perl/site/bin;';
505 $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/perl/bin;';
506 $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/c/bin;';
507 }
508 if ( $bearsamppTools->getPython()->isEnable() ) {
509 $value .= $bearsamppTools->getPython()->getSymlinkPath() . '/bin;';
510 }
511 if ( $bearsamppTools->getRuby()->isEnable() ) {
512 $value .= $bearsamppTools->getRuby()->getSymlinkPath() . '/bin;';
513 }
514 if ( $bearsamppTools->getYarn()->isEnable() ) {
515 $value .= $bearsamppTools->getYarn()->getSymlinkPath() . ';';
516 $value .= $bearsamppTools->getYarn()->getSymlinkPath() . '/global/bin;';
517 }
518 $value = self::formatWindowsPath( $value );
519 self::logDebug( 'Generated app bins reg key: ' . $value );
520 }
521
522 return $value;
523 }
524
525 /**
526 * Retrieves or generates the application binaries registry key.
527 *
528 * @param bool $fromRegistry Determines whether to retrieve the key from the registry or generate it.
529 *
530 * @return string Returns the application binaries registry key.
531 */
532 public static function setAppBinsRegKey($value)
533 {
534 global $bearsamppRegistry;
535
536 return $bearsamppRegistry->setStringValue(
540 $value
541 );
542 }
543
544 /**
545 * Retrieves the application path from the registry.
546 *
547 * @return mixed The value of the application path registry key or false on error.
548 */
549 public static function getAppPathRegKey()
550 {
551 global $bearsamppRegistry;
552
553 return $bearsamppRegistry->getValue(
557 );
558 }
559
560 /**
561 * Sets the application path in the registry.
562 *
563 * @param string $value The new value for the application path.
564 *
565 * @return bool True on success, false on failure.
566 */
567 public static function setAppPathRegKey($value)
568 {
569 global $bearsamppRegistry;
570
571 return $bearsamppRegistry->setStringValue(
575 $value
576 );
577 }
578
579 /**
580 * Retrieves the system path from the registry.
581 *
582 * @return mixed The value of the system path registry key or false on error.
583 */
584 public static function getSysPathRegKey()
585 {
586 global $bearsamppRegistry;
587
588 return $bearsamppRegistry->getValue(
592 );
593 }
594
595 /**
596 * Sets the system path in the registry.
597 *
598 * @param string $value The new value for the system path.
599 *
600 * @return bool True on success, false on failure.
601 */
602 public static function setSysPathRegKey($value)
603 {
604 global $bearsamppRegistry;
605
606 return $bearsamppRegistry->setExpandStringValue(
610 $value
611 );
612 }
613
614 /**
615 * Retrieves the processor identifier from the registry.
616 *
617 * @return mixed The value of the processor identifier registry key or false on error.
618 */
619 public static function getProcessorRegKey()
620 {
621 global $bearsamppRegistry;
622
623 return $bearsamppRegistry->getValue(
627 );
628 }
629
630 /**
631 * Retrieves the path for the startup link file.
632 *
633 * @return string The full path to the startup link file.
634 */
635 public static function getStartupLnkPath()
636 {
637 return Vbs::getStartupPath( APP_TITLE . '.lnk' );
638 }
639
640 /**
641 * Checks if the application is set to launch at startup.
642 *
643 * @return bool True if the startup link exists, false otherwise.
644 */
645 public static function isLaunchStartup()
646 {
647 return file_exists( self::getStartupLnkPath() );
648 }
649
650 /**
651 * Enables launching the application at startup by creating a shortcut in the startup folder.
652 *
653 * @return bool True on success, false on failure.
654 */
655 public static function enableLaunchStartup()
656 {
657 return Vbs::createShortcut( self::getStartupLnkPath() );
658 }
659
660 /**
661 * Disables launching the application at startup by removing the shortcut from the startup folder.
662 *
663 * @return bool True on success, false on failure.
664 */
665 public static function disableLaunchStartup()
666 {
667 return @unlink( self::getStartupLnkPath() );
668 }
669
670 /**
671 * Logs a message to a specified file or default log file based on the log type.
672 *
673 * @param string $data The message to log.
674 * @param string $type The type of log message: 'ERROR', 'WARNING', 'INFO', 'DEBUG', or 'TRACE'.
675 * @param string|null $file The file path to write the log message to. If null, uses default log file based on type.
676 */
677 private static function log($data, $type, $file = null)
678 {
680 $file = $file == null ? ($type == self::LOG_ERROR ? $bearsamppRoot->getErrorLogFilePath() : $bearsamppRoot->getLogFilePath()) : $file;
681 if ( !$bearsamppRoot->isRoot() ) {
682 $file = $bearsamppRoot->getHomepageLogFilePath();
683 }
684
685 $verbose = array();
686 $verbose[Config::VERBOSE_SIMPLE] = $type == self::LOG_ERROR || $type == self::LOG_WARNING;
687 $verbose[Config::VERBOSE_REPORT] = $verbose[Config::VERBOSE_SIMPLE] || $type == self::LOG_INFO;
688 $verbose[Config::VERBOSE_DEBUG] = $verbose[Config::VERBOSE_REPORT] || $type == self::LOG_DEBUG;
689 $verbose[Config::VERBOSE_TRACE] = $verbose[Config::VERBOSE_DEBUG] || $type == self::LOG_TRACE;
690
691 $writeLog = false;
692 if ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_SIMPLE && $verbose[Config::VERBOSE_SIMPLE] ) {
693 $writeLog = true;
694 }
695 elseif ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_REPORT && $verbose[Config::VERBOSE_REPORT] ) {
696 $writeLog = true;
697 }
698 elseif ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_DEBUG && $verbose[Config::VERBOSE_DEBUG] ) {
699 $writeLog = true;
700 }
701 elseif ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_TRACE && $verbose[Config::VERBOSE_TRACE] ) {
702 $writeLog = true;
703 }
704
705 if ( $writeLog ) {
706 file_put_contents(
707 $file,
708 '[' . date( 'Y-m-d H:i:s', time() ) . '] # ' . APP_TITLE . ' ' . $bearsamppCore->getAppVersion() . ' # ' . $type . ': ' . $data . PHP_EOL,
709 FILE_APPEND
710 );
711 }
712 }
713
714 /**
715 * Appends a separator line to multiple log files if they do not already end with it.
716 * This function ensures that each log file ends with a clear separator for better readability.
717 *
718 * @global object $bearsamppRoot An object that provides paths to various log files.
719 */
720 public static function logSeparator()
721 {
722 global $bearsamppRoot;
723
724 $logs = array(
725 $bearsamppRoot->getLogFilePath(),
726 $bearsamppRoot->getErrorLogFilePath(),
727 $bearsamppRoot->getServicesLogFilePath(),
728 $bearsamppRoot->getRegistryLogFilePath(),
729 $bearsamppRoot->getStartupLogFilePath(),
730 $bearsamppRoot->getBatchLogFilePath(),
731 $bearsamppRoot->getVbsLogFilePath(),
732 $bearsamppRoot->getWinbinderLogFilePath(),
733 );
734
735 $separator = '========================================================================================' . PHP_EOL;
736 foreach ( $logs as $log ) {
737 if ( !file_exists( $log ) ) {
738 continue; // Skip to the next iteration if the file does not exist
739 }
740 $logContent = @file_get_contents( $log );
741 if ( $logContent !== false && !self::endWith( $logContent, $separator ) ) {
742 file_put_contents( $log, $separator, FILE_APPEND );
743 }
744 }
745 }
746
747 /**
748 * Logs trace information.
749 * This function is a wrapper around the generic log function for trace-level messages.
750 *
751 * @param mixed $data The data to log.
752 * @param string|null $file Optional. The file path to log to. If not provided, a default path is used.
753 */
754 public static function logTrace($data, $file = null)
755 {
756 self::log( $data, self::LOG_TRACE, $file );
757 }
758
759 /**
760 * Logs debug information.
761 * This function is a wrapper around the generic log function for debug-level messages.
762 *
763 * @param mixed $data The data to log.
764 * @param string|null $file Optional. The file path to log to. If not provided, a default path is used.
765 */
766 public static function logDebug($data, $file = null)
767 {
768 self::log( $data, self::LOG_DEBUG, $file );
769 }
770
771 /**
772 * Logs informational messages.
773 * This function is a wrapper around the generic log function for informational messages.
774 *
775 * @param mixed $data The data to log.
776 * @param string|null $file Optional. The file path to log to. If not provided, a default path is used.
777 */
778 public static function logInfo($data, $file = null)
779 {
780 self::log( $data, self::LOG_INFO, $file );
781 }
782
783 /**
784 * Logs warning messages.
785 * This function is a wrapper around the generic log function for warning-level messages.
786 *
787 * @param mixed $data The data to log.
788 * @param string|null $file Optional. The file path to log to. If not provided, a default path is used.
789 */
790 public static function logWarning($data, $file = null)
791 {
792 self::log( $data, self::LOG_WARNING, $file );
793 }
794
795 /**
796 * Logs error messages.
797 * This function is a wrapper around the generic log function for error-level messages.
798 *
799 * @param mixed $data The data to log.
800 * @param string|null $file Optional. The file path to log to. If not provided, a default path is used.
801 */
802 public static function logError($data, $file = null)
803 {
804 self::log( $data, self::LOG_ERROR, $file );
805 }
806
807 /**
808 * Logs the initialization of a class instance.
809 *
810 * @param object $classInstance The instance of the class to log.
811 */
812 public static function logInitClass($classInstance)
813 {
814 self::logTrace( 'Init ' . get_class( $classInstance ) );
815 }
816
817 /**
818 * Logs the reloading of a class instance.
819 *
820 * @param object $classInstance The instance of the class to log.
821 */
822 public static function logReloadClass($classInstance)
823 {
824 self::logTrace( 'Reload ' . get_class( $classInstance ) );
825 }
826
827 /**
828 * Finds the path to the PowerShell executable in the Windows System32 directory.
829 *
830 * @return string|false Returns the path to powershell.exe if found, otherwise false.
831 */
832 public static function getPowerShellPath()
833 {
834 if ( is_dir( 'C:\Windows\System32\WindowsPowerShell' ) ) {
835 return self::findFile( 'C:\Windows\System32\WindowsPowerShell', 'powershell.exe' );
836 }
837
838 return false;
839 }
840
841 /**
842 * Recursively searches for repositories starting from a given path up to a specified depth.
843 *
844 * @param string $initPath The initial path from where the search begins.
845 * @param string $startPath The current path from where to search.
846 * @param string $checkFile The file name to check for in the directory to consider it a repository.
847 * @param int $maxDepth The maximum depth of directories to search into.
848 *
849 * @return array Returns an array of paths that contain the specified file.
850 */
851 public static function findRepos($initPath, $startPath, $checkFile, $maxDepth = 1)
852 {
853 $depth = substr_count( str_replace( $initPath, '', $startPath ), '/' );
854 $result = array();
855
856 $handle = @opendir( $startPath );
857 if ( !$handle ) {
858 return $result;
859 }
860
861 while ( false !== ($file = readdir( $handle )) ) {
862 if ( $file == '.' || $file == '..' ) {
863 continue;
864 }
865 if ( is_dir( $startPath . '/' . $file ) && ($initPath == $startPath || $depth <= $maxDepth) ) {
866 $tmpResults = self::findRepos( $initPath, $startPath . '/' . $file, $checkFile, $maxDepth );
867 foreach ( $tmpResults as $tmpResult ) {
868 $result[] = $tmpResult;
869 }
870 }
871 elseif ( is_file( $startPath . '/' . $checkFile ) && !in_array( $startPath, $result ) ) {
872 $result[] = self::formatUnixPath( $startPath );
873 }
874 }
875
876 closedir( $handle );
877
878 return $result;
879 }
880
881 /**
882 * Converts a Unix-style path to a Windows-style path.
883 *
884 * @param string $path The Unix-style path to convert.
885 *
886 * @return string Returns the converted Windows-style path.
887 */
888 public static function formatWindowsPath($path)
889 {
890 return str_replace( '/', '\\', $path );
891 }
892
893 /**
894 * Converts a Windows-style path to a Unix-style path.
895 *
896 * @param string $path The Windows-style path to convert.
897 *
898 * @return string Returns the converted Unix-style path.
899 */
900 public static function formatUnixPath($path)
901 {
902 return str_replace( '\\', '/', $path );
903 }
904
905 /**
906 * Converts an image file to a base64 encoded string.
907 *
908 * @param string $path The path to the image file.
909 *
910 * @return string Returns the base64 encoded string of the image.
911 */
912 public static function imgToBase64($path)
913 {
914 $type = pathinfo( $path, PATHINFO_EXTENSION );
915 $data = file_get_contents( $path );
916
917 return 'data:image/' . $type . ';base64,' . base64_encode( $data );
918 }
919
920 /**
921 * Converts UTF-8 encoded data to Windows-1252 encoding.
922 *
923 * @param string $data The UTF-8 encoded data.
924 *
925 * @return string Returns the data encoded in Windows-1252.
926 */
927 public static function utf8ToCp1252($data)
928 {
929 return iconv( "UTF-8", "WINDOWS-1252//IGNORE", $data );
930 }
931
932 /**
933 * Converts Windows-1252 encoded data to UTF-8 encoding.
934 *
935 * @param string $data The Windows-1252 encoded data.
936 *
937 * @return string Returns the data encoded in UTF-8.
938 */
939 public static function cp1252ToUtf8($data)
940 {
941 return iconv( "WINDOWS-1252", "UTF-8//IGNORE", $data );
942 }
943
944 /**
945 * Initiates a loading process using external components.
946 */
947 public static function startLoading()
948 {
949 global $bearsamppCore, $bearsamppWinbinder;
950 $bearsamppWinbinder->exec( $bearsamppCore->getPhpExe(), Core::isRoot_FILE . ' ' . Action::LOADING );
951 }
952
953 /**
954 * Stops a previously started loading process and cleans up related resources.
955 */
956 public static function stopLoading()
957 {
958 global $bearsamppCore;
959 if ( file_exists( $bearsamppCore->getLoadingPid() ) ) {
960 $pids = file( $bearsamppCore->getLoadingPid() );
961 foreach ( $pids as $pid ) {
962 Win32Ps::kill( $pid );
963 }
964 @unlink( $bearsamppCore->getLoadingPid() );
965 }
966 }
967
968 /**
969 * Retrieves a list of files to scan from specified paths or default paths.
970 *
971 * @param string|null $path Optional. The path to start scanning from. If null, uses default paths.
972 *
973 * @return array Returns an array of files found during the scan.
974 */
975 public static function getFilesToScan($path = null)
976 {
977 $result = array();
978 $pathsToScan = !empty( $path ) ? $path : self::getPathsToScan();
979 foreach ( $pathsToScan as $pathToScan ) {
980 $startTime = self::getMicrotime();
981 $findFiles = self::findFiles( $pathToScan['path'], $pathToScan['includes'], $pathToScan['recursive'] );
982 foreach ( $findFiles as $findFile ) {
983 $result[] = $findFile;
984 }
985 self::logDebug( $pathToScan['path'] . ' scanned in ' . round( self::getMicrotime() - $startTime, 3 ) . 's' );
986 }
987
988 return $result;
989 }
990
991 /**
992 * Retrieves a list of directories and file types to scan within the BEARSAMPP environment.
993 *
994 * This method compiles an array of paths from various components of the BEARSAMPP stack,
995 * including Apache, PHP, MySQL, MariaDB, PostgreSQL, Node.js, Filezilla, Composer, ConsoleZ,
996 * Python, Ruby, and Yarn. Each path entry includes the directory path, file types to include
997 * in the scan, and whether the scan should be recursive.
998 *
999 * The method uses global variables to access the root paths of each component. It then
1000 * dynamically fetches specific subdirectories using the `getFolderList` method (which is
1001 * assumed to be defined elsewhere in this class or in the global scope) and constructs
1002 * an array of path specifications.
1003 *
1004 * Each path specification is an associative array with the following keys:
1005 * - 'path': The full directory path to scan.
1006 * - 'includes': An array of file extensions or filenames to include in the scan.
1007 * - 'recursive': A boolean indicating whether the scan should include subdirectories.
1008 *
1009 * The method is designed to be used for setting up scans of configuration files and other
1010 * important files within the BEARSAMPP environment, possibly for purposes like configuration
1011 * management, backup, or security auditing.
1012 *
1013 * @return array An array of associative arrays, each containing 'path', 'includes', and 'recursive' keys.
1014 */
1015 private static function getPathsToScan()
1016 {
1017 global $bearsamppRoot, $bearsamppCore, $bearsamppBins, $bearsamppApps, $bearsamppTools;
1018 $paths = array();
1019
1020 // Alias
1021 $paths[] = array(
1022 'path' => $bearsamppRoot->getAliasPath(),
1023 'includes' => array(''),
1024 'recursive' => false
1025 );
1026
1027 // Vhosts
1028 $paths[] = array(
1029 'path' => $bearsamppRoot->getVhostsPath(),
1030 'includes' => array(''),
1031 'recursive' => false
1032 );
1033
1034 // OpenSSL
1035 $paths[] = array(
1036 'path' => $bearsamppCore->getOpenSslPath(),
1037 'includes' => array('openssl.cfg'),
1038 'recursive' => false
1039 );
1040
1041 // Homepage
1042 $paths[] = array(
1043 'path' => $bearsamppCore->getResourcesPath() . '/homepage',
1044 'includes' => array('alias.conf'),
1045 'recursive' => false
1046 );
1047
1048 // Apache
1049 $folderList = self::getFolderList( $bearsamppBins->getApache()->getRootPath() );
1050 foreach ( $folderList as $folder ) {
1051 $paths[] = array(
1052 'path' => $bearsamppBins->getApache()->getRootPath() . '/' . $folder,
1053 'includes' => array('.ini', '.conf'),
1054 'recursive' => true
1055 );
1056 }
1057
1058 // PHP
1059 $folderList = self::getFolderList( $bearsamppBins->getPhp()->getRootPath() );
1060 foreach ( $folderList as $folder ) {
1061 $paths[] = array(
1062 'path' => $bearsamppBins->getPhp()->getRootPath() . '/' . $folder,
1063 'includes' => array('.php', '.bat', '.ini', '.reg', '.inc'),
1064 'recursive' => true
1065 );
1066 }
1067
1068 // MySQL
1069 $folderList = self::getFolderList( $bearsamppBins->getMysql()->getRootPath() );
1070 foreach ( $folderList as $folder ) {
1071 $paths[] = array(
1072 'path' => $bearsamppBins->getMysql()->getRootPath() . '/' . $folder,
1073 'includes' => array('my.ini'),
1074 'recursive' => false
1075 );
1076 }
1077
1078 // MariaDB
1079 $folderList = self::getFolderList( $bearsamppBins->getMariadb()->getRootPath() );
1080 foreach ( $folderList as $folder ) {
1081 $paths[] = array(
1082 'path' => $bearsamppBins->getMariadb()->getRootPath() . '/' . $folder,
1083 'includes' => array('my.ini'),
1084 'recursive' => false
1085 );
1086 }
1087
1088 // PostgreSQL
1089 $folderList = self::getFolderList( $bearsamppBins->getPostgresql()->getRootPath() );
1090 foreach ( $folderList as $folder ) {
1091 $paths[] = array(
1092 'path' => $bearsamppBins->getPostgresql()->getRootPath() . '/' . $folder,
1093 'includes' => array('.ber', '.conf', '.bat'),
1094 'recursive' => true
1095 );
1096 }
1097
1098 // Node.js
1099 $folderList = self::getFolderList( $bearsamppBins->getNodejs()->getRootPath() );
1100 foreach ( $folderList as $folder ) {
1101 $paths[] = array(
1102 'path' => $bearsamppBins->getNodejs()->getRootPath() . '/' . $folder . '/etc',
1103 'includes' => array('npmrc'),
1104 'recursive' => true
1105 );
1106 $paths[] = array(
1107 'path' => $bearsamppBins->getNodejs()->getRootPath() . '/' . $folder . '/node_modules/npm',
1108 'includes' => array('npmrc'),
1109 'recursive' => false
1110 );
1111 }
1112
1113 // Filezilla
1114 $folderList = self::getFolderList( $bearsamppBins->getFilezilla()->getRootPath() );
1115 foreach ( $folderList as $folder ) {
1116 $paths[] = array(
1117 'path' => $bearsamppBins->getFilezilla()->getRootPath() . '/' . $folder,
1118 'includes' => array('.xml'),
1119 'recursive' => true
1120 );
1121 }
1122
1123 // Composer
1124 $folderList = self::getFolderList( $bearsamppTools->getComposer()->getRootPath() );
1125 foreach ( $folderList as $folder ) {
1126 $paths[] = array(
1127 'path' => $bearsamppTools->getComposer()->getRootPath() . '/' . $folder,
1128 'includes' => array('giscus.json'),
1129 'recursive' => false
1130 );
1131 }
1132
1133 // ConsoleZ
1134 $folderList = self::getFolderList( $bearsamppTools->getConsoleZ()->getRootPath() );
1135 foreach ( $folderList as $folder ) {
1136 $paths[] = array(
1137 'path' => $bearsamppTools->getConsoleZ()->getRootPath() . '/' . $folder,
1138 'includes' => array('console.xml', '.ini', '.btm'),
1139 'recursive' => true
1140 );
1141 }
1142
1143 // Python
1144 $folderList = self::getFolderList( $bearsamppTools->getPython()->getRootPath() );
1145 foreach ( $folderList as $folder ) {
1146 $paths[] = array(
1147 'path' => $bearsamppTools->getPython()->getRootPath() . '/' . $folder . '/bin',
1148 'includes' => array('.bat'),
1149 'recursive' => false
1150 );
1151 $paths[] = array(
1152 'path' => $bearsamppTools->getPython()->getRootPath() . '/' . $folder . '/settings',
1153 'includes' => array('winpython.ini'),
1154 'recursive' => false
1155 );
1156 }
1157
1158 // Ruby
1159 $folderList = self::getFolderList( $bearsamppTools->getRuby()->getRootPath() );
1160 foreach ( $folderList as $folder ) {
1161 $paths[] = array(
1162 'path' => $bearsamppTools->getRuby()->getRootPath() . '/' . $folder . '/bin',
1163 'includes' => array('!.dll', '!.exe'),
1164 'recursive' => false
1165 );
1166 }
1167
1168 // Yarn
1169 $folderList = self::getFolderList( $bearsamppTools->getYarn()->getRootPath() );
1170 foreach ( $folderList as $folder ) {
1171 $paths[] = array(
1172 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder,
1173 'includes' => array('yarn.bat'),
1174 'recursive' => false
1175 );
1176 $paths[] = array(
1177 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder . '/global/bin',
1178 'includes' => array('.bat'),
1179 'recursive' => false
1180 );
1181 $paths[] = array(
1182 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder . '/nodejs/etc',
1183 'includes' => array('npmrc'),
1184 'recursive' => true
1185 );
1186 $paths[] = array(
1187 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder . '/nodejs/node_modules/npm',
1188 'includes' => array('npmrc'),
1189 'recursive' => false
1190 );
1191 }
1192
1193 return $paths;
1194 }
1195
1196 /**
1197 * Recursively finds files in a directory that match a set of inclusion patterns.
1198 *
1199 * @param string $startPath The directory path to start the search from.
1200 * @param array $includes An array of file patterns to include in the search. Patterns starting with '!' are excluded.
1201 * @param bool $recursive Determines whether the search should be recursive.
1202 *
1203 * @return array An array of files that match the inclusion patterns.
1204 */
1205 private static function findFiles($startPath, $includes = array(''), $recursive = true)
1206 {
1207 $result = array();
1208
1209 $handle = @opendir( $startPath );
1210 if ( !$handle ) {
1211 return $result;
1212 }
1213
1214 while ( false !== ($file = readdir( $handle )) ) {
1215 if ( $file == '.' || $file == '..' ) {
1216 continue;
1217 }
1218 if ( is_dir( $startPath . '/' . $file ) && $recursive ) {
1219 $tmpResults = self::findFiles( $startPath . '/' . $file, $includes );
1220 foreach ( $tmpResults as $tmpResult ) {
1221 $result[] = $tmpResult;
1222 }
1223 }
1224 elseif ( is_file( $startPath . '/' . $file ) ) {
1225 foreach ( $includes as $include ) {
1226 if ( self::startWith( $include, '!' ) ) {
1227 $include = ltrim( $include, '!' );
1228 if ( self::startWith( $file, '.' ) && !self::endWith( $file, $include ) ) {
1229 $result[] = self::formatUnixPath( $startPath . '/' . $file );
1230 }
1231 elseif ( $file != $include ) {
1232 $result[] = self::formatUnixPath( $startPath . '/' . $file );
1233 }
1234 }
1235 elseif ( self::endWith( $file, $include ) || $file == $include || empty( $include ) ) {
1236 $result[] = self::formatUnixPath( $startPath . '/' . $file );
1237 }
1238 }
1239 }
1240 }
1241
1242 closedir( $handle );
1243
1244 return $result;
1245 }
1246
1247 /**
1248 * Replaces old path references with new path references in the specified files.
1249 *
1250 * @param array $filesToScan Array of file paths to scan and modify.
1251 * @param string|null $rootPath The new root path to replace the old one. If null, uses a default root path.
1252 *
1253 * @return array Returns an array with the count of occurrences changed and the count of files changed.
1254 */
1255 public static function changePath($filesToScan, $rootPath = null)
1256 {
1258
1259 $result = array(
1260 'countChangedOcc' => 0,
1261 'countChangedFiles' => 0
1262 );
1263
1264 $rootPath = $rootPath != null ? $rootPath : $bearsamppRoot->getRootPath();
1265 $unixOldPath = self::formatUnixPath( $bearsamppCore->getLastPathContent() );
1266 $windowsOldPath = self::formatWindowsPath( $bearsamppCore->getLastPathContent() );
1267 $unixCurrentPath = self::formatUnixPath( $rootPath );
1268 $windowsCurrentPath = self::formatWindowsPath( $rootPath );
1269
1270 foreach ( $filesToScan as $fileToScan ) {
1271 $tmpCountChangedOcc = 0;
1272 $fileContentOr = file_get_contents( $fileToScan );
1273 $fileContent = $fileContentOr;
1274
1275 // old path
1276 preg_match( '#' . $unixOldPath . '#i', $fileContent, $unixMatches );
1277 if ( !empty( $unixMatches ) ) {
1278 $fileContent = str_replace( $unixOldPath, $unixCurrentPath, $fileContent, $countChanged );
1279 $tmpCountChangedOcc += $countChanged;
1280 }
1281 preg_match( '#' . str_replace( '\\', '\\\\', $windowsOldPath ) . '#i', $fileContent, $windowsMatches );
1282 if ( !empty( $windowsMatches ) ) {
1283 $fileContent = str_replace( $windowsOldPath, $windowsCurrentPath, $fileContent, $countChanged );
1284 $tmpCountChangedOcc += $countChanged;
1285 }
1286
1287 // placeholders
1288 preg_match( '#' . Core::PATH_LIN_PLACEHOLDER . '#i', $fileContent, $unixMatches );
1289 if ( !empty( $unixMatches ) ) {
1290 $fileContent = str_replace( Core::PATH_LIN_PLACEHOLDER, $unixCurrentPath, $fileContent, $countChanged );
1291 $tmpCountChangedOcc += $countChanged;
1292 }
1293 preg_match( '#' . Core::PATH_WIN_PLACEHOLDER . '#i', $fileContent, $windowsMatches );
1294 if ( !empty( $windowsMatches ) ) {
1295 $fileContent = str_replace( Core::PATH_WIN_PLACEHOLDER, $windowsCurrentPath, $fileContent, $countChanged );
1296 $tmpCountChangedOcc += $countChanged;
1297 }
1298
1299 if ( $fileContentOr != $fileContent ) {
1300 $result['countChangedOcc'] += $tmpCountChangedOcc;
1301 $result['countChangedFiles'] += 1;
1302 file_put_contents( $fileToScan, $fileContent );
1303 }
1304 }
1305
1306 return $result;
1307 }
1308
1309 /**
1310 * Fetches the latest version information from a given URL.
1311 *
1312 * @param string $url The URL to fetch version information from.
1313 *
1314 * @return array|null Returns an array with 'version' and 'url' if successful, null otherwise.
1315 */
1316 public static function getLatestVersion($url)
1317 {
1318 $result = self::getApiJson( $url );
1319 if ( empty( $result ) ) {
1320 self::logError( 'Cannot retrieve latest github info for: ' . $result . ' RESULT' );
1321
1322 return null;
1323 }
1324
1325 $resultArray = json_decode( $result, true );
1326 if ( isset( $resultArray['tag_name'] ) && isset( $resultArray['assets'][0]['browser_download_url'] ) ) {
1327 $tagName = $resultArray['tag_name'];
1328 $downloadUrl = $resultArray['assets'][0]['browser_download_url'];
1329 $name = $resultArray['name'];
1330 self::logDebug( 'Latest version tag name: ' . $tagName );
1331 self::logDebug( 'Download URL: ' . $downloadUrl );
1332 self::logDebug( 'Name: ' . $name );
1333
1334 return ['version' => $tagName, 'html_url' => $downloadUrl, 'name' => $name];
1335 }
1336 else {
1337 self::logError( 'Tag name, download URL, or name not found in the response: ' . $result );
1338
1339 return null;
1340 }
1341 }
1342
1343 /**
1344 * Constructs a website URL without UTM parameters.
1345 *
1346 * @param string $path Optional path to append to the base URL.
1347 * @param string $fragment Optional fragment to append to the URL.
1348 *
1349 * @return string The constructed URL without UTM parameters.
1350 */
1351 public static function getWebsiteUrlNoUtm($path = '', $fragment = '')
1352 {
1353 return self::getWebsiteUrl( $path, $fragment, false );
1354 }
1355
1356 /**
1357 * Constructs a complete website URL with optional path, fragment, and UTM source parameters.
1358 *
1359 * @param string $path Optional path to append to the base URL.
1360 * @param string $fragment Optional fragment to append to the URL.
1361 * @param bool $utmSource Whether to include UTM source parameters.
1362 *
1363 * @return string The constructed URL.
1364 */
1365 public static function getWebsiteUrl($path = '', $fragment = '', $utmSource = true)
1366 {
1367 global $bearsamppCore;
1368
1369 $url = APP_WEBSITE;
1370 if ( !empty( $path ) ) {
1371 $url .= '/' . ltrim( $path, '/' );
1372 }
1373 if ( $utmSource ) {
1374 $url = rtrim( $url, '/' ) . '/?utm_source=bearsampp-' . $bearsamppCore->getAppVersion();
1375 }
1376 if ( !empty( $fragment ) ) {
1377 $url .= $fragment;
1378 }
1379
1380 return $url;
1381 }
1382
1383 /**
1384 * Constructs the URL to the changelog page, optionally including UTM parameters.
1385 *
1386 * @param bool $utmSource Whether to include UTM source parameters.
1387 *
1388 * @return string The URL to the changelog page.
1389 */
1390 public static function getChangelogUrl($utmSource = true)
1391 {
1392 return self::getWebsiteUrl( 'doc/changelog', null, $utmSource );
1393 }
1394
1395 /**
1396 * Retrieves the file size of a remote file.
1397 *
1398 * @param string $url The URL of the remote file.
1399 * @param bool $humanFileSize Whether to return the size in a human-readable format.
1400 *
1401 * @return mixed The file size, either in bytes or as a formatted string.
1402 */
1403 public static function getRemoteFilesize($url, $humanFileSize = true)
1404 {
1405 $size = 0;
1406
1407 $data = get_headers( $url, true );
1408 if ( isset( $data['Content-Length'] ) ) {
1409 $size = intval( $data['Content-Length'] );
1410 }
1411
1412 return $humanFileSize ? self::humanFileSize( $size ) : $size;
1413 }
1414
1415 /**
1416 * Converts a file size in bytes to a human-readable format.
1417 *
1418 * @param int $size The file size in bytes.
1419 * @param string $unit The unit to convert to ('GB', 'MB', 'KB', or ''). If empty, auto-selects the unit.
1420 *
1421 * @return string The formatted file size.
1422 */
1423 public static function humanFileSize($size, $unit = '')
1424 {
1425 if ( (!$unit && $size >= 1 << 30) || $unit == 'GB' ) {
1426 return number_format( $size / (1 << 30), 2 ) . 'GB';
1427 }
1428 if ( (!$unit && $size >= 1 << 20) || $unit == 'MB' ) {
1429 return number_format( $size / (1 << 20), 2 ) . 'MB';
1430 }
1431 if ( (!$unit && $size >= 1 << 10) || $unit == 'KB' ) {
1432 return number_format( $size / (1 << 10), 2 ) . 'KB';
1433 }
1434
1435 return number_format( $size ) . ' bytes';
1436 }
1437
1438 /**
1439 * Checks if the operating system is 32-bit.
1440 *
1441 * @return bool True if the OS is 32-bit, false otherwise.
1442 */
1443 public static function is32BitsOs()
1444 {
1445 $processor = self::getProcessorRegKey();
1446
1447 return self::contains( $processor, 'x86' );
1448 }
1449
1450 /**
1451 * Retrieves HTTP headers from a given URL using either cURL or fopen, depending on availability.
1452 *
1453 * @param string $pingUrl The URL to ping for headers.
1454 *
1455 * @return array An array of HTTP headers.
1456 */
1457 public static function getHttpHeaders($pingUrl)
1458 {
1459 if ( function_exists( 'curl_version' ) ) {
1460 $result = self::getCurlHttpHeaders( $pingUrl );
1461 }
1462 else {
1463 $result = self::getFopenHttpHeaders( $pingUrl );
1464 }
1465
1466 if ( !empty( $result ) ) {
1467 $rebuildResult = array();
1468 foreach ( $result as $row ) {
1469 $row = trim( $row );
1470 if ( !empty( $row ) ) {
1471 $rebuildResult[] = $row;
1472 }
1473 }
1474 $result = $rebuildResult;
1475
1476 self::logDebug( 'getHttpHeaders:' );
1477 foreach ( $result as $header ) {
1478 self::logDebug( '-> ' . $header );
1479 }
1480 }
1481
1482 return $result;
1483 }
1484
1485 /**
1486 * Retrieves HTTP headers from a given URL using the fopen function.
1487 *
1488 * This method creates a stream context to disable SSL peer and peer name verification,
1489 * which allows self-signed certificates. It attempts to open the URL and read the HTTP
1490 * response headers.
1491 *
1492 * @param string $url The URL from which to fetch the headers.
1493 *
1494 * @return array An array of headers if successful, otherwise an empty array.
1495 */
1496 public static function getFopenHttpHeaders($url)
1497 {
1498 $result = array();
1499
1500 $context = stream_context_create( array(
1501 'ssl' => array(
1502 'verify_peer' => false,
1503 'verify_peer_name' => false,
1504 'allow_self_signed' => true,
1505 )
1506 ) );
1507
1508 $fp = @fopen( $url, 'r', false, $context );
1509 if ( $fp ) {
1510 $meta = stream_get_meta_data( $fp );
1511 $result = isset( $meta['wrapper_data'] ) ? $meta['wrapper_data'] : $result;
1512 fclose( $fp );
1513 }
1514
1515 return $result;
1516 }
1517
1518 /**
1519 * Retrieves HTTP headers from a given URL using cURL.
1520 *
1521 * This method initializes a cURL session, sets various options to fetch headers
1522 * including disabling SSL peer verification, and executes the request. It logs
1523 * the raw response for debugging purposes and parses the headers from the response.
1524 *
1525 * @param string $url The URL from which to fetch the headers.
1526 *
1527 * @return array An array of headers if successful, otherwise an empty array.
1528 */
1529 public static function getCurlHttpHeaders($url)
1530 {
1531 $result = array();
1532
1533 $ch = curl_init();
1534 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
1535 curl_setopt( $ch, CURLOPT_VERBOSE, true );
1536 curl_setopt( $ch, CURLOPT_HEADER, true );
1537 curl_setopt( $ch, CURLOPT_URL, $url );
1538 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
1539
1540 $response = @curl_exec( $ch );
1541 if ( empty( $response ) ) {
1542 return $result;
1543 }
1544
1545 self::logTrace( 'getCurlHttpHeaders:' . $response );
1546 $responseHeaders = explode( "\r\n\r\n", $response, 2 );
1547 if ( !isset( $responseHeaders[0] ) || empty( $responseHeaders[0] ) ) {
1548 return $result;
1549 }
1550
1551 return explode( "\n", $responseHeaders[0] );
1552 }
1553
1554 /**
1555 * Retrieves the initial response line from a specified host and port using a socket connection.
1556 *
1557 * This method optionally uses SSL and creates a stream context similar to `getFopenHttpHeaders`.
1558 * It attempts to connect to the host and port, reads the first line of the response, and parses it.
1559 * Detailed debug information is logged for each header line received.
1560 *
1561 * @param string $host The host name or IP address to connect to.
1562 * @param int $port The port number to connect to.
1563 * @param bool $ssl Whether to use SSL (defaults to false).
1564 *
1565 * @return array An array containing the first line of the response, split into parts, or an empty array if unsuccessful.
1566 */
1567 public static function getHeaders($host, $port, $ssl = false)
1568 {
1569 $result = array();
1570 $context = stream_context_create( array(
1571 'ssl' => array(
1572 'verify_peer' => false,
1573 'verify_peer_name' => false,
1574 'allow_self_signed' => true,
1575 )
1576 ) );
1577
1578 $fp = @stream_socket_client( ($ssl ? 'ssl://' : '') . $host . ':' . $port, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $context );
1579 if ( $fp ) {
1580 $out = fgets( $fp );
1581 $result = explode( PHP_EOL, $out );
1582 @fclose( $fp );
1583 }
1584
1585 if ( !empty( $result ) ) {
1586 $rebuildResult = array();
1587 foreach ( $result as $row ) {
1588 $row = trim( $row );
1589 if ( !empty( $row ) ) {
1590 $rebuildResult[] = $row;
1591 }
1592 }
1593 $result = $rebuildResult;
1594
1595 self::logDebug( 'getHeaders:' );
1596 foreach ( $result as $header ) {
1597 self::logDebug( '-> ' . $header );
1598 }
1599 }
1600
1601 return $result;
1602 }
1603
1604 /**
1605 * Sends a GET request to the specified URL and returns the response.
1606 *
1607 * @param string $url The URL to send the GET request to.
1608 *
1609 * @return string The trimmed response data from the URL.
1610 */
1611 public static function getApiJson($url)
1612 {
1614
1615 $ch = curl_init();
1616 curl_setopt( $ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 );
1617 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
1618 curl_setopt( $ch, CURLOPT_VERBOSE, true );
1619 curl_setopt( $ch, CURLOPT_URL, $url );
1620 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
1621 curl_setopt( $ch, CURLOPT_HTTPHEADER, $header );
1622 $data = curl_exec( $ch );
1623 if ( curl_errno( $ch ) ) {
1624 Util::logError( 'CURL Error: ' . curl_error( $ch ) );
1625 }
1626 curl_close( $ch );
1627
1628 return trim( $data );
1629
1630 }
1631
1632 /**
1633 * Checks if a specific port on localhost is in use and returns the process using it if available.
1634 *
1635 * @param int $port The port number to check.
1636 *
1637 * @return mixed Returns the process using the port if in use, 'N/A' if the port is open but no specific process can be identified, or false if the port is not in use.
1638 */
1639 public static function isPortInUse($port)
1640 {
1641 // Declaring a variable to hold the IP
1642 // address getHostName() gets the name
1643 // of the local machine getHostByName()
1644 // gets the corresponding IP
1645 $localIP = getHostByName( getHostName() );
1646
1647 $connection = @fsockopen( $localIP, $port );
1648
1649 if ( is_resource( $connection ) ) {
1650 fclose( $connection );
1651 $process = Batch::getProcessUsingPort( $port );
1652
1653 return $process != null ? $process : 'N/A';
1654 }
1655
1656 return false;
1657 }
1658
1659 /**
1660 * Validates a domain name based on specific criteria.
1661 *
1662 * @param string $domainName The domain name to validate.
1663 *
1664 * @return bool Returns true if the domain name is valid, false otherwise.
1665 */
1666 public static function isValidDomainName($domainName)
1667 {
1668 return preg_match( '/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $domainName )
1669 && preg_match( '/^.{1,253}$/', $domainName )
1670 && preg_match( '/^[^\.]{1,63}(\.[^\.]{1,63})*$/', $domainName );
1671 }
1672
1673 /**
1674 * Checks if a string is alphanumeric.
1675 *
1676 * @param string $string The string to check.
1677 *
1678 * @return bool Returns true if the string is alphanumeric, false otherwise.
1679 */
1680 public static function isAlphanumeric($string)
1681 {
1682 return ctype_alnum( $string );
1683 }
1684
1685 /**
1686 * Attempts to install and start a service on a specific port, with optional syntax checking and user notifications.
1687 *
1688 * @param object $bin An object containing the binary information and methods related to the service.
1689 * @param int $port The port number on which the service should run.
1690 * @param string $syntaxCheckCmd The command to execute for syntax checking of the service configuration.
1691 * @param bool $showWindow Optional. Whether to show message boxes for information, warnings, and errors. Defaults to false.
1692 *
1693 * @return bool Returns true if the service is successfully installed and started, false otherwise.
1694 */
1695 public static function installService($bin, $port, $syntaxCheckCmd, $showWindow = false)
1696 {
1697 global $bearsamppLang, $bearsamppWinbinder;
1698 $name = $bin->getName();
1699 $service = $bin->getService();
1700 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::INSTALL_SERVICE_TITLE ), $name );
1701
1702 $isPortInUse = self::isPortInUse( $port );
1703 if ( $isPortInUse === false ) {
1704 if ( !$service->isInstalled() ) {
1705 $service->create();
1706 if ( $service->start() ) {
1707 self::logInfo( sprintf( '%s service successfully installed. (name: %s ; port: %s)', $name, $service->getName(), $port ) );
1708 if ( $showWindow ) {
1709 $bearsamppWinbinder->messageBoxInfo(
1710 sprintf( $bearsamppLang->getValue( Lang::SERVICE_INSTALLED ), $name, $service->getName(), $port ),
1711 $boxTitle
1712 );
1713 }
1714
1715 return true;
1716 }
1717 else {
1718 $serviceError = sprintf( $bearsamppLang->getValue( Lang::SERVICE_INSTALL_ERROR ), $name );
1719 $serviceErrorLog = sprintf( 'Error during the installation of %s service', $name );
1720 if ( !empty( $syntaxCheckCmd ) ) {
1721 $cmdSyntaxCheck = $bin->getCmdLineOutput( $syntaxCheckCmd );
1722 if ( !$cmdSyntaxCheck['syntaxOk'] ) {
1723 $serviceError .= PHP_EOL . sprintf( $bearsamppLang->getValue( Lang::STARTUP_SERVICE_SYNTAX_ERROR ), $cmdSyntaxCheck['content'] );
1724 $serviceErrorLog .= sprintf( ' (conf errors detected : %s)', $cmdSyntaxCheck['content'] );
1725 }
1726 }
1727 self::logError( $serviceErrorLog );
1728 if ( $showWindow ) {
1729 $bearsamppWinbinder->messageBoxError( $serviceError, $boxTitle );
1730 }
1731 }
1732 }
1733 else {
1734 self::logWarning( sprintf( '%s service already installed', $name ) );
1735 if ( $showWindow ) {
1736 $bearsamppWinbinder->messageBoxWarning(
1737 sprintf( $bearsamppLang->getValue( Lang::SERVICE_ALREADY_INSTALLED ), $name ),
1738 $boxTitle
1739 );
1740 }
1741
1742 return true;
1743 }
1744 }
1745 elseif ( $service->isRunning() ) {
1746 self::logWarning( sprintf( '%s service already installed and running', $name ) );
1747 if ( $showWindow ) {
1748 $bearsamppWinbinder->messageBoxWarning(
1749 sprintf( $bearsamppLang->getValue( Lang::SERVICE_ALREADY_INSTALLED ), $name ),
1750 $boxTitle
1751 );
1752 }
1753
1754 return true;
1755 }
1756 else {
1757 self::logError( sprintf( 'Port %s is used by an other application : %s', $name ) );
1758 if ( $showWindow ) {
1759 $bearsamppWinbinder->messageBoxError(
1760 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED_BY ), $port, $isPortInUse ),
1761 $boxTitle
1762 );
1763 }
1764 }
1765
1766 return false;
1767 }
1768
1769 /**
1770 * Removes a service if it is installed.
1771 *
1772 * @param Win32Service $service The service object to be removed.
1773 * @param string $name The name of the service.
1774 *
1775 * @return bool Returns true if the service is successfully removed, false otherwise.
1776 */
1777 public static function removeService($service, $name)
1778 {
1779 if ( !($service instanceof Win32Service) ) {
1780 self::logError( '$service not an instance of Win32Service' );
1781
1782 return false;
1783 }
1784
1785 if ( $service->isInstalled() ) {
1786 if ( $service->delete() ) {
1787 self::logInfo( sprintf( '%s service successfully removed', $name ) );
1788
1789 return true;
1790 }
1791 else {
1792 self::logError( sprintf( 'Error during the uninstallation of %s service', $name ) );
1793
1794 return false;
1795 }
1796 }
1797 else {
1798 self::logWarning( sprintf( '%s service does not exist', $name ) );
1799 }
1800
1801 return true;
1802 }
1803
1804 /**
1805 * Attempts to start a service and performs a syntax check if required.
1806 *
1807 * @param object $bin An object containing service details.
1808 * @param string $syntaxCheckCmd Command to check syntax errors.
1809 * @param bool $showWindow Whether to show error messages in a window.
1810 *
1811 * @return bool Returns true if the service starts successfully, false otherwise.
1812 */
1813 public static function startService($bin, $syntaxCheckCmd, $showWindow = false)
1814 {
1815 global $bearsamppLang, $bearsamppWinbinder;
1816 $name = $bin->getName();
1817 $service = $bin->getService();
1818 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::START_SERVICE_TITLE ), $name );
1819
1820 if ( !$service->start() ) {
1821 $serviceError = sprintf( $bearsamppLang->getValue( Lang::START_SERVICE_ERROR ), $name );
1822 $serviceErrorLog = sprintf( 'Error while starting the %s service', $name );
1823 if ( !empty( $syntaxCheckCmd ) ) {
1824 $cmdSyntaxCheck = $bin->getCmdLineOutput( $syntaxCheckCmd );
1825 if ( !$cmdSyntaxCheck['syntaxOk'] ) {
1826 $serviceError .= PHP_EOL . sprintf( $bearsamppLang->getValue( Lang::STARTUP_SERVICE_SYNTAX_ERROR ), $cmdSyntaxCheck['content'] );
1827 $serviceErrorLog .= sprintf( ' (conf errors detected : %s)', $cmdSyntaxCheck['content'] );
1828 }
1829 }
1830 self::logError( $serviceErrorLog );
1831 if ( $showWindow ) {
1832 $bearsamppWinbinder->messageBoxError( $serviceError, $boxTitle );
1833 }
1834
1835 return false;
1836 }
1837
1838 return true;
1839 }
1840
1841 /**
1842 * Constructs a GitHub user URL with an optional path.
1843 *
1844 * @param string|null $part Optional path to append to the URL.
1845 *
1846 * @return string The full GitHub user URL.
1847 */
1848 public static function getGithubUserUrl($part = null)
1849 {
1850 $part = !empty( $part ) ? '/' . $part : null;
1851
1852 return 'https://github.com/' . APP_GITHUB_USER . $part;
1853 }
1854
1855 /**
1856 * Constructs a GitHub repository URL with an optional path.
1857 *
1858 * @param string|null $part Optional path to append to the URL.
1859 *
1860 * @return string The full GitHub repository URL.
1861 */
1862 public static function getGithubUrl($part = null)
1863 {
1864 $part = !empty( $part ) ? '/' . $part : null;
1865
1866 return self::getGithubUserUrl( APP_GITHUB_REPO . $part );
1867 }
1868
1869 /**
1870 * Constructs a URL for raw content from a GitHub repository.
1871 *
1872 * @param string $file The file path to append to the base URL.
1873 *
1874 * @return string The full URL to the raw content on GitHub.
1875 */
1876 public static function getGithubRawUrl($file)
1877 {
1878 $file = !empty( $file ) ? '/' . $file : null;
1879
1880 return 'https://raw.githubusercontent.com/' . APP_GITHUB_USER . '/' . APP_GITHUB_REPO . '/main' . $file;
1881 }
1882
1883 /**
1884 * Retrieves a list of folders from a specified directory, excluding certain directories.
1885 *
1886 * @param string $path The directory path from which to list folders.
1887 *
1888 * @return array|bool An array of folder names, or false if the directory cannot be opened.
1889 */
1890 public static function getFolderList($path)
1891 {
1892 $result = array();
1893
1894 $handle = @opendir( $path );
1895 if ( !$handle ) {
1896 return false;
1897 }
1898
1899 while ( false !== ($file = readdir( $handle )) ) {
1900 $filePath = $path . '/' . $file;
1901 if ( $file != "." && $file != ".." && is_dir( $filePath ) && $file != 'current' ) {
1902 $result[] = $file;
1903 }
1904 }
1905
1906 closedir( $handle );
1907
1908 return $result;
1909 }
1910
1911 /**
1912 * Retrieves and formats environment paths from a data file.
1913 * Paths are verified to be directories and formatted to Unix style.
1914 * Warnings are logged for paths that do not exist.
1915 *
1916 * @return string A semicolon-separated string of formatted environment paths.
1917 * @global object $bearsamppRoot Global object containing root path methods.
1918 */
1919 public static function getNssmEnvPaths()
1920 {
1921 global $bearsamppRoot;
1922
1923 $result = '';
1924 $nssmEnvPathsFile = $bearsamppRoot->getRootPath() . '/nssmEnvPaths.dat';
1925
1926 if ( is_file( $nssmEnvPathsFile ) ) {
1927 $paths = explode( PHP_EOL, file_get_contents( $nssmEnvPathsFile ) );
1928 foreach ( $paths as $path ) {
1929 $path = trim( $path );
1930 if ( stripos( $path, ':' ) === false ) {
1931 $path = $bearsamppRoot->getRootPath() . '/' . $path;
1932 }
1933 if ( is_dir( $path ) ) {
1934 $result .= self::formatUnixPath( $path ) . ';';
1935 }
1936 else {
1937 self::logWarning( 'Path not found in nssmEnvPaths.dat: ' . $path );
1938 }
1939 }
1940 }
1941
1942 return $result;
1943 }
1944
1945 /**
1946 * Opens a file with a given caption and content in the default text editor.
1947 * The file is created in a temporary directory with a unique name.
1948 *
1949 * @param string $caption The filename to use when saving the content.
1950 * @param string $content The content to write to the file.
1951 *
1952 * @global object $bearsamppRoot Global object to access temporary path.
1953 * @global object $bearsamppConfig Global configuration object.
1954 * @global object $bearsamppWinbinder Global object to execute external programs.
1955 */
1956 public static function openFileContent($caption, $content)
1957 {
1958 global $bearsamppRoot, $bearsamppConfig, $bearsamppWinbinder;
1959
1960 $folderPath = $bearsamppRoot->getTmpPath() . '/openFileContent-' . self::random();
1961 if ( !is_dir( $folderPath ) ) {
1962 mkdir( $folderPath, 0777, true );
1963 }
1964
1965 $filepath = self::formatWindowsPath( $folderPath . '/' . $caption );
1966 file_put_contents( $filepath, $content );
1967
1968 $bearsamppWinbinder->exec( $bearsamppConfig->getNotepad(), '"' . $filepath . '"' );
1969 }
1970
1971 /**
1972 * Decrypts a file encrypted with a specified method and returns the content.
1973 *
1974 * @param string $encryptedFile Path to the encrypted file.
1975 * @param string $password Password used for decryption.
1976 * @param string $method Encryption method used (e.g., AES-256-CBC).
1977 *
1978 * @return string|false Decrypted content or false on failure.
1979 */
1980 public static function decryptFile()
1981 {
1982 global $bearsamppCore;
1983
1984 $stringfile = $bearsamppCore->getResourcesPath() . '/string.dat';
1985 $encryptedFile = $bearsamppCore->getResourcesPath() . '/github.dat';
1986 $method = 'AES-256-CBC'; // The same encryption method used
1987
1988 // Get key string
1989 $stringPhrase = file_get_contents( $stringfile );
1990 if ( $stringPhrase === false ) {
1991 Util::logDebug( "Failed to read the file at path: {$stringfile}" );
1992
1993 return false;
1994 }
1995
1996 $stringKey = convert_uudecode( $stringPhrase );
1997
1998 // Read the encrypted data from the file
1999 $encryptedData = file_get_contents( $encryptedFile );
2000 if ( $encryptedData === false ) {
2001 Util::logDebug( "Failed to read the file at path: {$encryptedFile}" );
2002
2003 return false;
2004 }
2005
2006 // Decode the base64 encoded data
2007 $data = base64_decode( $encryptedData );
2008 if ( $data === false ) {
2009 Util::logDebug( "Failed to decode the data from path: {$encryptedFile}" );
2010
2011 return false;
2012 }
2013
2014 // Extract the IV which was prepended to the encrypted data
2015 $ivLength = openssl_cipher_iv_length( $method );
2016 $iv = substr( $data, 0, $ivLength );
2017 $encrypted = substr( $data, $ivLength );
2018
2019 // Decrypt the data
2020 $decrypted = openssl_decrypt( $encrypted, $method, $stringKey, 0, $iv );
2021 if ( $decrypted === false ) {
2022 Util::logDebug( "Decryption failed for data from path: {$encryptedFile}" );
2023
2024 return false;
2025 }
2026
2027 return $decrypted;
2028 }
2029
2030 /**
2031 * Sets up a cURL header array using a decrypted GitHub Personal Access Token.
2032 *
2033 * @return array The header array for cURL with authorization and other necessary details.
2034 */
2035 public static function setupCurlHeaderWithToken()
2036 {
2037
2038 // Usage
2040 $Token = self::decryptFile();
2041
2042 return [
2043 'Accept: application/vnd.github+json',
2044 'Authorization: Token ' . $Token,
2045 'User-Agent: ' . APP_GITHUB_USERAGENT,
2046 'X-GitHub-Api-Version: 2022-11-28'
2047 ];
2048 }
2049
2050 /**
2051 * Checks the current state of the internet connection.
2052 *
2053 * This method attempts to reach a well-known website (e.g., www.google.com) to determine the state of the internet connection.
2054 * It returns `true` if the connection is successful, otherwise it returns `false`.
2055 *
2056 * @return bool True if the internet connection is active, false otherwise.
2057 */
2058 public static function checkInternetState()
2059 {
2060 $connected = @fsockopen( "www.google.com", 80 );
2061 if ( $connected ) {
2062 fclose( $connected );
2063
2064 return true; // Internet connection is active
2065 }
2066 else {
2067 return false; // Internet connection is not active
2068 }
2069 }
2070}
$result
global $bearsamppBins
global $bearsamppLang
global $bearsamppRoot
$port
global $bearsamppCore
$response
const LOADING
static getProcessUsingPort($port)
const VERBOSE_REPORT
const VERBOSE_DEBUG
const VERBOSE_SIMPLE
const VERBOSE_TRACE
const isRoot_FILE
const PATH_WIN_PLACEHOLDER
const PATH_LIN_PLACEHOLDER
const SERVICE_ALREADY_INSTALLED
const START_SERVICE_TITLE
const PORT_NOT_USED_BY
const START_SERVICE_ERROR
const SERVICE_INSTALL_ERROR
const STARTUP_SERVICE_SYNTAX_ERROR
const INSTALL_SERVICE_TITLE
const SERVICE_INSTALLED
const APP_BINS_REG_ENTRY
const PROCESSOR_REG_ENTRY
const SYSPATH_REG_ENTRY
const PROCESSOR_REG_SUBKEY
const APP_PATH_REG_ENTRY
const HKEY_LOCAL_MACHINE
static getFolderList($path)
static getRemoteFilesize($url, $humanFileSize=true)
static findFiles($startPath, $includes=array(''), $recursive=true)
static getVersionList($path)
static getProcessorRegKey()
static startWith($string, $search)
static getPowerShellPath()
static getNssmEnvPaths()
const LOG_INFO
static getGithubUserUrl($part=null)
static getWebsiteUrlNoUtm($path='', $fragment='')
static setSysPathRegKey($value)
static isValidIp($ip)
static logReloadClass($classInstance)
static getApiJson($url)
static stopLoading()
static getHttpHeaders($pingUrl)
static findRepos($initPath, $startPath, $checkFile, $maxDepth=1)
static logSeparator()
static openFileContent($caption, $content)
const LOG_ERROR
static replaceInFile($path, $replaceList)
static getHeaders($host, $port, $ssl=false)
static cleanGetVar($name, $type='text')
static deleteFolder($path)
static contains($string, $search)
static getPathsToScan()
static logError($data, $file=null)
static getFilesToScan($path=null)
static endWith($string, $search)
static isValidPort($port)
static clearFolders($paths, $exclude=array())
static random($length=32, $withNumeric=true)
static getSysPathRegKey()
static cp1252ToUtf8($data)
static getChangelogUrl($utmSource=true)
static isAlphanumeric($string)
static getLatestVersion($url)
const LOG_TRACE
static getStartupLnkPath()
static formatUnixPath($path)
static getFopenHttpHeaders($url)
static changePath($filesToScan, $rootPath=null)
static decryptFile()
static installService($bin, $port, $syntaxCheckCmd, $showWindow=false)
static getGithubRawUrl($file)
static findFile($startPath, $findFile)
static isValidDomainName($domainName)
const LOG_WARNING
static startLoading()
static enableLaunchStartup()
static setAppPathRegKey($value)
static removeService($service, $name)
static is32BitsOs()
static getWebsiteUrl($path='', $fragment='', $utmSource=true)
static logDebug($data, $file=null)
static getAppPathRegKey()
static startService($bin, $syntaxCheckCmd, $showWindow=false)
static logInitClass($classInstance)
static cleanArgv($name, $type='text')
static isPortInUse($port)
static getGithubUrl($part=null)
static humanFileSize($size, $unit='')
static setAppBinsRegKey($value)
static replaceDefine($path, $var, $value)
static utf8ToCp1252($data)
static getMicrotime()
static logInfo($data, $file=null)
static disableLaunchStartup()
static logWarning($data, $file=null)
static log($data, $type, $file=null)
static imgToBase64($path)
static clearFolder($path, $exclude=array())
const LOG_DEBUG
static cleanPostVar($name, $type='text')
static formatWindowsPath($path)
static checkInternetState()
static logTrace($data, $file=null)
static setupCurlHeaderWithToken()
static getAppBinsRegKey($fromRegistry=true)
static isLaunchStartup()
static getCurlHttpHeaders($url)
static getStartupPath($file=null)
static createShortcut($savePath)
static kill($pid)
global $bearsamppConfig
Definition homepage.php:26
const APP_GITHUB_USERAGENT
Definition root.php:17
const APP_WEBSITE
Definition root.php:13
const APP_GITHUB_USER
Definition root.php:15
const APP_GITHUB_REPO
Definition root.php:16
const APP_TITLE
Definition root.php:12