124 if (!self::isPathWithinAllowedBase($path)) {
125 Log::error(
'Symlink removal blocked - path not in allowed directories: ' . $path);
130 if (!file_exists($path) && !is_link($path)) {
131 Log::debug(
'Symlink does not exist: ' . $path);
138 if (self::isSymlink($path)) {
139 $removed = @unlink($path) || @rmdir($path);
141 Log::debug(
'Safely removed symlink: ' . $path);
144 Log::error(
'Failed to remove symlink: ' . $path);
152 $items = @scandir($path);
153 if ($items ===
false) {
154 Log::error(
'Cannot read directory contents: ' . $path);
159 $realItems = array_diff($items, [
'.',
'..']);
161 if (!empty($realItems)) {
162 Log::warning(
'Directory is not empty - refusing to delete: ' . $path .
163 ' (contains ' . count($realItems) .
' items)');
169 Log::debug(
'Safely removed empty directory: ' . $path);
172 Log::error(
'Failed to remove empty directory: ' . $path);
178 Log::warning(
'Path is a regular file, not a symlink - refusing deletion: ' . $path);
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'
229 if (!is_array($array) || empty($array)) {
230 Log::error(
'Current symlinks array is not initialized or empty.');
235 foreach ($array as $name => $path) {
241 if (!file_exists($path) && !is_link($path)) {