143 $this->enable = $this->enable &&
$bearsamppConfig->getRaw(self::ROOT_CFG_ENABLE);
147 if ($this->bearsamppConfRaw !==
false) {
148 $this->exe = $this->symlinkPath .
'/' . $this->bearsamppConfRaw[self::LOCAL_CFG_EXE];
149 $this->conf = $this->symlinkPath .
'/' . $this->bearsamppConfRaw[self::LOCAL_CFG_CONF];
150 $this->port = $this->bearsamppConfRaw[self::LOCAL_CFG_PORT];
151 $this->rootUser = isset($this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_USER]) ? $this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_USER] :
'root';
152 $this->rootPwd = isset($this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_PWD]) ? $this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_PWD] :
'';
153 $this->cliExe = $this->symlinkPath .
'/' . $this->bearsamppConfRaw[self::LOCAL_CFG_CLI_EXE];
154 $this->admin = $this->symlinkPath .
'/' . $this->bearsamppConfRaw[self::LOCAL_CFG_ADMIN];
155 $this->dataDir = $this->symlinkPath .
'/data';
158 if (!$this->enable) {
159 Log::info($this->name .
' is not enabled!');
163 if (!is_dir($this->currentPath)) {
168 if (!is_dir($this->symlinkPath)) {
173 if (!is_file($this->bearsamppConf)) {
178 if (!is_file($this->exe)) {
183 if (!is_file($this->conf)) {
188 if (!is_numeric($this->port) || $this->port <= 0) {
193 if (empty($this->rootUser)) {
198 if (!is_file($this->cliExe)) {
203 if (!is_file($this->admin)) {
210 $this->service->setBinPath($this->exe);
211 $this->service->setParams(self::SERVICE_NAME);
223 $content = file_get_contents($this->bearsamppConf);
225 foreach ($params as $key => $value) {
226 $content = preg_replace(
'|' . $key .
' = .*|', $key .
' = ' .
'"' . $value .
'"', $content);
227 $this->bearsamppConfRaw[$key] = $value;
229 case self::LOCAL_CFG_PORT:
230 $this->port = $value;
232 case self::LOCAL_CFG_ROOT_USER:
233 $this->rootUser = $value;
235 case self::LOCAL_CFG_ROOT_PWD:
236 $this->rootPwd = $value;
241 file_put_contents($this->bearsamppConf, $content);
257 global $bearsamppWinbinder;
266 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
269 if (!$checkUsed || $isPortInUse ===
false) {
272 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
276 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
298 $startTime = microtime(
true);
312 $bearsamppWinbinder->messageBoxError(
323 static $cachedConnection =
null;
324 static $lastPort =
null;
326 if ($cachedConnection ===
null || $lastPort !==
$port) {
330 if (PHP_VERSION_ID >= 80500) {
331 $initCommandAttr = \Pdo\Mysql::ATTR_INIT_COMMAND;
333 $initCommandAttr = \PDO::MYSQL_ATTR_INIT_COMMAND;
337 \PDO::ATTR_TIMEOUT => $timeout,
338 \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
339 $initCommandAttr =>
"SET SESSION sql_mode=''"
343 $cachedConnection = new \PDO($dsn, $this->rootUser, $this->rootPwd,
$options);
345 }
catch (\PDOException $e) {
348 $bearsamppWinbinder->messageBoxWarning(
360 $stmt = $cachedConnection->query(
"SELECT @@version, @@version_comment");
361 $row = $stmt->fetch(\PDO::FETCH_NUM);
374 $bearsamppWinbinder->messageBoxWarning(
385 $bearsamppWinbinder->messageBoxInfo(
391 $totalTime = round(microtime(
true) - $startTime, 2);
392 Log::trace(
"MySQL port check completed in {$totalTime}s");
395 }
catch (\PDOException $e) {
398 $bearsamppWinbinder->messageBoxWarning(
419 global $bearsamppWinbinder;
420 $startTime = microtime(
true);
424 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
429 \PDO::ATTR_TIMEOUT => $timeout,
430 \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
434 $dbLink = new \PDO($dsn, $this->rootUser, $currentPwd,
$options);
436 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
439 $stmt = $dbLink->query(
'SELECT VERSION()');
442 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
445 if (version_compare(
$version,
'5.7.6',
'>=')) {
447 $sql =
"ALTER USER '{$this->rootUser}'@'localhost' IDENTIFIED BY :password";
448 $stmt = $dbLink->prepare($sql);
449 $stmt->bindParam(
':password', $newPwd);
452 $sql =
"SET PASSWORD FOR '{$this->rootUser}'@'localhost' = PASSWORD(:password)";
453 $stmt = $dbLink->prepare($sql);
454 $stmt->bindParam(
':password', $newPwd);
457 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
460 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
461 $dbLink->query(
'FLUSH PRIVILEGES');
463 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
466 }
catch (\PDOException $e) {
467 $error = $e->getMessage();
470 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
472 if (!empty($error)) {
473 $totalTime = round(microtime(
true) - $startTime, 2);
474 Log::trace(
"MySQL password change failed in {$totalTime}s: " . $error);
480 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
485 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
487 $totalTime = round(microtime(
true) - $startTime, 2);
488 Log::trace(
"MySQL password change completed in {$totalTime}s");
503 global $bearsamppWinbinder;
504 $startTime = microtime(
true);
505 $currentPwd = $currentPwd ==
null ? $this->rootPwd : $currentPwd;
509 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
512 static $passwordCache = [];
513 $cacheKey = md5($this->rootUser .
':' . $currentPwd .
':' . $this->port);
515 if (isset($passwordCache[$cacheKey]) && (time() - $passwordCache[$cacheKey][
'time']) < 30) {
516 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
517 $totalTime = round(microtime(
true) - $startTime, 2);
518 Log::trace(
"MySQL password check completed from cache in {$totalTime}s");
520 return $passwordCache[$cacheKey][
'result'];
526 if (PHP_VERSION_ID >= 80500) {
527 $initCommandAttr = \Pdo\Mysql::ATTR_INIT_COMMAND;
529 $initCommandAttr = \PDO::MYSQL_ATTR_INIT_COMMAND;
533 \PDO::ATTR_TIMEOUT => $timeout,
534 \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
535 $initCommandAttr =>
"SET SESSION sql_mode=''"
539 $dbLink = new \PDO($dsn, $this->rootUser, $currentPwd,
$options);
542 $dbLink->query(
'SELECT 1');
546 $passwordCache[$cacheKey] = [
550 }
catch (\PDOException $e) {
551 $error = $e->getMessage();
554 $passwordCache[$cacheKey] = [
556 'time' => time() - 25
560 $bearsamppWinbinder->incrProgressBar($wbProgressBar);
562 if (!empty($error)) {
563 $totalTime = round(microtime(
true) - $startTime, 2);
564 Log::trace(
"MySQL password check failed in {$totalTime}s: " . $error);
569 $totalTime = round(microtime(
true) - $startTime, 2);
570 Log::trace(
"MySQL password check completed in {$totalTime}s");
603 if (!$this->enable) {
608 Log::debug(($sub > 0 ? str_repeat(
' ', 2 * $sub) :
'') .
'Update ' . $this->name .
' ' .
$version .
' config');
621 Log::error(
'bearsampp config files not found for ' . $this->
getName() .
' ' . $version);
623 $bearsamppWinbinder->messageBoxError(
634 Log::error(
'bearsampp config file malformed for ' . $this->
getName() .
' ' . $version);
636 $bearsamppWinbinder->messageBoxError(
653 '/^port(.*?)=(.*?)(\d+)/' =>
'port = ' . $this->port
657 $bearsamppApps->getPhpmyadmin()->update($sub + 1);
676 Log::trace(
'Starting MySQL data initialization');
677 $startTime = microtime(
true);
682 $perfSchemaDir =
$dataDir .
'/performance_schema';
684 if (version_compare(
$version,
'5.7.0',
'<')) {
685 Log::trace(
'MySQL version below 5.7.0, skipping initialization');
693 Log::trace(
'MySQL data directory does not exist; initialization required');
696 if (!is_dir($perfSchemaDir)) {
697 Log::trace(
'performance_schema directory missing; reinitialization required');
703 Log::trace(
'MySQL data directory already initialized');
710 $backupDir =
$dataDir .
'_bak_' . date(
'Ymd_His');
711 if (@rename(
$dataDir, $backupDir)) {
712 Log::trace(
'Backed up existing data directory to: ' . $backupDir);
714 Log::trace(
'Failed to backup existing data directory; attempting to clear it');
716 $it = new \RecursiveDirectoryIterator(
$dataDir, \FilesystemIterator::SKIP_DOTS);
717 $files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
718 foreach ($files as $file) {
719 if ($file->isDir()) {
720 @rmdir($file->getPathname());
722 @unlink($file->getPathname());
726 }
catch (\Throwable $t) {
727 Log::trace(
'Error clearing data directory: ' . $t->getMessage());
734 Log::trace(
'Created clean MySQL data directory');
740 }
catch (\Throwable $e) {
741 Log::trace(
'Error during MySQL initialization via Batch: ' . $e->getMessage());
747 if (!is_dir($perfSchemaDir)) {
748 Log::trace(
'MySQL initialization appears to have failed: performance_schema still missing');
753 $totalTime = round(microtime(
true) - $startTime, 2);
754 Log::trace(
"MySQL initialization completed in {$totalTime}s");
776 if ($cmd == self::CMD_SYNTAX_CHECK) {
778 } elseif ($cmd == self::CMD_VARIABLES) {
787 if (file_exists($bin)) {
788 $tmpResult =
Batch::exec(
'mysqlGetCmdLineOutput',
'"' . $bin .
'" ' . $cmd .
' ' . $outputFrom, 5);
789 if ($tmpResult !==
false && is_array($tmpResult)) {
791 for ($i = 0; $i < $removeLines; $i++) {
792 unset($tmpResult[$i]);
794 $result[
'content'] = trim(str_replace($bin,
'', implode(PHP_EOL, $tmpResult)));
830 public function setEnable($enabled, $showWindow =
false)
835 Log::debug($this->
getName() .
' cannot be enabled because bundle ' . $this->
getVersion() .
' does not exist in ' . $this->currentPath);
837 $bearsamppWinbinder->messageBoxError(
static initializeMysql($path)
static exec($basename, $content, $timeout=true, $catchOutput=true, $standalone=false, $silent=true, $rebuild=true)
updateConfig($version=null, $sub=0, $showWindow=false)
const LOCAL_CFG_ROOT_USER
changeRootPassword($currentPwd, $newPwd, $wbProgressBar=null)
switchVersion($version, $showWindow=false)
checkPort($port, $showWindow=false)
changePort($port, $checkUsed=false, $wbProgressBar=null)
setEnable($enabled, $showWindow=false)
initData($path=null, $version=null)
reload($id=null, $type=null)
checkRootPassword($currentPwd=null, $wbProgressBar=null)
const ENABLE_BUNDLE_NOT_EXIST
const BEARSAMPP_CONF_MALFORMED_ERROR
const ERROR_EXE_NOT_FOUND
const ERROR_CONF_NOT_FOUND
const BEARSAMPP_CONF_NOT_FOUND_ERROR
const ERROR_INVALID_PARAMETER
const SWITCH_VERSION_TITLE
const PORT_USED_BY_ANOTHER_DBMS
const ERROR_FILE_NOT_FOUND
static info($data, $file=null)
static debug($data, $file=null)
static reloadClass($classInstance)
static trace($data, $file=null)
static error($data, $file=null)
static initClass($classInstance)
update($sub=0, $showWindow=false)
static invalidateConfigCacheForPath($sourcePath)
static getLogsPath($aetrayPath=false)
static getModuleCurrentPath($module)
static installService($bin, $port, $syntaxCheckCmd, $showWindow=false)
static removeService($service, $name)
static isPortInUse($port)
static isValidPort($port)
static replaceInFile($path, $replaceList)
static contains($string, $search)
static startWith($string, $search)
const SERVER_ERROR_NORMAL
const SERVICE_DEMAND_START