Bearsampp 2025.8.29
Loading...
Searching...
No Matches
class.bin.mariadb.php
Go to the documentation of this file.
1<?php
2/*
3 * Copyright (c) 2021-2024 Bearsampp
4 * License: GNU General Public License version 3 or later; see LICENSE.txt
5 * Author: Bear
6 * Website: https://bearsampp.com
7 * Github: https://github.com/Bearsampp
8 */
9
16class BinMariadb extends Module
17{
18 const SERVICE_NAME = 'bearsamppmariadb';
19
20 const ROOT_CFG_ENABLE = 'mariadbEnable';
21 const ROOT_CFG_VERSION = 'mariadbVersion';
22
23 const LOCAL_CFG_EXE = 'mariadbExe';
24 const LOCAL_CFG_CLI_EXE = 'mariadbCliExe';
25 const LOCAL_CFG_ADMIN = 'mariadbAdmin';
26 const LOCAL_CFG_CONF = 'mariadbConf';
27 const LOCAL_CFG_PORT = 'mariadbPort';
28 const LOCAL_CFG_ROOT_USER = 'mariadbRootUser';
29 const LOCAL_CFG_ROOT_PWD = 'mariadbRootPwd';
30
31 const CMD_VERSION = '--version';
32 const CMD_VARIABLES = 'variables';
33 const CMD_SYNTAX_CHECK = '--help --verbose 1>NUL';
34
35 private $service;
36 private $errorLog;
37
38 private $exe;
39 private $conf;
40 private $port;
41 private $rootUser;
42 private $rootPwd;
43 private $cliExe;
44 private $admin;
45
52 public function __construct($id, $type)
53 {
54 Util::logInitClass( $this );
55 $this->reload( $id, $type );
56 }
57
64 public function reload($id = null, $type = null)
65 {
67 Util::logReloadClass( $this );
68
69 $this->name = $bearsamppLang->getValue( Lang::MARIADB );
70 $this->version = $bearsamppConfig->getRaw( self::ROOT_CFG_VERSION );
71 parent::reload( $id, $type );
72
73 $this->enable = $this->enable && $bearsamppConfig->getRaw( self::ROOT_CFG_ENABLE );
74 $this->service = new Win32Service( self::SERVICE_NAME );
75 $this->errorLog = $bearsamppRoot->getLogsPath() . '/mariadb.log';
76
77 if ( $this->bearsamppConfRaw !== false ) {
78 $this->exe = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_EXE];
79 $this->conf = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_CONF];
80 $this->port = $this->bearsamppConfRaw[self::LOCAL_CFG_PORT];
81 $this->rootUser = isset( $this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_USER] ) ? $this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_USER] : 'root';
82 $this->rootPwd = isset( $this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_PWD] ) ? $this->bearsamppConfRaw[self::LOCAL_CFG_ROOT_PWD] : '';
83 $this->cliExe = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_CLI_EXE];
84 $this->admin = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_ADMIN];
85 }
86
87 if ( !$this->enable ) {
88 Util::logInfo( $this->name . ' is not enabled!' );
89
90 return;
91 }
92 if ( !is_dir( $this->currentPath ) ) {
93 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_FILE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->currentPath ) );
94
95 return;
96 }
97 if ( !is_dir( $this->symlinkPath ) ) {
98 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_FILE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->symlinkPath ) );
99
100 return;
101 }
102 if ( !is_file( $this->bearsamppConf ) ) {
103 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->bearsamppConf ) );
104
105 return;
106 }
107 if ( !is_file( $this->exe ) ) {
108 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_EXE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->exe ) );
109
110 return;
111 }
112 if ( !is_file( $this->conf ) ) {
113 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->conf ) );
114
115 return;
116 }
117 if ( !is_numeric( $this->port ) || $this->port <= 0 ) {
118 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_INVALID_PARAMETER ), self::LOCAL_CFG_PORT, $this->port ) );
119
120 return;
121 }
122 if ( empty( $this->rootUser ) ) {
123 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_INVALID_PARAMETER ), self::LOCAL_CFG_ROOT_USER, $this->rootUser ) );
124
125 return;
126 }
127 if ( !is_file( $this->cliExe ) ) {
128 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_EXE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->cliExe ) );
129
130 return;
131 }
132 if ( !is_file( $this->admin ) ) {
133 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_EXE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->admin ) );
134
135 return;
136 }
137
138 $this->service->setDisplayName( APP_TITLE . ' ' . $this->getName() );
139 $this->service->setBinPath( $this->exe );
140 $this->service->setParams( self::SERVICE_NAME );
141 $this->service->setStartType( Win32Service::SERVICE_DEMAND_START );
142 $this->service->setErrorControl( Win32Service::SERVER_ERROR_NORMAL );
143 }
144
150 protected function replaceAll($params)
151 {
152 $content = file_get_contents( $this->bearsamppConf );
153
154 foreach ( $params as $key => $value ) {
155 $content = preg_replace( '|' . $key . ' = .*|', $key . ' = ' . '"' . $value . '"', $content );
156 $this->bearsamppConfRaw[$key] = $value;
157 switch ( $key ) {
158 case self::LOCAL_CFG_PORT:
159 $this->port = $value;
160 break;
161 case self::LOCAL_CFG_ROOT_USER:
162 $this->rootUser = $value;
163 break;
164 case self::LOCAL_CFG_ROOT_PWD:
165 $this->rootPwd = $value;
166 break;
167 }
168 }
169
170 file_put_contents( $this->bearsamppConf, $content );
171 }
172
182 public function changePort($port, $checkUsed = false, $wbProgressBar = null)
183 {
184 global $bearsamppWinbinder;
185
186 if ( !Util::isValidPort( $port ) ) {
187 Util::logError( $this->getName() . ' port not valid: ' . $port );
188
189 return false;
190 }
191
192 $port = intval( $port );
193 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
194
195 $isPortInUse = Util::isPortInUse( $port );
196 if ( !$checkUsed || $isPortInUse === false ) {
197 // bearsampp.conf
198 $this->setPort( $port );
199 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
200
201 // conf
202 $this->update();
203 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
204
205 return true;
206 }
207
208 Util::logDebug( $this->getName() . ' port in used: ' . $port . ' - ' . $isPortInUse );
209
210 return $isPortInUse;
211 }
212
221 public function checkPort($port, $showWindow = false)
222 {
223 global $bearsamppLang, $bearsamppWinbinder;
224 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::CHECK_PORT_TITLE ), $this->getName(), $port );
225
226 if ( !Util::isValidPort( $port ) ) {
227 Util::logError( $this->getName() . ' port not valid: ' . $port );
228
229 return false;
230 }
231
232 $fp = @fsockopen( '127.0.0.1', $port, $errno, $errstr, 5 );
233 if ( $fp ) {
234 if ( version_compare( phpversion(), '5.3' ) === -1 ) {
235 $dbLink = mysqli_connect( '127.0.0.1', $this->rootUser, $this->rootPwd, '', $port );
236 }
237 else {
238 $dbLink = mysqli_connect( '127.0.0.1:' . $port, $this->rootUser, $this->rootPwd );
239 }
240 $isMariadb = false;
241 $version = false;
242
243 if ( $dbLink ) {
244 $result = mysqli_query( $dbLink, 'SHOW VARIABLES' );
245 if ( $result ) {
246 while ( false !== ($row = mysqli_fetch_array( $result, MYSQLI_NUM )) ) {
247 if ( $row[0] == 'version' ) {
248 $version = explode( '-', $row[1] );
249 $version = count( $version ) > 1 ? $version[0] : $row[1];
250 }
251 if ( $row[0] == 'version_comment' && Util::startWith( strtolower( $row[1] ), 'mariadb' ) ) {
252 $isMariadb = true;
253 }
254 if ( $isMariadb && $version !== false ) {
255 break;
256 }
257 }
258 if ( !$isMariadb ) {
259 Util::logDebug( $this->getName() . ' port used by another DBMS: ' . $port );
260 if ( $showWindow ) {
261 $bearsamppWinbinder->messageBoxWarning(
263 $boxTitle
264 );
265 }
266 }
267 else {
268 Util::logDebug( $this->getName() . ' port ' . $port . ' is used by: ' . $this->getName() . ' ' . $version );
269 if ( $showWindow ) {
270 $bearsamppWinbinder->messageBoxInfo(
271 sprintf( $bearsamppLang->getValue( Lang::PORT_USED_BY ), $port, $this->getName() . ' ' . $version ),
272 $boxTitle
273 );
274 }
275
276 return true;
277 }
278 }
279 mysqli_close( $dbLink );
280 }
281 else {
282 Util::logDebug( $this->getName() . ' port ' . $port . ' is used by another application' );
283 if ( $showWindow ) {
284 $bearsamppWinbinder->messageBoxWarning(
285 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED_BY ), $port ),
286 $boxTitle
287 );
288 }
289 }
290 }
291 else {
292 Util::logDebug( $this->getName() . ' port ' . $port . ' is not used' );
293 if ( $showWindow ) {
294 $bearsamppWinbinder->messageBoxError(
295 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED ), $port ),
296 $boxTitle
297 );
298 }
299 }
300
301 return false;
302 }
303
313 public function changeRootPassword($currentPwd, $newPwd, $wbProgressBar = null)
314 {
315 global $bearsamppWinbinder;
316 $error = null;
317
318 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
319 if ( version_compare( phpversion(), '5.3' ) === -1 ) {
320 $dbLink = @mysqli_connect( '127.0.0.1', $this->rootUser, $currentPwd, '', $this->port );
321 }
322 else {
323 $dbLink = @mysqli_connect( '127.0.0.1:' . $this->port, $this->rootUser, $currentPwd );
324 }
325 if ( !$dbLink ) {
326 $error = mysqli_connect_error();
327 }
328
329 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
330 $stmt = @mysqli_prepare( $dbLink, 'UPDATE mysql.user SET Password=PASSWORD(?) WHERE User=?' );
331 if ( empty( $error ) && $stmt === false ) {
332 $error = mysqli_error( $dbLink );
333 }
334
335 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
336 if ( empty( $error ) && !@mysqli_stmt_bind_param( $stmt, 'ss', $newPwd, $this->rootUser ) ) {
337 $error = mysqli_stmt_error( $stmt );
338 }
339
340 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
341 if ( empty( $error ) && !@mysqli_stmt_execute( $stmt ) ) {
342 $error = mysqli_stmt_error( $stmt );
343 }
344
345 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
346 if ( $stmt !== false ) {
347 mysqli_stmt_close( $stmt );
348 }
349
350 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
351 if ( empty( $error ) && @mysqli_query( $dbLink, 'FLUSH PRIVILEGES' ) === false ) {
352 $error = mysqli_error( $dbLink );
353 }
354
355 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
356 if ( $dbLink ) {
357 mysqli_close( $dbLink );
358 }
359
360 if ( !empty( $error ) ) {
361 return $error;
362 }
363
364 // bearsampp.conf
365 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
366 $this->setRootPwd( $newPwd );
367
368 // conf
369 $this->update();
370 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
371
372 return true;
373 }
374
383 public function checkRootPassword($currentPwd = null, $wbProgressBar = null)
384 {
385 global $bearsamppWinbinder;
386 $currentPwd = $currentPwd == null ? $this->rootPwd : $currentPwd;
387 $error = null;
388
389 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
390 if ( version_compare( phpversion(), '5.3' ) === -1 ) {
391 $dbLink = @mysqli_connect( '127.0.0.1', $this->rootUser, $currentPwd, '', $this->port );
392 }
393 else {
394 $dbLink = @mysqli_connect( '127.0.0.1:' . $this->port, $this->rootUser, $currentPwd );
395 }
396 if ( !$dbLink ) {
397 $error = mysqli_connect_error();
398 }
399
400 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
401 if ( $dbLink ) {
402 mysqli_close( $dbLink );
403 }
404
405 if ( !empty( $error ) ) {
406 return $error;
407 }
408
409 return true;
410 }
411
420 public function switchVersion($version, $showWindow = false)
421 {
422 Util::logDebug( 'Switch ' . $this->name . ' version to ' . $version );
423
424 return $this->updateConfig( $version, 0, $showWindow );
425 }
426
436 protected function updateConfig($version = null, $sub = 0, $showWindow = false) {
437 global $bearsamppLang, $bearsamppApps, $bearsamppWinbinder;
438
439 if (!$this->enable) {
440 return true;
441 }
442
443 $version = $version == null ? $this->version : $version;
444 Util::logDebug(($sub > 0 ? str_repeat(' ', 2 * $sub) : '') . 'Update ' . $this->name . ' ' . $version . ' config');
445
446 $boxTitle = sprintf($bearsamppLang->getValue(Lang::SWITCH_VERSION_TITLE), $this->getName(), $version);
447
448 $conf = str_replace('mariadb' . $this->getVersion(), 'mariadb' . $version, $this->getConf());
449 $bearsamppConf = str_replace('mariadb' . $this->getVersion(), 'mariadb' . $version, $this->bearsamppConf);
450
451 if (!file_exists($conf) || !file_exists($bearsamppConf)) {
452 Util::logError('bearsampp config files not found for ' . $this->getName() . ' ' . $version);
453 if ($showWindow) {
454 $bearsamppWinbinder->messageBoxError(
455 sprintf($bearsamppLang->getValue(Lang::BEARSAMPP_CONF_NOT_FOUND_ERROR), $this->getName() . ' ' . $version),
456 $boxTitle
457 );
458 }
459 return false;
460 }
461
462 $bearsamppConfRaw = parse_ini_file($bearsamppConf);
463 if ($bearsamppConfRaw === false || !isset($bearsamppConfRaw[self::ROOT_CFG_VERSION]) || $bearsamppConfRaw[self::ROOT_CFG_VERSION] != $version) {
464 Util::logError('bearsampp config file malformed for ' . $this->getName() . ' ' . $version);
465 if ($showWindow) {
466 $bearsamppWinbinder->messageBoxError(
467 sprintf($bearsamppLang->getValue(Lang::BEARSAMPP_CONF_MALFORMED_ERROR), $this->getName() . ' ' . $version),
468 $boxTitle
469 );
470 }
471 return false;
472 }
473
474 // bearsampp.conf
475 $this->setVersion($version);
476
477 // conf
478 Util::replaceInFile($this->getConf(), array(
479 '/^port(.*?)=(.*?)(\d+)/' => 'port = ' . $this->port
480 ));
481
482 // phpmyadmin
483 $bearsamppApps->getPhpmyadmin()->update($sub + 1);
484
485 return true;
486 }
487
495public function getCmdLineOutput($cmd) {
496 $result = array(
497 'syntaxOk' => false,
498 'content' => null,
499 );
500
501 $bin = $this->getExe();
502 $removeLines = 0;
503 $outputFrom = '';
504 if ($cmd == self::CMD_SYNTAX_CHECK) {
505 $outputFrom = '2';
506 } elseif ($cmd == self::CMD_VARIABLES) {
507 $bin = $this->getAdmin();
508 $cmd .= ' --user=' . $this->getRootUser();
509 if ($this->getRootPwd()) {
510 $cmd .= ' --password=' . $this->getRootPwd();
511 }
512 $removeLines = 2;
513 }
514
515 if (file_exists($bin)) {
516 $tmpResult = Batch::exec('mariadbGetCmdLineOutput', '"' . $bin . '" ' . $cmd . ' ' . $outputFrom, 5);
517 if ($tmpResult !== false && is_array($tmpResult)) {
518 $result['syntaxOk'] = empty($tmpResult) || !Util::contains(trim($tmpResult[count($tmpResult) - 1]), '[ERROR]');
519 for ($i = 0; $i < $removeLines; $i++) {
520 unset($tmpResult[$i]);
521 }
522 $result['content'] = trim(str_replace($bin, '', implode(PHP_EOL, $tmpResult)));
523 }
524 }
525
526 return $result;
527}
528
534public function setVersion($version) {
535 global $bearsamppConfig;
536 $this->version = $version;
537 $bearsamppConfig->replace(self::ROOT_CFG_VERSION, $version);
538 $this->reload();
539}
540
546public function getService() {
547 return $this->service;
548}
549
556public function setEnable($enabled, $showWindow = false) {
557 global $bearsamppConfig, $bearsamppLang, $bearsamppWinbinder;
558
559 if ($enabled == Config::ENABLED && !is_dir($this->currentPath)) {
560 Util::logDebug($this->getName() . ' cannot be enabled because bundle ' . $this->getVersion() . ' does not exist in ' . $this->currentPath);
561 if ($showWindow) {
562 $bearsamppWinbinder->messageBoxError(
563 sprintf($bearsamppLang->getValue(Lang::ENABLE_BUNDLE_NOT_EXIST), $this->getName(), $this->getVersion(), $this->currentPath),
564 sprintf($bearsamppLang->getValue(Lang::ENABLE_TITLE), $this->getName())
565 );
566 }
567 $enabled = Config::DISABLED;
568 }
569
570 Util::logInfo($this->getName() . ' switched to ' . ($enabled == Config::ENABLED ? 'enabled' : 'disabled'));
571 $this->enable = $enabled == Config::ENABLED;
572 $bearsamppConfig->replace(self::ROOT_CFG_ENABLE, $enabled);
573
574 $this->reload();
575 if ($this->enable) {
576 Util::installService($this, $this->port, self::CMD_SYNTAX_CHECK, $showWindow);
577 } else {
578 Util::removeService($this->service, $this->name);
579 }
580}
581
587public function getErrorLog() {
588 return $this->errorLog;
589}
590
596public function getExe() {
597 return $this->exe;
598}
599
605public function getConf() {
606 return $this->conf;
607}
608
614public function getPort() {
615 return $this->port;
616}
617
623public function setPort($port) {
624 $this->replace(self::LOCAL_CFG_PORT, $port);
625}
626
632public function getRootUser() {
633 return $this->rootUser;
634}
635
641public function setRootUser($rootUser) {
642 $this->replace(self::LOCAL_CFG_ROOT_USER, $rootUser);
643}
644
650public function getRootPwd() {
651 return $this->rootPwd;
652}
653
659public function setRootPwd($rootPwd) {
660 $this->replace(self::LOCAL_CFG_ROOT_PWD, $rootPwd);
661}
662
668public function getCliExe() {
669 return $this->cliExe;
670}
671
677public function getAdmin() {
678 return $this->admin;
679}}
$result
global $bearsamppLang
global $bearsamppRoot
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
setRootUser($rootUser)
changeRootPassword($currentPwd, $newPwd, $wbProgressBar=null)
switchVersion($version, $showWindow=false)
setVersion($version)
checkPort($port, $showWindow=false)
changePort($port, $checkUsed=false, $wbProgressBar=null)
setEnable($enabled, $showWindow=false)
reload($id=null, $type=null)
__construct($id, $type)
checkRootPassword($currentPwd=null, $wbProgressBar=null)
setRootPwd($rootPwd)
const DISABLED
const ENABLED
const MARIADB
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 PORT_NOT_USED
const ERROR_INVALID_PARAMETER
const ENABLE_TITLE
const PORT_NOT_USED_BY
const SWITCH_VERSION_TITLE
const CHECK_PORT_TITLE
const PORT_USED_BY
const PORT_USED_BY_ANOTHER_DBMS
const ERROR_FILE_NOT_FOUND
update($sub=0, $showWindow=false)
replace($key, $value)
static logError($data, $file=null)
static installService($bin, $port, $syntaxCheckCmd, $showWindow=false)
static logInitClass($classInstance)
static removeService($service, $name)
static isValidPort($port)
static logInfo($data, $file=null)
static contains($string, $search)
static logDebug($data, $file=null)
static logReloadClass($classInstance)
static startWith($string, $search)
static isPortInUse($port)
static replaceInFile($path, $replaceList)
global $bearsamppConfig
Definition homepage.php:27
const APP_TITLE
Definition root.php:13