Bearsampp 2026.7.11
Loading...
Searching...
No Matches
class.action.switchVersion.php
Go to the documentation of this file.
1<?php
2/*
3 *
4 * * Copyright (c) 2022-2025 Bearsampp
5 * * License: GNU General Public License version 3 or later; see LICENSE.txt
6 * * Website: https://bearsampp.com
7 * * Github: https://github.com/Bearsampp
8 *
9 */
10
16{
18 private $version;
19 private $bin;
21 private $service;
22 private $changePort;
23 private $boxTitle;
24 private $pathsToScan = [];
25
26 const GAUGE_SERVICES = 1;
27 const GAUGE_OTHERS = 7;
28
29 // Configuration sections
30 const CONFIG_SECTION_APACHE = 'apache';
31 const CONFIG_SECTION_PHP = 'php';
32 const CONFIG_SECTION_MYSQL = 'mysql';
33 const CONFIG_SECTION_MARIADB = 'mariadb';
34 const CONFIG_SECTION_POSTGRESQL = 'postgresql';
35 const CONFIG_SECTION_NODEJS = 'nodejs';
36 const CONFIG_SECTION_MEMCACHED = 'memcached';
37 const CONFIG_SECTION_MAILPIT = 'mailpit';
38 const CONFIG_SECTION_XLIGHT = 'xlight';
39
40 // Configuration keys
41 const CONFIG_KEY_VERSION = 'version';
42
49 public function __construct($args)
50 {
51 global $bearsamppLang, $bearsamppBins, $bearsamppWinbinder;
52
53 if (isset($args[0]) && !empty($args[0]) && isset($args[1]) && !empty($args[1])) {
54 $this->pathsToScan = array();
55 $this->version = $args[1];
56
57 if ($args[0] == $bearsamppBins->getApache()->getName()) {
58 $this->bin = $bearsamppBins->getApache();
59 $this->currentVersion = $bearsamppBins->getApache()->getVersion();
60 $this->service = $bearsamppBins->getApache()->getService();
61 $this->changePort = true;
63 foreach ($folderList as $folder) {
64 $this->pathsToScan[] = array(
65 'path' => Path::getModuleRootPath($bearsamppBins->getApache()) . '/' . $folder,
66 'includes' => array('.ini', '.conf'),
67 'recursive' => true
68 );
69 }
70 } elseif ($args[0] == $bearsamppBins->getPhp()->getName()) {
71 $this->bin = $bearsamppBins->getPhp();
72 $this->currentVersion = $bearsamppBins->getPhp()->getVersion();
73 $this->service = $bearsamppBins->getApache()->getService();
74 $this->changePort = false;
76 foreach ($folderList as $folder) {
77 $this->pathsToScan[] = array(
78 'path' => Path::getModuleRootPath($bearsamppBins->getPhp()) . '/' . $folder,
79 'includes' => array('.php', '.bat', '.ini', '.reg', '.inc'),
80 'recursive' => true
81 );
82 }
83 } elseif ($args[0] == $bearsamppBins->getMysql()->getName()) {
84 $this->bin = $bearsamppBins->getMysql();
85 $this->currentVersion = $bearsamppBins->getMysql()->getVersion();
86 $this->service = $bearsamppBins->getMysql()->getService();
87 $this->changePort = true;
89 foreach ($folderList as $folder) {
90 $this->pathsToScan[] = array(
91 'path' => Path::getModuleRootPath($bearsamppBins->getMysql()) . '/' . $folder,
92 'includes' => array('my.ini'),
93 'recursive' => false
94 );
95 }
96 } elseif ($args[0] == $bearsamppBins->getMariadb()->getName()) {
97 $this->bin = $bearsamppBins->getMariadb();
98 $this->currentVersion = $bearsamppBins->getMariadb()->getVersion();
99 $this->service = $bearsamppBins->getMariadb()->getService();
100 $this->changePort = true;
101 $folderList = Util::getFolderList(Path::getModuleRootPath($bearsamppBins->getMariadb()));
102 foreach ($folderList as $folder) {
103 $this->pathsToScan[] = array(
104 'path' => Path::getModuleRootPath($bearsamppBins->getMariadb()) . '/' . $folder,
105 'includes' => array('my.ini'),
106 'recursive' => false
107 );
108 }
109 } elseif ($args[0] == $bearsamppBins->getPostgresql()->getName()) {
110 $this->bin = $bearsamppBins->getPostgresql();
111 $this->currentVersion = $bearsamppBins->getPostgresql()->getVersion();
112 $this->service = $bearsamppBins->getPostgresql()->getService();
113 $this->changePort = true;
114 $folderList = Util::getFolderList(Path::getModuleRootPath($bearsamppBins->getPostgresql()));
115 foreach ($folderList as $folder) {
116 $this->pathsToScan[] = array(
117 'path' => Path::getModuleRootPath($bearsamppBins->getPostgresql()) . '/' . $folder,
118 'includes' => array( '.conf', '.bat'),
119 'recursive' => true
120 );
121 }
122 } elseif ($args[0] == $bearsamppBins->getNodejs()->getName()) {
123 $this->bin = $bearsamppBins->getNodejs();
124 $this->currentVersion = $bearsamppBins->getNodejs()->getVersion();
125 $this->service = null;
126 $this->changePort = false;
128 foreach ($folderList as $folder) {
129 $this->pathsToScan[] = array(
130 'path' => Path::getModuleRootPath($bearsamppBins->getNodejs()) . '/' . $folder . '/etc',
131 'includes' => array('npmrc'),
132 'recursive' => true
133 );
134 $this->pathsToScan[] = array(
135 'path' => Path::getModuleRootPath($bearsamppBins->getNodejs()) . '/' . $folder . '/node_modules/npm',
136 'includes' => array('npmrc'),
137 'recursive' => false
138 );
139 }
140 } elseif ($args[0] == $bearsamppBins->getMemcached()->getName()) {
141 $this->bin = $bearsamppBins->getMemcached();
142 $this->currentVersion = $bearsamppBins->getMemcached()->getVersion();
143 $this->service = $bearsamppBins->getMemcached()->getService();
144 $this->changePort = true;
145 } elseif ($args[0] == $bearsamppBins->getMailpit()->getName()) {
146 $this->bin = $bearsamppBins->getMailpit();
147 $this->currentVersion = $bearsamppBins->getMailpit()->getVersion();
148 $this->service = $bearsamppBins->getMailpit()->getService();
149 $this->changePort = false;
150 $folderList = Util::getFolderList(Path::getModuleRootPath($bearsamppBins->getMailpit()));
151 foreach ($folderList as $folder) {
152 $this->pathsToScan[] = array(
153 'path' => Path::getModuleRootPath($bearsamppBins->getMailpit()) . '/' . $folder,
154 'includes' => array('.conf'),
155 'recursive' => true
156 );
157 }
158 } elseif ($args[0] == $bearsamppBins->getXlight()->getName()) {
159 $this->bin = $bearsamppBins->getXlight();
160 $this->currentVersion = $bearsamppBins->getXlight()->getVersion();
161 $this->service = $bearsamppBins->getXlight()->getService();
162 $this->changePort = true;
164 foreach ($folderList as $folder) {
165 $this->pathsToScan[] = array(
166 'path' => Path::getModuleRootPath($bearsamppBins->getXlight()) . '/' . $folder,
167 'includes' => array('.conf, ftpd.hosts, ftpd.option, ftpd.password, ftpd.rules, ftpd.users, .ini'),
168 'recursive' => true
169 );
170 }
171 }
172
173 $this->boxTitle = sprintf($bearsamppLang->getValue(Lang::SWITCH_VERSION_TITLE), $this->bin->getName(), $this->version);
174
175 // Start splash screen
176 $this->bearsamppSplash = new Splash();
177 $this->bearsamppSplash->init(
178 $this->boxTitle,
179 self::GAUGE_SERVICES * count($bearsamppBins->getServices()) + self::GAUGE_OTHERS,
180 $this->boxTitle
181 );
182
183 $bearsamppWinbinder->setHandler($this->bearsamppSplash->getWbWindow(), $this, 'processWindow', 1000);
184 $bearsamppWinbinder->mainLoop();
185 $bearsamppWinbinder->reset();
186 }
187 }
188
198 public function processWindow($window, $id, $ctrl, $param1, $param2)
199 {
200 global $bearsamppCore, $bearsamppLang, $bearsamppBins, $bearsamppWinbinder;
201
202 if ($this->version == $this->currentVersion) {
203 $bearsamppWinbinder->messageBoxWarning(sprintf($bearsamppLang->getValue(Lang::SWITCH_VERSION_SAME_ERROR), $this->bin->getName(), $this->version), $this->boxTitle);
204 $bearsamppWinbinder->destroyWindow($window);
205 }
206
207 // scan folder
208 $this->bearsamppSplash->incrProgressBar();
209 if (!empty($this->pathsToScan)) {
210 Path::changePath(Util::getFilesToScan($this->pathsToScan));
211 }
212
213 // switch
214 $this->bearsamppSplash->incrProgressBar();
215 if ($this->bin->switchVersion($this->version, true) === false) {
216 $this->bearsamppSplash->incrProgressBar(self::GAUGE_SERVICES * count($bearsamppBins->getServices()) + self::GAUGE_OTHERS);
217 $bearsamppWinbinder->destroyWindow($window);
218 }
219
220 // stop service
221 if ($this->service != null) {
222 $binName = $this->bin->getName() == $bearsamppLang->getValue(Lang::PHP) ? $bearsamppLang->getValue(Lang::APACHE) : $this->bin->getName();
223 $this->bearsamppSplash->setTextLoading(sprintf($bearsamppLang->getValue(Lang::STOP_SERVICE_TITLE), $binName));
224 $this->bearsamppSplash->incrProgressBar();
225 $this->service->stop();
226 // Wait for SCM to stop the service
227 usleep(2000000); // 2 seconds
228 } else {
229 $this->bearsamppSplash->incrProgressBar();
230 }
231
232 // reload config
233 $this->bearsamppSplash->setTextLoading($bearsamppLang->getValue(Lang::SWITCH_VERSION_RELOAD_CONFIG));
234 $this->bearsamppSplash->incrProgressBar();
236
237 // reload bins
238 $this->bearsamppSplash->setTextLoading($bearsamppLang->getValue(Lang::SWITCH_VERSION_RELOAD_BINS));
239 $this->bearsamppSplash->incrProgressBar();
240 $bearsamppBins->reload();
241
242 // After reloading bins, get a fresh service reference from the reloaded bin.
243 // This ensures we're using the updated service instance with new configuration.
244 if ($this->service != null) {
245 // PHP is a special case: it runs under Apache's service, not its own.
246 if ($this->bin->getName() == $bearsamppBins->getPhp()->getName()) {
247 $this->service = $bearsamppBins->getApache()->getService();
248 Log::trace("Refreshed service reference from reloaded Apache bin (for PHP)");
249 } else {
250 $freshBin = $bearsamppBins->getBinByName($this->bin->getName());
251 if ($freshBin !== null) {
252 $this->service = $freshBin->getService();
253 Log::trace("Refreshed service reference from reloaded " . $this->bin->getName() . " bin");
254 }
255 }
256 }
257
258 // change port
259 if ($this->changePort) {
260 $this->bin->reload();
261 $this->bin->changePort($this->bin->getPort());
262 }
263
264 // start service
265 if ($this->service != null) {
266 $binName = $this->bin->getName() == $bearsamppLang->getValue(Lang::PHP) ? $bearsamppLang->getValue(Lang::APACHE) : $this->bin->getName();
267 $this->bearsamppSplash->setTextLoading(sprintf($bearsamppLang->getValue(Lang::START_SERVICE_TITLE), $binName));
268 $this->bearsamppSplash->incrProgressBar();
269 $this->service->start();
270 } else {
271 $this->bearsamppSplash->incrProgressBar();
272 }
273
274 $this->bearsamppSplash->incrProgressBar(self::GAUGE_SERVICES * count($bearsamppBins->getServices()) + 1);
275
276 // Update configuration file with the new version
277 Log::trace('Updating ini & menu...');
278 $this->updateConfigVersion();
279
280 // Store current registry value for comparison
281 global $bearsamppRegistry;
282 $currentRegValue = $bearsamppRegistry->getAppBinsRegKey(false);
284
285 Log::trace(sprintf(
286 'Starting registry adjustment for key: %s | Current value: %s',
287 $regEntry,
288 $currentRegValue
289 ));
290
291 // Perform the registry update
292 $newRegValue = $bearsamppRegistry->setAppBinsRegKey($currentRegValue);
293
294 $this->bearsamppSplash->setTextLoading(sprintf(
296 $regEntry
297 ));
298
299 $this->bearsamppSplash->incrProgressBar(2);
300 Log::trace(sprintf(
301 'Registry update completed | Key: %s | New value: %s | Previous value: %s',
302 $regEntry,
303 $newRegValue,
304 $currentRegValue
305 ));
306
307 $this->bearsamppSplash->setTextLoading($bearsamppLang->getValue(Lang::SWITCH_VERSION_RESET_SERVICES));
308
309 // For version switches, services are properly restarted above
310 // No additional service reset/delete is needed
311 // The service is now running with the new version
312 Log::trace('Version switch complete - service restarted with new version');
313 $this->bearsamppSplash->incrProgressBar();
314
315 // Compensate progress bar for all services (none are being reset)
316 $remainingServicesCount = count($bearsamppBins->getServices());
317 if ($remainingServicesCount > 0) {
318 $this->bearsamppSplash->incrProgressBar($remainingServicesCount);
319 }
320
321 Log::trace('Version switch process completed successfully');
322
323 Log::trace('Creating modal...');
324 $bearsamppWinbinder->messageBoxInfo(
325 sprintf($bearsamppLang->getValue(Lang::SWITCH_VERSION_OK), $this->bin->getName(), $this->version),
326 $this->boxTitle
327 );
328
329 Log::trace('Destroying splash window...');
330 $bearsamppWinbinder->destroyWindow($window);
331 }
332
337 private function updateConfigVersion(): void
338 {
339 $bearsamppConfig = new Config();
340 $configSection = '';
341 $version = $this->version; // Ensure version is available in scope
342
343 // Determine the correct configuration section based on binary type
344 if ($this->bin->getName() == $GLOBALS['bearsamppBins']->getApache()->getName()) {
345 $configSection = self::CONFIG_SECTION_APACHE;
346 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
347 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getPhp()->getName()) {
348 $configSection = self::CONFIG_SECTION_PHP;
349 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
350 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getMysql()->getName()) {
351 $configSection = self::CONFIG_SECTION_MYSQL;
352 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
353 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getMariadb()->getName()) {
354 $configSection = self::CONFIG_SECTION_MARIADB;
355 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
356 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getPostgresql()->getName()) {
357 $configSection = self::CONFIG_SECTION_POSTGRESQL;
358 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
359 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getNodejs()->getName()) {
360 $configSection = self::CONFIG_SECTION_NODEJS;
361 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
362 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getMemcached()->getName()) {
363 $configSection = self::CONFIG_SECTION_MEMCACHED;
364 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
365 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getMailpit()->getName()) {
366 $configSection = self::CONFIG_SECTION_MAILPIT;
367 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
368 } elseif ($this->bin->getName() == $GLOBALS['bearsamppBins']->getXlight()->getName()) {
369 $configSection = self::CONFIG_SECTION_XLIGHT;
370 Log::trace(sprintf('Switch %s version to %s', $configSection, $version));
371 }
372
373 // Update the configuration if a valid section was found
374 if (!empty($configSection)) {
375 Log::trace('Updating .ini file...');
376 $bearsamppConfig->replace($configSection, self::CONFIG_KEY_VERSION, $version);
377
378 // Update tray menu display if TrayMenu class is available
379 Log::trace('Updating TrayMenu...');
380 if (class_exists('TrayMenu')) {
381 $trayMenu = TrayMenu::getInstance();
382 if (method_exists($trayMenu, 'updateSectionVersion')) {
383 $trayMenu->updateSectionVersion(
384 strtoupper($configSection),
386 );
387 }
388 }
389 }
390 Log::trace('Returning to parent call');
391 }
392}
global $bearsamppBins
global $bearsamppLang
global $bearsamppCore
processWindow($window, $id, $ctrl, $param1, $param2)
const SWITCH_VERSION_RELOAD_CONFIG
const SWITCH_VERSION_RELOAD_BINS
const START_SERVICE_TITLE
const SWITCH_VERSION_REGISTRY
const SWITCH_VERSION_OK
const STOP_SERVICE_TITLE
const PHP
const APACHE
const SWITCH_VERSION_SAME_ERROR
const SWITCH_VERSION_TITLE
const SWITCH_VERSION_RESET_SERVICES
static trace($data, $file=null)
static changePath($filesToScan, $rootPath=null)
static getModuleRootPath($module)
const APP_BINS_REG_ENTRY
static loadConfig()
static getFolderList($path)
static getFilesToScan($path=null, $useCache=true, $forceRefresh=false)
global $bearsamppConfig
Definition homepage.php:41