2024.8.23
Loading...
Searching...
No Matches
class.bin.apache.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
10/**
11 * Class BinApache
12 *
13 * This class represents the Apache module in the Bearsampp application.
14 * It provides functionalities to manage Apache services, configurations, and modules.
15 */
16class BinApache extends Module
17{
18 const SERVICE_NAME = 'bearsamppapache';
19 const SERVICE_PARAMS = '-k runservice';
20
21 const ROOT_CFG_ENABLE = 'apacheEnable';
22 const ROOT_CFG_VERSION = 'apacheVersion';
23
24 const LOCAL_CFG_EXE = 'apacheExe';
25 const LOCAL_CFG_CONF = 'apacheConf';
26 const LOCAL_CFG_PORT = 'apachePort';
27 const LOCAL_CFG_SSL_PORT = 'apacheSslPort';
28 const LOCAL_CFG_OPENSSL_EXE = 'apacheOpensslExe';
29
30 const CMD_VERSION_NUMBER = '-v';
34 const CMD_VHOSTS_SETTINGS = '-S';
35 const CMD_LOADED_MODULES = '-M';
36 const CMD_SYNTAX_CHECK = '-t';
37
38 const TAG_START_SWITCHONLINE = '# START switchOnline tag - Do not replace!';
39 const TAG_END_SWITCHONLINE = '# END switchOnline tag - Do not replace!';
40
41 private $service;
42 private $modulesPath;
43 private $sslConf;
44 private $accessLog;
45 private $rewriteLog;
46 private $errorLog;
47
48 private $exe;
49 private $conf;
50 private $port;
51 private $sslPort;
52 private $opensslExe;
53
54 /**
55 * Constructor for the BinApache class.
56 *
57 * @param string $id The ID of the module.
58 * @param string $type The type of the module.
59 */
60 public function __construct($id, $type)
61 {
62 Util::logInitClass( $this );
63 $this->reload( $id, $type );
64 }
65
66 /**
67 * Reloads the module configuration based on the provided ID and type.
68 *
69 * @param string|null $id The ID of the module. If null, the current ID is used.
70 * @param string|null $type The type of the module. If null, the current type is used.
71 */
72 public function reload($id = null, $type = null)
73 {
75 Util::logReloadClass( $this );
76
77 $this->name = $bearsamppLang->getValue( Lang::APACHE );
78 $this->version = $bearsamppConfig->getRaw( self::ROOT_CFG_VERSION );
79 parent::reload( $id, $type );
80
81 $this->enable = $this->enable && $bearsamppConfig->getRaw( self::ROOT_CFG_ENABLE );
82 $this->service = new Win32Service( self::SERVICE_NAME );
83 $this->modulesPath = $this->symlinkPath . '/modules';
84 $this->sslConf = $this->symlinkPath . '/conf/extra/httpd-ssl.conf';
85 $this->accessLog = $bearsamppRoot->getLogsPath() . '/apache_access.log';
86 $this->rewriteLog = $bearsamppRoot->getLogsPath() . '/apache_rewrite.log';
87 $this->errorLog = $bearsamppRoot->getLogsPath() . '/apache_error.log';
88
89 if ( $this->bearsamppConfRaw !== false ) {
90 $this->exe = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_EXE];
91 $this->conf = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_CONF];
92 $this->port = $this->bearsamppConfRaw[self::LOCAL_CFG_PORT];
93 $this->sslPort = $this->bearsamppConfRaw[self::LOCAL_CFG_SSL_PORT];
94 $this->opensslExe = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_OPENSSL_EXE];
95 }
96
97 if ( !$this->enable ) {
98 Util::logInfo( $this->name . ' is not enabled!' );
99
100 return;
101 }
102 if ( !is_dir( $this->currentPath ) ) {
103 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_FILE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->currentPath ) );
104
105 return;
106 }
107 if ( !is_dir( $this->symlinkPath ) ) {
108 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_FILE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->symlinkPath ) );
109
110 return;
111 }
112 if ( !is_file( $this->bearsamppConf ) ) {
113 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->bearsamppConf ) );
114
115 return;
116 }
117 if ( !is_file( $this->sslConf ) ) {
118 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->sslConf ) );
119
120 return;
121 }
122 if ( !is_file( $this->exe ) ) {
123 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_EXE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->exe ) );
124
125 return;
126 }
127 if ( !is_file( $this->conf ) ) {
128 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->conf ) );
129
130 return;
131 }
132 if ( !is_numeric( $this->port ) || $this->port <= 0 ) {
133 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_INVALID_PARAMETER ), self::LOCAL_CFG_PORT, $this->port ) );
134
135 return;
136 }
137 if ( !is_numeric( $this->sslPort ) || $this->sslPort <= 0 ) {
138 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_INVALID_PARAMETER ), self::LOCAL_CFG_SSL_PORT, $this->sslPort ) );
139
140 return;
141 }
142 if ( !is_file( $this->opensslExe ) ) {
143 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_EXE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->opensslExe ) );
144
145 return;
146 }
147
148 $nssm = new Nssm( self::SERVICE_NAME );
149 $nssm->setDisplayName( APP_TITLE . ' ' . $this->getName() );
150 $nssm->setBinPath( $this->exe );
151 $nssm->setStart( Nssm::SERVICE_DEMAND_START );
152
153 $this->service->setNssm( $nssm );
154 }
155
156 /**
157 * Replaces multiple key-value pairs in the configuration file.
158 *
159 * @param array $params An associative array of key-value pairs to replace.
160 */
161 protected function replaceAll($params)
162 {
163 $content = file_get_contents( $this->bearsamppConf );
164
165 foreach ( $params as $key => $value ) {
166 $content = preg_replace( '|' . $key . ' = .*|', $key . ' = ' . '"' . $value . '"', $content );
167 $this->bearsamppConfRaw[$key] = $value;
168 switch ( $key ) {
170 $this->port = $value;
171 break;
173 $this->sslPort = $value;
174 break;
175 }
176 }
177
178 file_put_contents( $this->bearsamppConf, $content );
179 }
180
181 /**
182 * Changes the port for the Apache service.
183 *
184 * @param int $port The new port number.
185 * @param bool $checkUsed Whether to check if the port is already in use.
186 * @param mixed $wbProgressBar The progress bar object for updating progress.
187 *
188 * @return bool|string True if the port was changed successfully, or the process using the port if it is in use.
189 */
190 public function changePort($port, $checkUsed = false, $wbProgressBar = null)
191 {
192 global $bearsamppWinbinder;
193
194 if ( !Util::isValidPort( $port ) ) {
195 Util::logError( $this->getName() . ' port not valid: ' . $port );
196
197 return false;
198 }
199
200 $port = intval( $port );
201 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
202
203 $isPortInUse = Util::isPortInUse( $port );
204 if ( !$checkUsed || $isPortInUse === false ) {
205 // bearsampp.conf
206 $this->setPort( $port );
207 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
208
209 // conf
210 $this->update();
211 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
212
213 return true;
214 }
215
216 Util::logDebug( $this->getName() . ' port in used: ' . $port . ' - ' . $isPortInUse );
217
218 return $isPortInUse;
219 }
220
221 /**
222 * Checks if a specific port is being used by the Apache service.
223 *
224 * @param int $port The port number to check.
225 * @param bool $ssl Whether to check for SSL.
226 * @param bool $showWindow Whether to show a window with the result.
227 *
228 * @return bool True if the port is used by Apache, false otherwise.
229 */
230 public function checkPort($port, $ssl = false, $showWindow = false)
231 {
232 global $bearsamppLang, $bearsamppWinbinder, $bearsamppHomepage;
233 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::CHECK_PORT_TITLE ), $this->getName(), $port );
234
235 if ( !Util::isValidPort( $port ) ) {
236 Util::logError( $this->getName() . ' port not valid: ' . $port );
237
238 return false;
239 }
240
241 $headers = Util::getHttpHeaders( 'http' . ($ssl ? 's' : '') . '://localhost:' . $port . '/' . $bearsamppHomepage->getResourcesPath() . '/ping.php' );
242 if ( !empty( $headers ) ) {
243 foreach ( $headers as $row ) {
244 if ( Util::startWith( $row, 'Server: ' ) || Util::startWith( $row, 'server: ' ) ) {
245 Util::logDebug( $this->getName() . ' port ' . $port . ' is used by: ' . $this->getName() . ' ' . str_replace( 'Server: ', '', str_replace( 'server: ', '', trim( $row ) ) ) );
246 if ( $showWindow ) {
247 $bearsamppWinbinder->messageBoxInfo(
248 sprintf( $bearsamppLang->getValue( Lang::PORT_USED_BY ), $port, str_replace( 'Server: ', '', str_replace( 'server: ', '', trim( $row ) ) ) ),
249 $boxTitle
250 );
251 }
252
253 return true;
254 }
255 }
256 Util::logDebug( $this->getName() . ' port ' . $port . ' is used by another application' );
257 if ( $showWindow ) {
258 $bearsamppWinbinder->messageBoxWarning(
259 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED_BY ), $port ),
260 $boxTitle
261 );
262 }
263 }
264 else {
265 Util::logDebug( $this->getName() . ' port ' . $port . ' is not used' );
266 if ( $showWindow ) {
267 $bearsamppWinbinder->messageBoxError(
268 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED ), $port ),
269 $boxTitle
270 );
271 }
272 }
273
274 return false;
275 }
276
277 /**
278 * Switches the Apache version.
279 *
280 * @param string $version The version to switch to.
281 * @param bool $showWindow Whether to show a window with the result.
282 *
283 * @return bool True if the version was switched successfully, false otherwise.
284 */
285 public function switchVersion($version, $showWindow = false)
286 {
287 Util::logDebug( 'Switch ' . $this->name . ' version to ' . $version );
288
289 return $this->updateConfig( $version, 0, $showWindow );
290 }
291
292 /**
293 * Updates the Apache configuration with a specific version.
294 *
295 * @param string|null $version The version to update to. If null, the current version is used.
296 * @param int $sub The sub-level for logging indentation.
297 * @param bool $showWindow Whether to show a window during the update process.
298 *
299 * @return bool True if the configuration was updated successfully, false otherwise.
300 */
301 protected function updateConfig($version = null, $sub = 0, $showWindow = false)
302 {
303 global $bearsamppRoot, $bearsamppLang, $bearsamppBins, $bearsamppWinbinder;
304
305 if ( !$this->enable ) {
306 return true;
307 }
308
309 $version = $version == null ? $this->version : $version;
310 Util::logDebug( ($sub > 0 ? str_repeat( ' ', 2 * $sub ) : '') . 'Update ' . $this->name . ' ' . $version . ' config' );
311
312 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::SWITCH_VERSION_TITLE ), $this->getName(), $version );
313
314 $conf = str_replace( 'apache' . $this->getVersion(), 'apache' . $version, $this->getConf() );
315 $bearsamppConf = str_replace( 'apache' . $this->getVersion(), 'apache' . $version, $this->bearsamppConf );
316
317 $tsDll = $bearsamppBins->getPhp()->getTsDll();
318
319 $apachePhpModuleName = null;
320 if ( $tsDll !== false ) {
321 $apachemoduleNamePrefix = substr( $tsDll, 0, 4 );
322 $apachePhpModuleName = ($apachemoduleNamePrefix == 'php8' ? 'php' : $apachemoduleNamePrefix) . '_module';
323 }
324 $apachePhpModulePath = $bearsamppBins->getPhp()->getApacheModule( $version );
325 $apachePhpModuleDll = basename( $apachePhpModulePath );
326
327 Util::logDebug( ($sub > 0 ? str_repeat( ' ', 2 * $sub ) : '') . 'PHP TsDll found: ' . $tsDll );
328 Util::logDebug( ($sub > 0 ? str_repeat( ' ', 2 * $sub ) : '') . 'PHP Apache module found: ' . $apachePhpModulePath );
329
330 if ( !file_exists( $conf ) || !file_exists( $bearsamppConf ) ) {
331 Util::logError( 'bearsampp config files not found for ' . $this->getName() . ' ' . $version );
332 if ( $showWindow ) {
333 $bearsamppWinbinder->messageBoxError(
334 sprintf( $bearsamppLang->getValue( Lang::BEARSAMPP_CONF_NOT_FOUND_ERROR ), $this->getName() . ' ' . $version ),
335 $boxTitle
336 );
337 }
338
339 return false;
340 }
341
342 $bearsamppConfRaw = parse_ini_file( $bearsamppConf );
343 if ( $bearsamppConfRaw === false || !isset( $bearsamppConfRaw[self::ROOT_CFG_VERSION] ) || $bearsamppConfRaw[self::ROOT_CFG_VERSION] != $version ) {
344 Util::logError( 'bearsampp config file malformed for ' . $this->getName() . ' ' . $version );
345 if ( $showWindow ) {
346 $bearsamppWinbinder->messageBoxError(
347 sprintf( $bearsamppLang->getValue( Lang::BEARSAMPP_CONF_MALFORMED_ERROR ), $this->getName() . ' ' . $version ),
348 $boxTitle
349 );
350 }
351
352 return false;
353 }
354
355 if ( $tsDll === false || $apachePhpModulePath === false ) {
356 Util::logDebug( $this->getName() . ' ' . $version . ' does not seem to be compatible with PHP ' . $bearsamppBins->getPhp()->getVersion() );
357 if ( $showWindow ) {
358 $bearsamppWinbinder->messageBoxError(
359 sprintf( $bearsamppLang->getValue( Lang::APACHE_INCPT ), $version, $bearsamppBins->getPhp()->getVersion() ),
360 $boxTitle
361 );
362 }
363
364 return false;
365 }
366
367 // httpd.conf
368 $this->setVersion( $version );
369
370 // conf
371 Util::logDebug( 'httpd.conf = ' . $conf );
373 // PHP module
374 '/^#?PHPIniDir\s.*/' => ($bearsamppBins->getPhp()->isEnable() ? '' : '#') . 'PHPIniDir "' . $bearsamppBins->getPhp()->getSymlinkPath() . '"',
375 '/^#?LoadFile\s.*php.ts\.dll.*/' => ($bearsamppBins->getPhp()->isEnable() ? '' : '#') . (!file_exists( $bearsamppBins->getPhp()->getSymlinkPath() . '/' . $tsDll ) ? '#' : '') . 'LoadFile "' . $bearsamppBins->getPhp()->getSymlinkPath() . '/' . $tsDll . '"',
376 '/^#?LoadModule\sphp.*/' => ($bearsamppBins->getPhp()->isEnable() ? '' : '#') . 'LoadModule ' . $apachePhpModuleName . ' "' . $bearsamppBins->getPhp()->getSymlinkPath() . '/' . $apachePhpModuleDll . '"',
377 '/^#?LoadModule\sphp_*/' => ($bearsamppBins->getPhp()->isEnable() ? '' : '#') . 'LoadModule ' . $apachePhpModuleName . ' "' . $bearsamppBins->getPhp()->getSymlinkPath() . '/' . $apachePhpModuleDll . '"',
378
379
380 // Port
381 '/^Listen\s(\d+)/' => 'Listen ' . $this->port,
382 '/^ServerName\s+([a-zA-Z0-9.]+):(\d+)/' => 'ServerName {{1}}:' . $this->port,
383 '/^NameVirtualHost\s+([a-zA-Z0-9.*]+):(\d+)/' => 'NameVirtualHost {{1}}:' . $this->port,
384 '/^<VirtualHost\s+([a-zA-Z0-9.*]+):(\d+)>/' => '<VirtualHost {{1}}:' . $this->port . '>'
385 ) );
386
387 // vhosts
388 foreach ( $this->getVhosts() as $vhost ) {
389 Util::replaceInFile( $bearsamppRoot->getVhostsPath() . '/' . $vhost . '.conf', array(
390 '/^<VirtualHost\s+([a-zA-Z0-9.*]+):(\d+)>$/' => '<VirtualHost {{1}}:' . $this->port . '>$'
391 ) );
392 }
393
394 // www .htaccess
395 Util::replaceInFile( $bearsamppRoot->getWwwPath() . '/.htaccess', array(
396 '/(.*)http:\/\/localhost(.*)/' => '{{1}}http://localhost' . ($this->port != 80 ? ':' . $this->port : '') . '/$1 [QSA,R=301,L]',
397 ) );
398
399 return true;
400 }
401
402 /**
403 * Retrieves the list of modules by merging the modules from the folder and the configuration file.
404 *
405 * @return array The list of modules.
406 */
407 public function getModules()
408 {
409 $fromFolder = $this->getModulesFromFolder();
410 $fromConf = $this->getModulesFromConf();
411 $result = array_merge( $fromFolder, $fromConf );
412 ksort( $result );
413
414 return $result;
415 }
416
417 /**
418 * Retrieves the list of modules from the configuration file.
419 *
420 * @return array The list of modules from the configuration file.
421 */
422 public function getModulesFromConf()
423 {
424 $result = array();
425
426 if ( !$this->enable ) {
427 return $result;
428 }
429
430 $confContent = file( $this->getConf() );
431 foreach ( $confContent as $row ) {
432 $modMatch = array();
433 if ( preg_match( '/^(#)?LoadModule\s*([a-z0-9_-]+)\s*"?(.*)"?/i', $row, $modMatch ) ) {
434 $name = $modMatch[2];
435 //$path = $modMatch[3];
436 if ( !Util::startWith( $name, 'php' ) ) {
437 if ( $modMatch[1] == '#' ) {
439 }
440 else {
442 }
443 }
444 }
445 }
446
447 ksort( $result );
448
449 return $result;
450 }
451
452 /**
453 * Retrieves the list of loaded modules from the configuration file.
454 *
455 * @return array The list of loaded modules.
456 */
457 public function getModulesLoaded()
458 {
459 $result = array();
460 foreach ( $this->getModulesFromConf() as $name => $status ) {
461 if ( $status == ActionSwitchApacheModule::SWITCH_ON ) {
462 $result[] = $name;
463 }
464 }
465
466 return $result;
467 }
468
469 /**
470 * Retrieves the list of modules from the modules folder.
471 *
472 * @return array The list of modules from the modules folder.
473 */
474 private function getModulesFromFolder()
475 {
476 $result = array();
477
478 if ( !$this->enable ) {
479 return $result;
480 }
481
482 $handle = @opendir( $this->getModulesPath() );
483 if ( !$handle ) {
484 return $result;
485 }
486
487 while ( false !== ($file = readdir( $handle )) ) {
488 if ( $file != '.' && $file != '..' && Util::startWith( $file, 'mod_' ) && (Util::endWith( $file, '.so' ) || Util::endWith( $file, '.dll' )) ) {
489 $name = str_replace( array('mod_', '.so', '.dll'), '', $file ) . '_module';
491 }
492 }
493
494 closedir( $handle );
495 ksort( $result );
496
497 return $result;
498 }
499
500 /**
501 * Retrieves the list of alias configurations.
502 *
503 * @return array The list of alias configurations.
504 */
505 public function getAlias()
506 {
507 global $bearsamppRoot;
508 $result = array();
509
510 $handle = @opendir( $bearsamppRoot->getAliasPath() );
511 if ( !$handle ) {
512 return $result;
513 }
514
515 while ( false !== ($file = readdir( $handle )) ) {
516 if ( $file != '.' && $file != '..' && Util::endWith( $file, '.conf' ) ) {
517 $result[] = str_replace( '.conf', '', $file );
518 }
519 }
520
521 closedir( $handle );
522 ksort( $result );
523
524 return $result;
525 }
526
527 /**
528 * Retrieves the list of virtual hosts configurations.
529 *
530 * @return array The list of virtual hosts configurations.
531 */
532 public function getVhosts()
533 {
534 global $bearsamppRoot;
535 $result = array();
536
537 $handle = @opendir( $bearsamppRoot->getVhostsPath() );
538 if ( !$handle ) {
539 return $result;
540 }
541
542 while ( false !== ($file = readdir( $handle )) ) {
543 if ( $file != '.' && $file != '..' && Util::endWith( $file, '.conf' ) ) {
544 $result[] = str_replace( '.conf', '', $file );
545 }
546 }
547
548 closedir( $handle );
549 ksort( $result );
550
551 return $result;
552 }
553
554 /**
555 * Retrieves the URLs of the virtual hosts.
556 *
557 * @return array The list of virtual hosts URLs.
558 */
559 public function getVhostsUrl()
560 {
561 global $bearsamppRoot;
562 $result = array();
563
564 foreach ( $this->getVhosts() as $vhost ) {
565 $vhostContent = file( $bearsamppRoot->getVhostsPath() . '/' . $vhost . '.conf' );
566 foreach ( $vhostContent as $vhostLine ) {
567 $vhostLine = trim( $vhostLine );
568 $enabled = !Util::startWith( $vhostLine, '#' );
569 if ( preg_match_all( '/ServerName\s+(.*)/', $vhostLine, $matches ) ) {
570 foreach ( $matches as $match ) {
571 $found = isset( $match[1] ) ? trim( $match[1] ) : trim( $match[0] );
572 if ( filter_var( 'http://' . $found, FILTER_VALIDATE_URL ) !== false ) {
573 $result[$found] = $enabled;
574 break 2;
575 }
576 }
577 }
578 }
579 }
580
581 return $result;
582 }
583
584 /**
585 * Retrieves the list of directories in the www folder.
586 *
587 * @return array The list of directories in the www folder.
588 */
589 public function getWwwDirectories()
590 {
591 global $bearsamppRoot;
592 $result = array();
593
594 $handle = @opendir( $bearsamppRoot->getWwwPath() );
595 if ( !$handle ) {
596 return $result;
597 }
598
599 while ( false !== ($file = readdir( $handle )) ) {
600 if ( $file != '.' && $file != '..' && is_dir( $bearsamppRoot->getWwwPath() . '/' . $file ) ) {
601 $result[] = $file;
602 }
603 }
604
605 closedir( $handle );
606 ksort( $result );
607
608 return $result;
609 }
610
611 /**
612 * Executes a command line and retrieves the output.
613 *
614 * @param string $cmd The command to execute.
615 *
616 * @return array The output of the command.
617 */
618 public function getCmdLineOutput($cmd)
619 {
620 $result = array(
621 'syntaxOk' => false,
622 'content' => null,
623 );
624
625 if ( file_exists( $this->getExe() ) ) {
626 $tmpResult = Batch::exec( 'apacheGetCmdLineOutput', '"' . $this->getExe() . '" ' . $cmd );
627 if ( $tmpResult !== false && is_array( $tmpResult ) ) {
628 $result['syntaxOk'] = trim( $tmpResult[count( $tmpResult ) - 1] ) == 'Syntax OK';
629 if ( $result['syntaxOk'] ) {
630 unset( $tmpResult[count( $tmpResult ) - 1] );
631 }
632 $result['content'] = implode( PHP_EOL, $tmpResult );
633 }
634 }
635
636 return $result;
637 }
638
639 /**
640 * Generates the online content for the configuration file.
641 *
642 * @param string|null $version The version of the configuration.
643 *
644 * @return string The online content.
645 */
646 private function getOnlineContent($version = null)
647 {
648 $version = $version != null ? $version : $this->getVersion();
649 $result = self::TAG_START_SWITCHONLINE . PHP_EOL;
650
651 if ( Util::startWith( $version, '2.4' ) ) {
652 $result .= 'Require all granted' . PHP_EOL;
653 }
654 else {
655 $result .= 'Order Allow,Deny' . PHP_EOL .
656 'Allow from all' . PHP_EOL;
657 }
658
660 }
661
662 /**
663 * Generates the offline content for the configuration file.
664 *
665 * @param string|null $version The version of the configuration.
666 *
667 * @return string The offline content.
668 */
669 private function getOfflineContent($version = null)
670 {
671 $version = $version != null ? $version : $this->getVersion();
672 $result = self::TAG_START_SWITCHONLINE . PHP_EOL;
673
674 if ( Util::startWith( $version, '2.4' ) ) {
675 $result .= 'Require local' . PHP_EOL;
676 }
677 else {
678 $result .= 'Order Deny,Allow' . PHP_EOL .
679 'Deny from all' . PHP_EOL .
680 'Allow from 127.0.0.1 ::1' . PHP_EOL;
681 }
682
684 }
685
686 /**
687 * Generates the required content for the configuration file based on the online status.
688 *
689 * @param string|null $version The version of the configuration.
690 *
691 * @return string The required content.
692 */
693 private function getRequiredContent($version = null)
694 {
695 global $bearsamppConfig;
696
697 return $bearsamppConfig->isOnline() ? $this->getOnlineContent( $version ) : $this->getOfflineContent( $version );
698 }
699
700 /**
701 * Generates the alias content for the configuration file.
702 *
703 * @param string $name The name of the alias.
704 * @param string $dest The destination path of the alias.
705 *
706 * @return string The alias content.
707 */
708 public function getAliasContent($name, $dest)
709 {
710 $dest = Util::formatUnixPath( $dest );
711
712 return 'Alias /' . $name . ' "' . $dest . '"' . PHP_EOL . PHP_EOL .
713 '<Directory "' . $dest . '">' . PHP_EOL .
714 ' Options Indexes FollowSymLinks MultiViews' . PHP_EOL .
715 ' AllowOverride all' . PHP_EOL .
716 $this->getRequiredContent() . PHP_EOL .
717 '</Directory>' . PHP_EOL;
718 }
719
720 /**
721 * Generates the virtual host content for the configuration file.
722 *
723 * @param string $serverName The server name of the virtual host.
724 * @param string $documentRoot The document root of the virtual host.
725 *
726 * @return string The virtual host content.
727 */
728 public function getVhostContent($serverName, $documentRoot)
729 {
730 global $bearsamppRoot;
731
732 $documentRoot = Util::formatUnixPath( $documentRoot );
733
734 return '<VirtualHost *:' . $this->getPort() . '>' . PHP_EOL .
735 ' ServerAdmin webmaster@' . $serverName . PHP_EOL .
736 ' DocumentRoot "' . $documentRoot . '"' . PHP_EOL .
737 ' ServerName ' . $serverName . PHP_EOL .
738 ' ErrorLog "' . $bearsamppRoot->getLogsPath() . '/' . $serverName . '_error.log"' . PHP_EOL .
739 ' CustomLog "' . $bearsamppRoot->getLogsPath() . '/' . $serverName . '_access.log" combined' . PHP_EOL . PHP_EOL .
740 ' <Directory "' . $documentRoot . '">' . PHP_EOL .
741 ' Options Indexes FollowSymLinks MultiViews' . PHP_EOL .
742 ' AllowOverride all' . PHP_EOL .
743 $this->getRequiredContent() . PHP_EOL .
744 ' </Directory>' . PHP_EOL .
745 '</VirtualHost>' . PHP_EOL . PHP_EOL .
746 '<IfModule ssl_module>' . PHP_EOL .
747 '<VirtualHost *:' . $this->getSslPort() . '> #SSL' . PHP_EOL .
748 ' DocumentRoot "' . $documentRoot . '"' . PHP_EOL .
749 ' ServerName ' . $serverName . PHP_EOL .
750 ' ServerAdmin webmaster@' . $serverName . PHP_EOL .
751 ' ErrorLog "' . $bearsamppRoot->getLogsPath() . '/' . $serverName . '_error.log"' . PHP_EOL .
752 ' TransferLog "' . $bearsamppRoot->getLogsPath() . '/' . $serverName . '_access.log"' . PHP_EOL . PHP_EOL .
753 ' SSLEngine on' . PHP_EOL .
754 ' SSLProtocol all -SSLv2' . PHP_EOL .
755 ' SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5' . PHP_EOL .
756 ' SSLCertificateFile "' . $bearsamppRoot->getSslPath() . '/' . $serverName . '.crt"' . PHP_EOL .
757 ' SSLCertificateKeyFile "' . $bearsamppRoot->getSslPath() . '/' . $serverName . '.pub"' . PHP_EOL .
758 ' BrowserMatch "MSIE [2-5]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0' . PHP_EOL .
759 ' CustomLog "' . $bearsamppRoot->getLogsPath() . '/' . $serverName . '_sslreq.log" "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"' . PHP_EOL . PHP_EOL .
760 ' <Directory "' . $documentRoot . '">' . PHP_EOL .
761 ' SSLOptions +StdEnvVars' . PHP_EOL .
762 ' Options Indexes FollowSymLinks MultiViews' . PHP_EOL .
763 ' AllowOverride all' . PHP_EOL .
764 $this->getRequiredContent() . PHP_EOL .
765 ' </Directory>' . PHP_EOL .
766 '</VirtualHost>' . PHP_EOL .
767 '</IfModule>' . PHP_EOL;
768 }
769
770 /**
771 * Refreshes the configuration file to switch between online and offline modes.
772 *
773 * @param bool $putOnline Whether to put the configuration online.
774 */
775 public function refreshConf($putOnline)
776 {
777 if ( !$this->enable ) {
778 return;
779 }
780
781 $onlineContent = $this->getOnlineContent();
782 $offlineContent = $this->getOfflineContent();
783
784 $conf = file_get_contents( $this->getConf() );
785 Util::logTrace( 'refreshConf ' . $this->getConf() );
786 preg_match( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $conf, $matches );
787 Util::logTrace( isset( $matches[1] ) ? print_r( $matches[1], true ) : 'N/A' );
788
789 if ( $putOnline ) {
790 $conf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $onlineContent, $conf, -1, $count );
791 }
792 else {
793 $conf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $offlineContent, $conf, -1, $count );
794 }
795 file_put_contents( $this->getConf(), $conf );
796 Util::logDebug( 'Refresh ' . $this->getConf() . ': ' . $count . ' occurrence(s) replaced' );
797
798 $sslConf = file_get_contents( $this->getSslConf() );
799 Util::logTrace( 'refreshConf ' . $this->getSslConf() );
800 preg_match( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $sslConf, $matches );
801 Util::logTrace( isset( $matches[1] ) ? print_r( $matches[1], true ) : 'N/A' );
802
803 if ( $putOnline ) {
804 $sslConf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $onlineContent, $sslConf, -1, $count );
805 }
806 else {
807 $sslConf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $offlineContent, $sslConf, -1, $count );
808 }
809 file_put_contents( $this->getSslConf(), $sslConf );
810 Util::logDebug( 'Refresh ' . $this->getSslConf() . ': ' . $count . ' occurrence(s) replaced' );
811 }
812
813 /**
814 * Refreshes the alias configurations to switch between online and offline modes.
815 *
816 * @param bool $putOnline Whether to put the alias configurations online.
817 */
818 public function refreshAlias($putOnline)
819 {
821
822 if ( !$this->enable ) {
823 return;
824 }
825
826 $onlineContent = $this->getOnlineContent();
827 $offlineContent = $this->getOfflineContent();
828
829 foreach ( $this->getAlias() as $alias ) {
830 $aliasConf = file_get_contents( $bearsamppRoot->getAliasPath() . '/' . $alias . '.conf' );
831 Util::logTrace( 'refreshAlias ' . $bearsamppRoot->getAliasPath() . '/' . $alias . '.conf' );
832 preg_match( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $aliasConf, $matches );
833 Util::logTrace( isset( $matches[1] ) ? print_r( $matches[1], true ) : 'N/A' );
834
835 if ( $putOnline ) {
836 $aliasConf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $onlineContent, $aliasConf, -1, $count );
837 }
838 else {
839 $aliasConf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $offlineContent, $aliasConf, -1, $count );
840 }
841 file_put_contents( $bearsamppRoot->getAliasPath() . '/' . $alias . '.conf', $aliasConf );
842 Util::logDebug( 'Refresh ' . $bearsamppRoot->getAliasPath() . '/' . $alias . '.conf: ' . $count . ' occurrence(s) replaced' );
843 }
844
845 // Homepage
846 $bearsamppHomepage->refreshAliasContent();
847 }
848
849 /**
850 * Refreshes the virtual host configurations to switch between online and offline modes.
851 *
852 * @param bool $putOnline Whether to put the virtual host configurations online.
853 */
854 public function refreshVhosts($putOnline)
855 {
856 global $bearsamppRoot;
857
858 if ( !$this->enable ) {
859 return;
860 }
861
862 $onlineContent = $this->getOnlineContent();
863 $offlineContent = $this->getOfflineContent();
864
865 foreach ( $this->getVhosts() as $vhost ) {
866 $vhostConf = file_get_contents( $bearsamppRoot->getVhostsPath() . '/' . $vhost . '.conf' );
867 Util::logTrace( 'refreshVhost ' . $bearsamppRoot->getVhostsPath() . '/' . $vhost . '.conf' );
868 preg_match( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $vhostConf, $matches );
869 Util::logTrace( isset( $matches[1] ) ? print_r( $matches[1], true ) : 'N/A' );
870
871 if ( $putOnline ) {
872 $vhostConf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $onlineContent, $vhostConf, -1, $count );
873 }
874 else {
875 $vhostConf = preg_replace( '/' . self::TAG_START_SWITCHONLINE . '(.*?)' . self::TAG_END_SWITCHONLINE . '/s', $offlineContent, $vhostConf, -1, $count );
876 }
877 file_put_contents( $bearsamppRoot->getVhostsPath() . '/' . $vhost . '.conf', $vhostConf );
878 Util::logDebug( 'Refresh ' . $bearsamppRoot->getVhostsPath() . '/' . $vhost . '.conf: ' . $count . ' occurrence(s) replaced' );
879 }
880 }
881
882 /**
883 * Sets the enable status of the module.
884 *
885 * This method enables or disables the module based on the provided parameter.
886 * If enabling the module and the current path does not exist, it logs an error
887 * and optionally shows an error message window.
888 *
889 * @param bool $enabled Whether to enable or disable the module.
890 * @param bool $showWindow Whether to show an error message window if enabling fails.
891 */
892 public function setEnable($enabled, $showWindow = false)
893 {
894 global $bearsamppConfig, $bearsamppLang, $bearsamppWinbinder;
895
896 if ( $enabled == Config::ENABLED && !is_dir( $this->currentPath ) ) {
897 Util::logDebug( $this->getName() . ' cannot be enabled because bundle ' . $this->getVersion() . ' does not exist in ' . $this->currentPath );
898 if ( $showWindow ) {
899 $bearsamppWinbinder->messageBoxError(
900 sprintf( $bearsamppLang->getValue( Lang::ENABLE_BUNDLE_NOT_EXIST ), $this->getName(), $this->getVersion(), $this->currentPath ),
901 sprintf( $bearsamppLang->getValue( Lang::ENABLE_TITLE ), $this->getName() )
902 );
903 }
904 $enabled = Config::DISABLED;
905 }
906
907 Util::logInfo( $this->getName() . ' switched to ' . ($enabled == Config::ENABLED ? 'enabled' : 'disabled') );
908 $this->enable = $enabled == Config::ENABLED;
909 $bearsamppConfig->replace( self::ROOT_CFG_ENABLE, $enabled );
910
911 $this->reload();
912 if ( $this->enable ) {
913 Util::installService( $this, $this->port, self::CMD_SYNTAX_CHECK, $showWindow );
914 }
915 else {
916 Util::removeService( $this->service, $this->name );
917 }
918 }
919
920 /**
921 * Sets the version of the module.
922 *
923 * This method updates the version of the module and reloads its configuration.
924 *
925 * @param string $version The version to set for the module.
926 */
927 public function setVersion($version)
928 {
929 global $bearsamppConfig;
930 $this->version = $version;
931 $bearsamppConfig->replace( self::ROOT_CFG_VERSION, $version );
932 $this->reload();
933 }
934
935 /**
936 * Gets the service associated with the module.
937 *
938 * @return string The service associated with the module.
939 */
940 public function getService()
941 {
942 return $this->service;
943 }
944
945 /**
946 * Gets the path to the modules.
947 *
948 * @return string The path to the modules.
949 */
950 public function getModulesPath()
951 {
952 return $this->modulesPath;
953 }
954
955 /**
956 * Gets the SSL configuration file path.
957 *
958 * @return string The SSL configuration file path.
959 */
960 public function getSslConf()
961 {
962 return $this->sslConf;
963 }
964
965 /**
966 * Gets the access log file path.
967 *
968 * @return string The access log file path.
969 */
970 public function getAccessLog()
971 {
972 return $this->accessLog;
973 }
974
975 /**
976 * Gets the rewrite log file path.
977 *
978 * @return string The rewrite log file path.
979 */
980 public function getRewriteLog()
981 {
982 return $this->rewriteLog;
983 }
984
985 /**
986 * Gets the error log file path.
987 *
988 * @return string The error log file path.
989 */
990 public function getErrorLog()
991 {
992 return $this->errorLog;
993 }
994
995 /**
996 * Gets the executable file path.
997 *
998 * @return string The executable file path.
999 */
1000 public function getExe()
1001 {
1002 return $this->exe;
1003 }
1004
1005 /**
1006 * Gets the configuration file path.
1007 *
1008 * @return string The configuration file path.
1009 */
1010 public function getConf()
1011 {
1012 return $this->conf;
1013 }
1014
1015 /**
1016 * Gets the port number.
1017 *
1018 * @return int The port number.
1019 */
1020 public function getPort()
1021 {
1022 return $this->port;
1023 }
1024
1025 /**
1026 * Sets the port number.
1027 *
1028 * This method updates the port number in the configuration.
1029 *
1030 * @param int $port The port number to set.
1031 */
1032 public function setPort($port)
1033 {
1034 $this->replace( self::LOCAL_CFG_PORT, $port );
1035 }
1036
1037 /**
1038 * Gets the SSL port number.
1039 *
1040 * @return int The SSL port number.
1041 */
1042 public function getSslPort()
1043 {
1044 return $this->sslPort;
1045 }
1046
1047 /**
1048 * Sets the SSL port number.
1049 *
1050 * This method updates the SSL port number in the configuration.
1051 *
1052 * @param int $sslPort The SSL port number to set.
1053 */
1054 public function setSslPort($sslPort)
1055 {
1056 $this->replace( self::LOCAL_CFG_SSL_PORT, $sslPort );
1057 }
1058
1059 /**
1060 * Gets the OpenSSL executable file path.
1061 *
1062 * @return string The OpenSSL executable file path.
1063 */
1064 public function getOpensslExe()
1065 {
1066 return $this->opensslExe;
1067 }
1068}
$result
global $bearsamppBins
global $bearsamppLang
global $bearsamppRoot
static exec($basename, $content, $timeout=true, $catchOutput=true, $standalone=false, $silent=true, $rebuild=true)
const CMD_LOADED_MODULES
changePort($port, $checkUsed=false, $wbProgressBar=null)
switchVersion($version, $showWindow=false)
setSslPort($sslPort)
getAliasContent($name, $dest)
const CMD_VERSION_NUMBER
reload($id=null, $type=null)
getOfflineContent($version=null)
const CMD_VHOSTS_SETTINGS
setEnable($enabled, $showWindow=false)
const LOCAL_CFG_SSL_PORT
refreshConf($putOnline)
updateConfig($version=null, $sub=0, $showWindow=false)
getVhostContent($serverName, $documentRoot)
const ROOT_CFG_ENABLE
refreshVhosts($putOnline)
getRequiredContent($version=null)
replaceAll($params)
getOnlineContent($version=null)
const TAG_END_SWITCHONLINE
refreshAlias($putOnline)
const TAG_START_SWITCHONLINE
checkPort($port, $ssl=false, $showWindow=false)
const CMD_CONFIG_DIRECTIVES
const CMD_COMPILE_SETTINGS
setVersion($version)
const ROOT_CFG_VERSION
__construct($id, $type)
const CMD_SYNTAX_CHECK
const LOCAL_CFG_OPENSSL_EXE
const CMD_COMPILED_MODULES
const DISABLED
const ENABLED
const ENABLE_TITLE
const PORT_NOT_USED_BY
const ERROR_FILE_NOT_FOUND
const ERROR_INVALID_PARAMETER
const BEARSAMPP_CONF_NOT_FOUND_ERROR
const CHECK_PORT_TITLE
const APACHE_INCPT
const ENABLE_BUNDLE_NOT_EXIST
const ERROR_CONF_NOT_FOUND
const SWITCH_VERSION_TITLE
const ERROR_EXE_NOT_FOUND
const APACHE
const PORT_USED_BY
const PORT_NOT_USED
const BEARSAMPP_CONF_MALFORMED_ERROR
update($sub=0, $showWindow=false)
replace($key, $value)
const SERVICE_DEMAND_START
static startWith($string, $search)
static logReloadClass($classInstance)
static getHttpHeaders($pingUrl)
static replaceInFile($path, $replaceList)
static logError($data, $file=null)
static endWith($string, $search)
static isValidPort($port)
static formatUnixPath($path)
static installService($bin, $port, $syntaxCheckCmd, $showWindow=false)
static removeService($service, $name)
static logDebug($data, $file=null)
static logInitClass($classInstance)
static isPortInUse($port)
static logInfo($data, $file=null)
static logTrace($data, $file=null)
global $bearsamppConfig
Definition homepage.php:26
global $bearsamppHomepage
Definition homepage.php:26
const APP_TITLE
Definition root.php:12