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

Public Member Functions

 __construct ()
 __toString ()
 addLoadingPid ($pid)
 getAppVersion ()
 getExec ($aetrayPath=false)
 getLastPathContent ()
 getLoadingPid ($aetrayPath=false)
 getPreviousExec ()
 setExec ($action)
 unzipFile ($filePath, $destination, $progressCallback=null)

Data Fields

const APP_VERSION = 'version.dat'
const EXEC = 'exec.dat'
const HOSTSEDITOR_EXE = 'hEdit_x64.exe'
const isRoot_FILE = 'root.php'
const LAST_PATH = 'lastPath.dat'
const LN_EXE = 'ln.exe'
const LOADING_PID = 'loading.pid'
const NSSM_EXE = 'nssm.exe'
const OPENSSL_CONF = 'openssl.cfg'
const OPENSSL_EXE = 'openssl.exe'
const PATH_LIN_PLACEHOLDER = '~BEARSAMPP_LIN_PATH~'
const PATH_WIN_PLACEHOLDER = '~BEARSAMPP_WIN_PATH~'
const PHP_EXE = 'php-win.exe'
const PWGEN_EXE = "PwTech.exe"
const SETENV_EXE = 'SetEnv.exe'

Static Private Member Functions

static isSafeDestinationFileList ($sevenZipPath, $filePath)
static isUnsafeArchiveEntryPath ($entryPath)

Detailed Description

Class Core

This class provides core functionalities and constants for the Bearsampp application. It includes methods for retrieving paths, managing application versions, and handling various executable files and configurations.

Definition at line 18 of file class.core.php.

Constructor & Destructor Documentation

◆ __construct()

__construct ( )

Core constructor.

Loads the WinBinder extension if available.

Definition at line 44 of file class.core.php.

45 {
46 if (extension_loaded('winbinder')) {
47 require_once Path::getLibsPath() . '/winbinder/winbinder.php';
48 }
49 }
static getLibsPath($aetrayPath=false)

References Path\getLibsPath().

Here is the call graph for this function:

Member Function Documentation

◆ __toString()

__toString ( )

Provides a string representation of the core object.

Returns
string A string describing the core object.

Definition at line 144 of file class.core.php.

145 {
146 return 'core object';
147 }

◆ addLoadingPid()

addLoadingPid ( $pid)

Adds a PID to the loading PID file.

Parameters
int$pidThe PID to add.

Definition at line 134 of file class.core.php.

135 {
136 file_put_contents($this->getLoadingPid(), $pid . PHP_EOL, FILE_APPEND);
137 }
getLoadingPid($aetrayPath=false)

References getLoadingPid().

Here is the call graph for this function:

◆ getAppVersion()

getAppVersion ( )

Retrieves the application version.

Returns
string|null The application version or null if not found.

Definition at line 56 of file class.core.php.

57 {
58 global $bearsamppLang;
59
60 $filePath = Path::getResourcesPath() . '/' . self::APP_VERSION;
61 if (!is_file($filePath)) {
62 Log::error(sprintf($bearsamppLang->getValue(Lang::ERROR_CONF_NOT_FOUND), APP_TITLE, $filePath));
63
64 return null;
65 }
66
67 return trim(file_get_contents($filePath));
68 }
global $bearsamppLang
const ERROR_CONF_NOT_FOUND
static error($data, $file=null)
static getResourcesPath($aetrayPath=false)
const APP_TITLE
Definition root.php:19

References $bearsamppLang, APP_TITLE, Log\error(), Lang\ERROR_CONF_NOT_FOUND, and Path\getResourcesPath().

Here is the call graph for this function:

◆ getExec()

getExec ( $aetrayPath = false)

Retrieves the path to the exec file.

Parameters
bool$aetrayPathWhether to format the path for AeTrayMenu.
Returns
string The path to the exec file.

Definition at line 102 of file class.core.php.

103 {
104 return Path::getTmpPath($aetrayPath) . '/' . self::EXEC;
105 }
static getTmpPath($aetrayPath=false)

References Path\getTmpPath().

Referenced by getPreviousExec(), and setExec().

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

◆ getLastPathContent()

getLastPathContent ( )

Retrieves the content of the last path file.

Returns
string|false The content of the last path file or false on failure.

Definition at line 75 of file class.core.php.

76 {
77 return @file_get_contents(Path::getLastPath());
78 }
static getLastPath($aetrayPath=false)

References Path\getLastPath().

Here is the call graph for this function:

◆ getLoadingPid()

getLoadingPid ( $aetrayPath = false)

Retrieves the path to the loading PID file.

Parameters
bool$aetrayPathWhether to format the path for AeTrayMenu.
Returns
string The path to the loading PID file.

Definition at line 124 of file class.core.php.

125 {
126 return Path::getResourcesPath($aetrayPath) . '/' . self::LOADING_PID;
127 }

References Path\getResourcesPath().

Referenced by addLoadingPid().

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

◆ getPreviousExec()

getPreviousExec ( )

Retrieves the content of the exec file without unlinking it.

Returns
string|false The content of the exec file or false if it doesn't exist.

Definition at line 85 of file class.core.php.

86 {
87 $file = $this->getExec();
88 if (file_exists($file)) {
89 return trim(file_get_contents($file));
90 }
91
92 return false;
93 }
getExec($aetrayPath=false)

References getExec().

Here is the call graph for this function:

◆ isSafeDestinationFileList()

isSafeDestinationFileList ( $sevenZipPath,
$filePath )
staticprivate

Parses 7z l -slt output and verifies every listed entry path is safe to extract relative to the destination, returning the number of valid entries.

The listing is captured to a temp file (avoiding a slow pipe capture) and split into one block per entry on blank-line separators, each block containing a Path = <value> line. We extract each entry path individually and reject any that is empty, is absolute (drive-letter or rooted path), or contains a parent-directory (..) traversal. Banner/header blocks (including the header's reference to the archive itself) are skipped, and directories are validated but not counted, matching the Files: count of 7z t. This must fail closed: a failure to list the archive, or discovering no file entries or any unsafe entry, returns false so extraction is aborted rather than performed on an unverified archive.

Parameters
string$sevenZipPathPath to the 7za executable.
string$filePathPath to the archive file.
Returns
int|false The number of listed (safe) file entries on success, or false if the listing failed or any entry is unsafe.

Definition at line 272 of file class.core.php.

273 {
274 $listingFile = Path::getTmpPath() . '/7z-listing-' . uniqid('', true) . '.txt';
275 $stderrFile = Path::getTmpPath() . '/7z-listing-' . uniqid('', true) . '.err';
276
277 $returnVar = CommandRunner::execToFile($sevenZipPath, ['l', '-slt', $filePath], $listingFile, $stderrFile);
278 if ($returnVar === false) {
279 Log::error('Path-traversal scan: unable to list archive: ' . $filePath);
280
281 return false;
282 }
283
284 $listingOutput = @file_get_contents($listingFile);
285 @unlink($listingFile);
286 @unlink($stderrFile);
287
288 if (!is_string($listingOutput) || $listingOutput === '') {
289 Log::error('Path-traversal scan: unable to list archive: ' . $filePath);
290
291 return false;
292 }
293
294 // 7-Zip separates the `-slt` entry blocks with blank lines (a single dash
295 // line precedes the first entry, and the banner/header references the archive
296 // itself). Normalize line endings and split on blank lines so each block is
297 // one archive entry.
298 $listingOutput = str_replace("\r\n", "\n", $listingOutput);
299 $blocks = preg_split('/\n[ \t]*\n/', $listingOutput);
300 if (empty($blocks)) {
301 // No entries listed at all - cannot validate, fail closed.
302 Log::error('Path-traversal scan: no entries found in archive: ' . $filePath);
303
304 return false;
305 }
306
307 // The header block's `Path = <archive itself>` entry must not be validated
308 // or counted; skip any block that resolves to the archive file.
309 $archivePathNormalized = strtolower(str_replace('/', '\\', $filePath));
310
311 $numFiles = 0;
312 foreach ($blocks as $block) {
313 $block = trim($block);
314 if ($block === '') {
315 continue;
316 }
317
318 if (!preg_match('/^Path = (.*)$/m', $block, $match)) {
319 // Not an entry block (banner/scanning preamble lines) - skip.
320 continue;
321 }
322
323 $entryPath = trim($match[1]);
324 if (strtolower(str_replace('/', '\\', $entryPath)) === $archivePathNormalized) {
325 // Banner/header (and any trailing archive-summary) block.
326 continue;
327 }
328
329 if (self::isUnsafeArchiveEntryPath($entryPath)) {
330 Log::error('Archive contains an unsafe entry path ("' . $entryPath . '"): ' . $filePath);
331
332 return false;
333 }
334
335 // Directories are validated above but not counted as files, matching the
336 // file count previously reported by `7z t` (`Files:` excludes folders).
337 if (preg_match('/^Attributes = D\s*$/m', $block)) {
338 continue;
339 }
340
341 $numFiles++;
342 }
343
344 if ($numFiles === 0) {
345 // Nothing to extract - cannot validate, fail closed.
346 Log::error('Path-traversal scan: no file entries found in archive: ' . $filePath);
347
348 return false;
349 }
350
351 return $numFiles;
352 }
static execToFile(string $executable, array $args, string $stdoutFile, string $stderrFile)

References Log\error(), CommandRunner\execToFile(), and Path\getTmpPath().

Referenced by unzipFile().

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

◆ isUnsafeArchiveEntryPath()

isUnsafeArchiveEntryPath ( $entryPath)
staticprivate

Determines whether a single archive entry path is unsafe to extract.

A path is considered unsafe if it is empty, contains a parent-directory (..) token, or is absolute (a Windows drive path such as C:\... or a rooted path beginning with / or \\endiskip).

Parameters
string$entryPathThe entry path extracted from the archive listing.
Returns
bool True if the path is unsafe, false if safe.

Definition at line 365 of file class.core.php.

366 {
367 if ($entryPath === '') {
368 return true;
369 }
370
371 // Parent-directory traversal (matches any path segment equal to '..').
372 if (preg_match('/(?:^|[\\/\\\\])\.\.(?:[\\/\\\\]|$)/', $entryPath)) {
373 return true;
374 }
375
376 // Absolute / rooted paths.
377 if (preg_match('#^(?:[A-Za-z]:[\\/\\\\]|[\\/\\\\])#', $entryPath)) {
378 return true;
379 }
380
381 return false;
382 }

◆ setExec()

setExec ( $action)

Sets the content of the exec file.

Parameters
string$actionThe content to set in the exec file.

Definition at line 112 of file class.core.php.

113 {
114 file_put_contents($this->getExec(), $action);
115 }

References getExec().

Here is the call graph for this function:

◆ unzipFile()

unzipFile ( $filePath,
$destination,
$progressCallback = null )

Unzips a file to the specified directory and provides progress updates.

This method uses the 7-Zip command-line tool to extract the contents of a zip file. It first validates the archive's entry paths (and counts its files) via a structured listing, then proceeds with the extraction while providing progress updates via a callback function.

Parameters
string$filePathThe path to the zip file.
string$destinationThe directory to extract the files to.
callable | null$progressCallbackA callback function to report progress. The callback receives two parameters:
  • int $currentFile: The current file number being extracted.
  • int $totalFiles: The total number of files to be extracted.
Returns
array|false An array containing the result of the extraction on success or failure:
  • On success: ['success' => true, 'numFiles' => int]
  • On failure: ['error' => string, 'numFiles' => int]
  • Returns false if the 7-Zip executable is not found. @global object $bearsamppRoot Global object to get core paths.

Definition at line 170 of file class.core.php.

171 {
172 global $bearsamppRoot;
173
174 $sevenZipPath = Path::getLibsPath() . '/7zip/7za.exe';
175
176 if (!file_exists($sevenZipPath)) {
177 Log::error('7za.exe not found at: ' . $sevenZipPath);
178
179 return false;
180 }
181
182 if ($progressCallback) {
183 call_user_func($progressCallback, 'Analyzing archive...');
184 }
185
186 // Defensive path-traversal scan: parse the structured `7z l -slt` output into
187 // each individual entry path and validate every one relative to the destination,
188 // so extraction can never escape the intended directory. This must fail closed:
189 // any listing/parse failure aborts the operation rather than proceeding unverified.
190 // The scan also returns the number of archive entries, used as the extraction
191 // file count. A standalone integrity test is not needed: the archive's SHA-256
192 // was already verified against its .sha256 sidecar upstream, and `7za x`
193 // CRC-checks every file as it is extracted.
194 $numFiles = self::isSafeDestinationFileList($sevenZipPath, $filePath);
195 if ($numFiles === false) {
196 Log::error('Archive path-traversal scan failed or rejected for: ' . $filePath);
197
198 return false;
199 }
200 Log::trace('Number of files to be extracted: ' . $numFiles);
201
202 if ($progressCallback) {
203 call_user_func($progressCallback, 'Initializing extraction...');
204 }
205 // Extract the archive, streaming progress line-by-line
206 $returnVar = CommandRunner::stream(
207 $sevenZipPath,
208 ['x', $filePath, '-y', '-bsp1', '-bb0', '-o' . $destination],
209 function (string $line) use ($progressCallback) {
210 Log::trace("Processing line: $line");
211 if ($line === 'Everything is Ok') {
212 if ($progressCallback) {
213 Log::trace('Extraction progress: 100%');
214 call_user_func($progressCallback, 100);
215 }
216 } elseif ($progressCallback && preg_match('/(?:^|\s)(\d+)%/', $line, $matches)) {
217 $currentPercentage = intval($matches[1]);
218 Log::trace("Extraction progress: $currentPercentage%");
219 call_user_func($progressCallback, $currentPercentage);
220 } else {
221 Log::trace("Line did not match pattern: $line");
222 }
223 }
224 );
225
226 if ($returnVar === false) {
227 Log::error('Failed to open process for: ' . $sevenZipPath);
228
229 return ['error' => 'Failed to open process', 'numFiles' => $numFiles];
230 }
231
232 Log::trace('Command return value: ' . $returnVar);
233
234 if ($returnVar === 0 && $progressCallback) {
235 Log::trace('Extraction completed successfully. Setting progress to 100%');
236 call_user_func($progressCallback, 100);
237 usleep(100000); // 100 milliseconds
238 }
239
240 if ($returnVar === 0) {
241 Log::debug('Successfully unzipped file to: ' . $destination);
242
243 return ['success' => true, 'numFiles' => $numFiles];
244 }
245
246 Log::error('Failed to unzip file. Command return value: ' . $returnVar);
247
248 return ['error' => 'Failed to unzip file', 'numFiles' => $numFiles];
249 }
global $bearsamppRoot
static stream(string $executable, array $args, callable $lineCallback)
static isSafeDestinationFileList($sevenZipPath, $filePath)
static debug($data, $file=null)
static trace($data, $file=null)

References $bearsamppRoot, Log\debug(), Log\error(), Path\getLibsPath(), isSafeDestinationFileList(), CommandRunner\stream(), and Log\trace().

Here is the call graph for this function:

Field Documentation

◆ APP_VERSION

const APP_VERSION = 'version.dat'

Definition at line 34 of file class.core.php.

◆ EXEC

const EXEC = 'exec.dat'

Definition at line 36 of file class.core.php.

◆ HOSTSEDITOR_EXE

const HOSTSEDITOR_EXE = 'hEdit_x64.exe'

Definition at line 30 of file class.core.php.

Referenced by Path\getHostsEditorExe().

◆ isRoot_FILE

const isRoot_FILE = 'root.php'

◆ LAST_PATH

const LAST_PATH = 'lastPath.dat'

Definition at line 35 of file class.core.php.

Referenced by Path\getLastPath().

◆ LN_EXE

const LN_EXE = 'ln.exe'

Definition at line 31 of file class.core.php.

Referenced by Path\getLnExe().

◆ LOADING_PID

const LOADING_PID = 'loading.pid'

Definition at line 37 of file class.core.php.

◆ NSSM_EXE

const NSSM_EXE = 'nssm.exe'

Definition at line 27 of file class.core.php.

Referenced by Path\getNssmExe().

◆ OPENSSL_CONF

const OPENSSL_CONF = 'openssl.cfg'

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

Referenced by Path\getOpenSslConf().

◆ OPENSSL_EXE

const OPENSSL_EXE = 'openssl.exe'

Definition at line 28 of file class.core.php.

Referenced by Path\getOpenSslExe().

◆ PATH_LIN_PLACEHOLDER

const PATH_LIN_PLACEHOLDER = '~BEARSAMPP_LIN_PATH~'

Definition at line 23 of file class.core.php.

Referenced by Path\changePath().

◆ PATH_WIN_PLACEHOLDER

const PATH_WIN_PLACEHOLDER = '~BEARSAMPP_WIN_PATH~'

Definition at line 22 of file class.core.php.

Referenced by Path\changePath().

◆ PHP_EXE

const PHP_EXE = 'php-win.exe'

Definition at line 25 of file class.core.php.

Referenced by Path\getPhpExe().

◆ PWGEN_EXE

const PWGEN_EXE = "PwTech.exe"

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

Referenced by Path\getPwgenExe().

◆ SETENV_EXE

const SETENV_EXE = 'SetEnv.exe'

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

Referenced by Path\getSetEnvExe().


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