Bearsampp 2026.5.5
Loading...
Searching...
No Matches
Symlinks Class Reference

Public Member Functions

 __construct ($root)

Static Public Member Functions

static deleteCurrentSymlinks ()

Data Fields

const APACHE_SYMLINK = 'apache'
const BRUNO_SYMLINK = 'bruno'
const COMPOSER_SYMLINK = 'composer'
const GHOSTSCRIPT_SYMLINK = 'ghostscript'
const GIT_SYMLINK = 'git'
const MAILPIT_SYMLINK = 'mailpit'
const MARIADB_SYMLINK = 'mariadb'
const MEMCACHED_SYMLINK = 'memcached'
const MYSQL_SYMLINK = 'mysql'
const NGROK_SYMLINK = 'ngrok'
const NODEJS_SYMLINK = 'nodejs'
const PERL_SYMLINK = 'perl'
const PHP_SYMLINK = 'php'
const PHPMYADMIN_SYMLINK = 'phpmyadmin'
const PHPPGADMIN_SYMLINK = 'phppgadmin'
const POSTGRESQL_SYMLINK = 'postgresql'
const POWERSHELL_SYMLINK = 'powershell'
const PYTHON_SYMLINK = 'python'
const RUBY_SYMLINK = 'ruby'
const XLIGHT_SYMLINK = 'xlight'

Static Private Member Functions

static isPathWithinAllowedBase ($path)
static isSymlink ($path)
static safeRemoveSymlink ($path)

Private Attributes

 $root

Detailed Description

Manages the creation and deletion of symbolic links for various components within the Bearsampp environment.

Definition at line 14 of file class.symlinks.php.

Constructor & Destructor Documentation

◆ __construct()

__construct ( $root)

Constructs a Symlinks object and initializes paths to current directories.

Parameters
Root$rootThe root object associated with the Bearsampp environment.

Definition at line 47 of file class.symlinks.php.

48 {
49 $this->root = $root;
50 $this->initializePaths();
51 }

References $root.

Member Function Documentation

◆ deleteCurrentSymlinks()

deleteCurrentSymlinks ( )
static

Deletes all symbolic links listed in the arrayOfCurrents. Logs each operation's success or failure.

This method iterates over a predefined list of symbolic link paths and attempts to delete each one. Uses strict safety checks to prevent accidental deletion of user data:

  • Only deletes symlinks or empty directories
  • Validates all paths are within Bearsampp managed directories
  • Refuses to perform recursive deletion
  • Does not follow or delete junction points with content

@global Root $bearsamppRoot The root object providing access to system paths. @global Core $bearsamppCore The core object providing core functionalities.

Definition at line 196 of file class.symlinks.php.

197 {
199
200 // Check to see if purging is necessary
201 $appsPath = $bearsamppRoot->getAppsPath();
202 $binPath = $bearsamppRoot->getBinPath();
203 $toolsPath = $bearsamppRoot->getToolsPath();
204
205 $array = [
206 self::PHPMYADMIN_SYMLINK => $appsPath . '/phpmyadmin/current',
207 self::PHPPGADMIN_SYMLINK => $appsPath . '/phppgadmin/current',
208 self::APACHE_SYMLINK => $binPath . '/apache/current',
209 self::MARIADB_SYMLINK => $binPath . '/mariadb/current',
210 self::MEMCACHED_SYMLINK => $binPath . '/memcached/current',
211 self::MYSQL_SYMLINK => $binPath . '/mysql/current',
212 self::NODEJS_SYMLINK => $binPath . '/nodejs/current',
213 self::PHP_SYMLINK => $binPath . '/php/current',
214 self::POSTGRESQL_SYMLINK => $binPath . '/postgresql/current',
215 self::COMPOSER_SYMLINK => $toolsPath . '/composer/current',
216 self::POWERSHELL_SYMLINK => $toolsPath . '/powershell/current',
217 self::GHOSTSCRIPT_SYMLINK => $toolsPath . '/ghostscript/current',
218 self::GIT_SYMLINK => $toolsPath . '/git/current',
219 self::NGROK_SYMLINK => $toolsPath . '/ngrok/current',
220 self::PERL_SYMLINK => $toolsPath . '/perl/current',
221 self::PYTHON_SYMLINK => $toolsPath . '/python/current',
222 self::RUBY_SYMLINK => $toolsPath . '/ruby/current',
223 self::XLIGHT_SYMLINK => $binPath . '/xlight/current',
224 self::MAILPIT_SYMLINK => $binPath . '/mailpit/current',
225 self::BRUNO_SYMLINK => $toolsPath . '/bruno/current'
226 ];
227
228 // Fix for PHP 8.2: Add null checks before accessing array elements
229 if (!is_array($array) || empty($array)) {
230 Log::error('Current symlinks array is not initialized or empty.');
231 return;
232 }
233
234 // Purge "current" symlinks with safety checks
235 foreach ($array as $name => $path) {
236 // Skip if path is null
237 if (empty($path)) {
238 continue;
239 }
240
241 if (!file_exists($path) && !is_link($path)) {
242 // Skip if the symlink doesn't exist - no need to log an error
243 continue;
244 }
245
246 // Use safe removal method with path validation and non-recursive guarantees
248 }
249 }
global $bearsamppRoot
global $bearsamppCore
static error($data, $file=null)

References $bearsamppCore, $bearsamppRoot, Log\error(), and safeRemoveSymlink().

Referenced by ActionQuit\processWindow().

◆ isPathWithinAllowedBase()

isPathWithinAllowedBase ( $path)
staticprivate

Validates that a path is within allowed symlink directories. Prevents deletion of paths outside the Bearsampp managed directories.

Parameters
string$pathThe path to validate
Returns
bool True if path is within allowed directories, false otherwise

Definition at line 60 of file class.symlinks.php.

61 {
62 global $bearsamppRoot;
63
64 // Normalize paths for comparison
65 $normalizedPath = realpath($path);
66 if ($normalizedPath === false) {
67 Log::error('Failed to resolve path: ' . $path);
68 return false;
69 }
70
71 $allowedBases = [
72 realpath($bearsamppRoot->getAppsPath()),
73 realpath($bearsamppRoot->getBinPath()),
74 realpath($bearsamppRoot->getToolsPath())
75 ];
76
77 foreach ($allowedBases as $base) {
78 if ($base === false) {
79 continue;
80 }
81
82 // Ensure path starts with allowed base (with directory separator to prevent substring matches)
83 if (strpos($normalizedPath, $base . DIRECTORY_SEPARATOR) === 0 ||
84 $normalizedPath === $base) {
85 return true;
86 }
87 }
88
89 Log::error('Path is outside allowed symlink directories: ' . $path);
90 return false;
91 }

References $bearsamppRoot, and Log\error().

◆ isSymlink()

isSymlink ( $path)
staticprivate

Checks if a path is a symlink (not following the link). Uses lstat to avoid following symlinks.

Parameters
string$pathThe path to check
Returns
bool True if path is a symlink, false otherwise

Definition at line 100 of file class.symlinks.php.

101 {
102 // Use is_link to check without following symlinks
103 return is_link($path);
104 }

◆ safeRemoveSymlink()

safeRemoveSymlink ( $path)
staticprivate

Safely removes a symlink or empty directory. CRITICAL: Does NOT recursively delete; only removes:

  • Actual symlinks (using unlink)
  • Empty directories (using rmdir)

Will NOT remove:

  • Non-empty directories
  • Files that are not symlinks
  • Paths outside allowed directories
  • Junctions or other special link types if they contain files
Parameters
string$pathThe path to remove
Returns
bool True on success, false on failure

Definition at line 121 of file class.symlinks.php.

122 {
123 // Validate path is within allowed directories
124 if (!self::isPathWithinAllowedBase($path)) {
125 Log::error('Symlink removal blocked - path not in allowed directories: ' . $path);
126 return false;
127 }
128
129 // Check if path exists
130 if (!file_exists($path) && !is_link($path)) {
131 Log::debug('Symlink does not exist: ' . $path);
132 return false;
133 }
134
135 // If it's a symlink, remove it appropriately.
136 // On Windows, directory junctions require rmdir(), not unlink(). For broken junctions,
137 // is_dir() returns false even though the link exists, so we try both methods.
138 if (self::isSymlink($path)) {
139 $removed = @unlink($path) || @rmdir($path);
140 if ($removed) {
141 Log::debug('Safely removed symlink: ' . $path);
142 return true;
143 } else {
144 Log::error('Failed to remove symlink: ' . $path);
145 return false;
146 }
147 }
148
149 // If it's a directory, only remove if empty (rmdir fails on non-empty)
150 if (is_dir($path)) {
151 // Double-check: ensure we're not attempting recursive deletion
152 $items = @scandir($path);
153 if ($items === false) {
154 Log::error('Cannot read directory contents: ' . $path);
155 return false;
156 }
157
158 // Count real items (exclude . and ..)
159 $realItems = array_diff($items, ['.', '..']);
160
161 if (!empty($realItems)) {
162 Log::warning('Directory is not empty - refusing to delete: ' . $path .
163 ' (contains ' . count($realItems) . ' items)');
164 return false;
165 }
166
167 // Directory is empty, safe to remove
168 if (@rmdir($path)) {
169 Log::debug('Safely removed empty directory: ' . $path);
170 return true;
171 } else {
172 Log::error('Failed to remove empty directory: ' . $path);
173 return false;
174 }
175 }
176
177 // Regular files should not be deleted here
178 Log::warning('Path is a regular file, not a symlink - refusing deletion: ' . $path);
179 return false;
180 }
static debug($data, $file=null)
static warning($data, $file=null)

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

Referenced by deleteCurrentSymlinks().

Field Documentation

◆ $root

$root
private

Definition at line 40 of file class.symlinks.php.

Referenced by __construct().

◆ APACHE_SYMLINK

const APACHE_SYMLINK = 'apache'

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

◆ BRUNO_SYMLINK

const BRUNO_SYMLINK = 'bruno'

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

◆ COMPOSER_SYMLINK

const COMPOSER_SYMLINK = 'composer'

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

◆ GHOSTSCRIPT_SYMLINK

const GHOSTSCRIPT_SYMLINK = 'ghostscript'

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

◆ GIT_SYMLINK

const GIT_SYMLINK = 'git'

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

◆ MAILPIT_SYMLINK

const MAILPIT_SYMLINK = 'mailpit'

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

◆ MARIADB_SYMLINK

const MARIADB_SYMLINK = 'mariadb'

Definition at line 19 of file class.symlinks.php.

◆ MEMCACHED_SYMLINK

const MEMCACHED_SYMLINK = 'memcached'

Definition at line 20 of file class.symlinks.php.

◆ MYSQL_SYMLINK

const MYSQL_SYMLINK = 'mysql'

Definition at line 21 of file class.symlinks.php.

◆ NGROK_SYMLINK

const NGROK_SYMLINK = 'ngrok'

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

◆ NODEJS_SYMLINK

const NODEJS_SYMLINK = 'nodejs'

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

◆ PERL_SYMLINK

const PERL_SYMLINK = 'perl'

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

◆ PHP_SYMLINK

const PHP_SYMLINK = 'php'

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

◆ PHPMYADMIN_SYMLINK

const PHPMYADMIN_SYMLINK = 'phpmyadmin'

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

◆ PHPPGADMIN_SYMLINK

const PHPPGADMIN_SYMLINK = 'phppgadmin'

Definition at line 17 of file class.symlinks.php.

◆ POSTGRESQL_SYMLINK

const POSTGRESQL_SYMLINK = 'postgresql'

Definition at line 24 of file class.symlinks.php.

◆ POWERSHELL_SYMLINK

const POWERSHELL_SYMLINK = 'powershell'

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

◆ PYTHON_SYMLINK

const PYTHON_SYMLINK = 'python'

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

◆ RUBY_SYMLINK

const RUBY_SYMLINK = 'ruby'

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

◆ XLIGHT_SYMLINK

const XLIGHT_SYMLINK = 'xlight'

Definition at line 33 of file class.symlinks.php.


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