2024.8.23
Loading...
Searching...
No Matches
class.bin.filezilla.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 BinFilezilla
12 *
13 * This class represents the FileZilla module in the Bearsampp application.
14 * It handles the configuration, management, and operations related to the FileZilla service.
15 */
16class BinFilezilla extends Module
17{
18 const SERVICE_NAME = 'bearsamppfilezilla';
19
20 const ROOT_CFG_ENABLE = 'filezillaEnable';
21 const ROOT_CFG_VERSION = 'filezillaVersion';
22
23 const LOCAL_CFG_EXE = 'filezillaExe';
24 const LOCAL_CFG_ITF_EXE = 'filezillaItfExe';
25 const LOCAL_CFG_CONF = 'filezillaConf';
26 const LOCAL_CFG_ITF_CONF = 'filezillaItfConf';
27 const LOCAL_CFG_PORT = 'filezillaPort';
28 const LOCAL_CFG_SSL_PORT = 'filezillaSslPort';
29
30 const CFG_SERVER_PORT = 0;
31 const CFG_WELCOME_MSG = 15;
34 const CFG_SERVICE_NAME = 58;
36
37 private $service;
38 private $logsPath;
39 private $log;
40
41 private $exe;
42 private $itfExe;
43 private $conf;
44 private $itfConf;
46 private $port;
47 private $sslPort;
48
49 /**
50 * Constructs a BinFilezilla object and initializes the module.
51 *
52 * @param string $id The ID of the module.
53 * @param string $type The type of the module.
54 */
55 public function __construct($id, $type)
56 {
57 Util::logInitClass( $this );
58 $this->reload( $id, $type );
59 }
60
61 /**
62 * Reloads the module configuration based on the provided ID and type.
63 *
64 * @param string|null $id The ID of the module. If null, the current ID is used.
65 * @param string|null $type The type of the module. If null, the current type is used.
66 */
67 public function reload($id = null, $type = null)
68 {
70 Util::logReloadClass( $this );
71
72 $this->name = $bearsamppLang->getValue( Lang::FILEZILLA );
73 $this->version = $bearsamppConfig->getRaw( self::ROOT_CFG_VERSION );
74 parent::reload( $id, $type );
75
76 $this->enable = $this->enable && $bearsamppConfig->getRaw( self::ROOT_CFG_ENABLE );
77 $this->service = new Win32Service( self::SERVICE_NAME );
78 $this->logsPath = $this->symlinkPath . '/Logs';
79 $this->log = $bearsamppRoot->getLogsPath() . '/filezilla.log';
80
81 if ( $this->bearsamppConfRaw !== false ) {
82 $this->exe = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_EXE];
83 $this->itfExe = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_ITF_EXE];
84 $this->conf = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_CONF];
85 $this->itfConf = $this->symlinkPath . '/' . $this->bearsamppConfRaw[self::LOCAL_CFG_ITF_CONF];
86 $this->localItfConf = Util::formatUnixPath( getenv( 'APPDATA' ) ) . '/FileZilla Server/' . $this->bearsamppConfRaw[self::LOCAL_CFG_ITF_CONF];
87 $this->port = $this->bearsamppConfRaw[self::LOCAL_CFG_PORT];
88 $this->sslPort = $this->bearsamppConfRaw[self::LOCAL_CFG_SSL_PORT];
89 }
90
91 if ( !$this->enable ) {
92 Util::logInfo( $this->name . ' is not enabled!' );
93
94 return;
95 }
96 if ( !is_dir( $this->currentPath ) ) {
97 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_FILE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->currentPath ) );
98
99 return;
100 }
101 if ( !is_dir( $this->symlinkPath ) ) {
102 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_FILE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->symlinkPath ) );
103
104 return;
105 }
106 if ( !is_file( $this->bearsamppConf ) ) {
107 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->bearsamppConf ) );
108
109 return;
110 }
111
112 // Create log hard link
113 $log = $this->logsPath . '/FileZilla Server.log';
114 if ( !file_exists( $this->log ) && file_exists( $log ) ) {
115 @link( $log, $this->log );
116 }
117
118 if ( !is_file( $this->exe ) ) {
119 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_EXE_NOT_FOUND ), $this->name . ' ' . $this->version, $this->exe ) );
120
121 return;
122 }
123 if ( !is_file( $this->conf ) ) {
124 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), $this->name . ' ' . $this->version, $this->conf ) );
125
126 return;
127 }
128 if ( !is_numeric( $this->port ) || $this->port <= 0 ) {
129 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_INVALID_PARAMETER ), self::LOCAL_CFG_PORT, $this->port ) );
130
131 return;
132 }
133 if ( !is_numeric( $this->sslPort ) || $this->sslPort <= 0 ) {
134 Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_INVALID_PARAMETER ), self::LOCAL_CFG_SSL_PORT, $this->sslPort ) );
135
136 return;
137 }
138 if ( !file_exists( $this->localItfConf ) ) {
139 if ( !is_dir( dirname( $this->localItfConf ) ) ) {
140 Util::logDebug( 'Create folder ' . dirname( $this->localItfConf ) );
141 @mkdir( dirname( $this->localItfConf ), 0777 );
142 }
143 Util::logDebug( 'Write ' . $this->bearsamppConfRaw[self::LOCAL_CFG_ITF_CONF] . ' to ' . $this->localItfConf );
144 @copy( $this->itfConf, $this->localItfConf );
145 }
146
147 $this->service->setDisplayName( APP_TITLE . ' ' . $this->getName() );
148 $this->service->setBinPath( $this->exe );
149 $this->service->setStartType( Win32Service::SERVICE_DEMAND_START );
150 $this->service->setErrorControl( Win32Service::SERVER_ERROR_NORMAL );
151 }
152
153 /**
154 * Changes the port for the FileZilla service.
155 *
156 * @param int $port The new port number.
157 * @param bool $checkUsed Whether to check if the port is already in use.
158 * @param mixed $wbProgressBar The progress bar object for displaying progress.
159 *
160 * @return bool|string Returns true if the port is changed successfully, false if the port is invalid, or a string if the port is in use.
161 */
162 public function changePort($port, $checkUsed = false, $wbProgressBar = null)
163 {
164 global $bearsamppWinbinder;
165
166 if ( !Util::isValidPort( $port ) ) {
167 Util::logError( $this->getName() . ' port not valid: ' . $port );
168
169 return false;
170 }
171
172 $port = intval( $port );
173 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
174
175 $isPortInUse = Util::isPortInUse( $port );
176 if ( !$checkUsed || $isPortInUse === false ) {
177 // bearsampp.conf
178 $this->setPort( $port );
179 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
180
181 // conf
182 $this->update();
183 $bearsamppWinbinder->incrProgressBar( $wbProgressBar );
184
185 return true;
186 }
187
188 Util::logDebug( $this->getName() . ' port in used: ' . $port . ' - ' . $isPortInUse );
189
190 return $isPortInUse;
191 }
192
193 /**
194 * Checks if the specified port is in use.
195 *
196 * @param int $port The port number to check.
197 * @param bool $ssl Whether to use SSL for the check.
198 * @param bool $showWindow Whether to show a window with the result.
199 *
200 * @return bool Returns true if the port is in use, false otherwise.
201 */
202 public function checkPort($port, $ssl = false, $showWindow = false)
203 {
204 global $bearsamppLang, $bearsamppWinbinder;
205 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::CHECK_PORT_TITLE ), $this->getName(), $port );
206
207 if ( !Util::isValidPort( $port ) ) {
208 Util::logError( $this->getName() . ' port not valid: ' . $port );
209
210 return false;
211 }
212
213 $headers = Util::getHeaders( '127.0.0.1', $port, $ssl );
214 if ( !empty( $headers ) ) {
215 if ( $headers[0] == '220 ' . $this->getService()->getDisplayName() ) {
216 Util::logDebug( $this->getName() . ' port ' . $port . ' is used by: ' . str_replace( '220 ', '', $headers[0] ) );
217 if ( $showWindow ) {
218 $bearsamppWinbinder->messageBoxInfo(
219 sprintf( $bearsamppLang->getValue( Lang::PORT_USED_BY ), $port, str_replace( '220 ', '', $headers[0] ) ),
220 $boxTitle
221 );
222 }
223
224 return true;
225 }
226 Util::logDebug( $this->getName() . ' port ' . $port . ' is used by another application' );
227 if ( $showWindow ) {
228 $bearsamppWinbinder->messageBoxWarning(
229 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED_BY ), $port ),
230 $boxTitle
231 );
232 }
233 }
234 else {
235 Util::logDebug( $this->getName() . ' port ' . $port . ' is not used' );
236 if ( $showWindow ) {
237 $bearsamppWinbinder->messageBoxError(
238 sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED ), $port ),
239 $boxTitle
240 );
241 }
242 }
243
244 return false;
245 }
246
247 /**
248 * Retrieves the Win32Service object for the FileZilla service.
249 *
250 * @return Win32Service The Win32Service object.
251 */
252 public function getService()
253 {
254 return $this->service;
255 }
256
257 /**
258 * Switches the version of the FileZilla module.
259 *
260 * @param string $version The version to switch to.
261 * @param bool $showWindow Whether to show a window with the result.
262 *
263 * @return bool Returns true if the version is switched successfully, false otherwise.
264 */
265 public function switchVersion($version, $showWindow = false)
266 {
267 Util::logDebug( 'Switch ' . $this->name . ' version to ' . $version );
268
269 return $this->updateConfig( $version, 0, $showWindow );
270 }
271
272 /**
273 * Updates the configuration for the specified version.
274 *
275 * @param string|null $version The version to update to. If null, the current version is used.
276 * @param int $sub The sub-level for logging indentation.
277 * @param bool $showWindow Whether to show a window with the result.
278 *
279 * @return bool Returns true if the configuration is updated successfully, false otherwise.
280 */
281 protected function updateConfig($version = null, $sub = 0, $showWindow = false)
282 {
283 global $bearsamppLang, $bearsamppWinbinder;
284
285 if ( !$this->enable ) {
286 return true;
287 }
288
289 $version = $version == null ? $this->version : $version;
290 Util::logDebug( ($sub > 0 ? str_repeat( ' ', 2 * $sub ) : '') . 'Update ' . $this->name . ' ' . $version . ' config' );
291
292 $boxTitle = sprintf( $bearsamppLang->getValue( Lang::SWITCH_VERSION_TITLE ), $this->getName(), $version );
293
294 $conf = str_replace( 'filezilla' . $this->getVersion(), 'filezilla' . $version, $this->getConf() );
295 $bearsamppConf = str_replace( 'filezilla' . $this->getVersion(), 'filezilla' . $version, $this->bearsamppConf );
296
297 if ( !file_exists( $conf ) || !file_exists( $bearsamppConf ) ) {
298 Util::logError( 'bearsampp config files not found for ' . $this->getName() . ' ' . $version );
299 if ( $showWindow ) {
300 $bearsamppWinbinder->messageBoxError(
301 sprintf( $bearsamppLang->getValue( Lang::BEARSAMPP_CONF_NOT_FOUND_ERROR ), $this->getName() . ' ' . $version ),
302 $boxTitle
303 );
304 }
305
306 return false;
307 }
308
309 $bearsamppConfRaw = parse_ini_file( $bearsamppConf );
310 if ( $bearsamppConfRaw === false || !isset( $bearsamppConfRaw[self::ROOT_CFG_VERSION] ) || $bearsamppConfRaw[self::ROOT_CFG_VERSION] != $version ) {
311 Util::logError( 'bearsampp config file malformed for ' . $this->getName() . ' ' . $version );
312 if ( $showWindow ) {
313 $bearsamppWinbinder->messageBoxError(
314 sprintf( $bearsamppLang->getValue( Lang::BEARSAMPP_CONF_MALFORMED_ERROR ), $this->getName() . ' ' . $version ),
315 $boxTitle
316 );
317 }
318
319 return false;
320 }
321
322 // bearsampp.conf
323 $this->setVersion( $version );
324
325 // conf
326 $this->rebuildConf();
327
328 return true;
329 }
330
331 /**
332 * Retrieves the configuration file path for the FileZilla module.
333 *
334 * @return string The configuration file path.
335 */
336 public function getConf()
337 {
338 return $this->conf;
339 }
340
341 /**
342 * Sets the configuration values for the FileZilla module.
343 *
344 * @param array $elts An associative array of configuration key-value pairs.
345 */
346 public function setConf($elts)
347 {
348 if ( !$this->enable ) {
349 return;
350 }
351
352 $conf = simplexml_load_file( $this->conf );
353 foreach ( $elts as $key => $value ) {
354 $conf->Settings->Item[$key] = $value;
355 }
356 $conf->asXML( $this->conf );
357 }
358
359 /**
360 * Sets the version for the FileZilla module.
361 *
362 * @param string $version The version to set.
363 */
364 public function setVersion($version)
365 {
366 global $bearsamppConfig;
367 $this->version = $version;
368 $bearsamppConfig->replace( self::ROOT_CFG_VERSION, $version );
369 $this->reload();
370 }
371
372 /**
373 * Rebuilds the configuration file for the FileZilla module.
374 */
375 public function rebuildConf()
376 {
377 if ( !$this->enable ) {
378 return;
379 }
380
381 $this->setConf( array(
382 self::CFG_SERVER_PORT => $this->port,
383 self::CFG_SERVICE_NAME => $this->service->getName(),
384 self::CFG_WELCOME_MSG => $this->service->getDisplayName(),
385 self::CFG_SERVICE_DISPLAY_NAME => $this->service->getDisplayName()
386 ) );
387 }
388
389 /**
390 * Enables or disables the FileZilla module.
391 *
392 * @param bool $enabled Whether to enable or disable the module.
393 * @param bool $showWindow Whether to show a window with the result.
394 */
395 public function setEnable($enabled, $showWindow = false)
396 {
397 global $bearsamppConfig, $bearsamppLang, $bearsamppWinbinder;
398
399 if ( $enabled == Config::ENABLED && !is_dir( $this->currentPath ) ) {
400 Util::logDebug( $this->getName() . ' cannot be enabled because bundle ' . $this->getVersion() . ' does not exist in ' . $this->currentPath );
401 if ( $showWindow ) {
402 $bearsamppWinbinder->messageBoxError(
403 sprintf( $bearsamppLang->getValue( Lang::ENABLE_BUNDLE_NOT_EXIST ), $this->getName(), $this->getVersion(), $this->currentPath ),
404 sprintf( $bearsamppLang->getValue( Lang::ENABLE_TITLE ), $this->getName() )
405 );
406 }
407 $enabled = Config::DISABLED;
408 }
409
410 Util::logInfo( $this->getName() . ' switched to ' . ($enabled == Config::ENABLED ? 'enabled' : 'disabled') );
411 $this->enable = $enabled == Config::ENABLED;
412 $bearsamppConfig->replace( self::ROOT_CFG_ENABLE, $enabled );
413
414 $this->reload();
415 if ( $this->enable ) {
416 Util::installService( $this, $this->port, null, $showWindow );
417 }
418 else {
419 Util::removeService( $this->service, $this->name );
420 }
421 }
422
423 /**
424 * Retrieves the logs path for the FileZilla module.
425 *
426 * @return string The logs path.
427 */
428 public function getLogsPath()
429 {
430 return $this->logsPath;
431 }
432
433 /**
434 * Retrieves the log file path for the FileZilla module.
435 *
436 * @return string The log file path.
437 */
438 public function getLog()
439 {
440 return $this->log;
441 }
442
443 /**
444 * Retrieves the executable file path for the FileZilla module.
445 *
446 * @return string The executable file path.
447 */
448 public function getExe()
449 {
450 return $this->exe;
451 }
452
453 /**
454 * Retrieves the interface executable file path for the FileZilla module.
455 *
456 * @return string The interface executable file path.
457 */
458 public function getItfExe()
459 {
460 return $this->itfExe;
461 }
462
463 /**
464 * Retrieves the interface configuration file path for the FileZilla module.
465 *
466 * @return string The interface configuration file path.
467 */
468 public function getItfConf()
469 {
470 return $this->itfConf;
471 }
472
473 /**
474 * Retrieves the port number for the FileZilla service.
475 *
476 * @return int The port number.
477 */
478 public function getPort()
479 {
480 return $this->port;
481 }
482
483 /**
484 * Sets the port number for the FileZilla service.
485 *
486 * @param int $port The new port number.
487 */
488 public function setPort($port)
489 {
490 $this->replace( self::LOCAL_CFG_PORT, $port );
491 }
492
493 /**
494 * Retrieves the SSL port number for the FileZilla service.
495 *
496 * @return int The SSL port number.
497 */
498 public function getSslPort()
499 {
500 return $this->sslPort;
501 }
502
503 /**
504 * Sets the SSL port number for the FileZilla service.
505 *
506 * @param int $sslPort The new SSL port number.
507 */
508 public function setSslPort($sslPort)
509 {
510 $this->replace( self::LOCAL_CFG_SSL_PORT, $sslPort );
511 }
512
513 /**
514 * Replaces multiple key-value pairs in the configuration file.
515 *
516 * This method reads the current configuration file, replaces the specified key-value pairs,
517 * and updates the internal configuration state. It also updates the port and SSL port properties
518 * if they are included in the key-value pairs.
519 *
520 * @param array $params An associative array of key-value pairs to replace in the configuration file.
521 */
522 protected function replaceAll($params)
523 {
524 $content = file_get_contents( $this->bearsamppConf );
525
526 foreach ( $params as $key => $value ) {
527 $content = preg_replace( '|' . $key . ' = .*|', $key . ' = ' . '"' . $value . '"', $content );
528 $this->bearsamppConfRaw[$key] = $value;
529 switch ( $key ) {
531 $this->port = $value;
532 break;
534 $this->sslPort = $value;
535 break;
536 }
537 }
538
539 file_put_contents( $this->bearsamppConf, $content );
540 }
541}
global $bearsamppLang
global $bearsamppRoot
setEnable($enabled, $showWindow=false)
checkPort($port, $ssl=false, $showWindow=false)
changePort($port, $checkUsed=false, $wbProgressBar=null)
switchVersion($version, $showWindow=false)
updateConfig($version=null, $sub=0, $showWindow=false)
reload($id=null, $type=null)
__construct($id, $type)
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 ENABLE_BUNDLE_NOT_EXIST
const ERROR_CONF_NOT_FOUND
const SWITCH_VERSION_TITLE
const ERROR_EXE_NOT_FOUND
const FILEZILLA
const PORT_USED_BY
const PORT_NOT_USED
const BEARSAMPP_CONF_MALFORMED_ERROR
update($sub=0, $showWindow=false)
replace($key, $value)
static logReloadClass($classInstance)
static getHeaders($host, $port, $ssl=false)
static logError($data, $file=null)
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)
global $bearsamppConfig
Definition homepage.php:26
const APP_TITLE
Definition root.php:12