11<?php
2-
3- /*
4- Copyright (c) 2007, Till Brehm, projektfarm Gmbh
2+ /**
3+ Copyright (c) 2007-2022, Till Brehm, projektfarm Gmbh
54All rights reserved.
65
76Redistribution and use in source and binary forms, with or without modification,
2827EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2928*/
3029
31- //* Set timezone
32- if (isset ($ conf ['timezone ' ]) && $ conf ['timezone ' ] != '' ) date_default_timezone_set ($ conf ['timezone ' ]);
30+ // Set timezone
31+ if (isset ($ conf ['timezone ' ]) && $ conf ['timezone ' ] != '' ) { // note: !empty($conf['timezone']) should give the same result and is more idiomatic for current versions of PHP (gwyneth 20220315)
32+ date_default_timezone_set ($ conf ['timezone ' ]);
33+ }
3334
35+ /**
36+ * Class for defining (mostly static) methods that are commonly used across the whole application.
37+ *
38+ * @category unknown
39+ * @package server
40+ * @author Till Brehm
41+ * @license bsd-3-clause
42+ * @link empty
43+ **/
3444class app {
35-
36- var $ loaded_modules = array ();
37- var $ loaded_plugins = array ();
45+ /** @var array List of modules that have been loaded. */
46+ var $ loaded_modules = [];
47+ /** @var array List of plugins that have been loaded. */
48+ var $ loaded_plugins = [];
49+ /** @var callable Script calling this. */
3850 var $ _calling_script = '' ;
39- /**
40- * @var db
41- */
51+ /** @var resource? Database used for ISPConfig3. */
4252 public $ db ;
4353
54+ /**
55+ * Class constructor, which depends on the global configuration stored in $conf.
56+ *
57+ * @param void
58+ * @return void
59+ */
4460 function __construct () {
45-
61+ /** @var object Global object storing this application's configuration. */
4662 global $ conf ;
4763
4864 if ($ conf ['start_db ' ] == true ) {
49- $ this ->load ('db_ ' . $ conf ['db_type ' ]);
65+ $ this ->load ('db_ ' . $ conf ['db_type ' ]);
5066 try {
5167 $ this ->db = new db ;
52- } catch (Exception $ e ) {
68+ } catch (Exception $ e ) {
5369 $ this ->db = false ;
5470 }
5571
5672 /*
57- Initialize the connection to the master DB,
58- if we are in a multiserver setup
59- */
73+ Initialize the connection to the master DB,
74+ if we are in a multiserver setup
75+ */
6076
6177 if ($ conf ['dbmaster_host ' ] != '' && ($ conf ['dbmaster_host ' ] != $ conf ['db_host ' ] || ($ conf ['dbmaster_host ' ] == $ conf ['db_host ' ] && $ conf ['dbmaster_database ' ] != $ conf ['db_database ' ]))) {
6278 try {
@@ -67,14 +83,19 @@ function __construct() {
6783 } else {
6884 $ this ->dbmaster = $ this ->db ;
6985 }
70-
71-
7286 }
87+ } // end constructor
7388
74- }
75-
89+ /**
90+ * Getter method for some of the (valid) proprieties.
91+ *
92+ * @param string $name A valid property name to get. Will be checked for validity first!
93+ *
94+ * @return mixed
95+ */
7696 public function __get ($ name ) {
77- $ valid_names = array ('functions ' , 'getconf ' , 'letsencrypt ' , 'modules ' , 'plugins ' , 'services ' , 'system ' );
97+ /** @var array List of all possible proprieties that are valid to get. */
98+ $ valid_names = ['functions ' , 'getconf ' , 'letsencrypt ' , 'modules ' , 'plugins ' , 'services ' , 'system ' ];
7899 if (!in_array ($ name , $ valid_names )) {
79100 trigger_error ('Undefined property ' . $ name . ' of class app ' , E_USER_WARNING );
80101 }
@@ -89,14 +110,37 @@ public function __get($name) {
89110 }
90111 }
91112
113+ /**
114+ * Sets the calling script.
115+ *
116+ * @param callable $caller Calling script function.
117+ *
118+ * @return void
119+ */
92120 function setCaller ($ caller ) {
93121 $ this ->_calling_script = $ caller ;
94122 }
95123
124+ /**
125+ * Gets the calling script.
126+ *
127+ * Note that there is no error checking!
128+ *
129+ * @param void
130+ *
131+ * @return callable|null
132+ */
96133 function getCaller () {
97134 return $ this ->_calling_script ;
98135 }
99136
137+ /**
138+ * Emergency exit funcion.
139+ *
140+ * @param string $errmsg Error message to be displayedby the die() command on exit.
141+ *
142+ * @return void
143+ */
100144 function forceErrorExit ($ errmsg = 'undefined ' ) {
101145 global $ conf ;
102146
@@ -106,81 +150,145 @@ function forceErrorExit($errmsg = 'undefined') {
106150 die ('Exiting because of error: ' . $ errmsg );
107151 }
108152
153+ /**
154+ * Dynamic plugin loader and instantiator.
155+ *
156+ * This will include PHP scripts on demand, each representing a class to be loaded,
157+ * and if the process succeeds, it will retrieve an instance for the class.
158+ *
159+ * @param string $classes A list of plugin classes to be loaded (e.g. their files will be included)
160+ * and subsequently instantiated; it's a comma-separated string.
161+ *
162+ * @return void
163+ */
109164 function uses ($ classes ) {
110-
111165 global $ conf ;
112166
167+ /** @var array|null List of classes to be used, as an array, after successful 'explosion' */
113168 $ cl = explode (', ' , $ classes );
114169 if (is_array ($ cl )) {
115170 foreach ($ cl as $ classname ) {
116171 if (!@is_object ($ this ->$ classname )) {
117- if (is_file ($ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' ) && (DEVSYSTEM || !is_link ($ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' ))) {
118- include_once $ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' ;
172+ if (is_file ($ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' ) && (DEVSYSTEM || !is_link ($ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' ))) {
173+ include_once $ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' ;
119174 $ this ->$ classname = new $ classname ;
120175 }
121176 }
122177 }
123178 }
124179 }
125180
181+ /**
182+ * Dynamic plugin loader (no instantation).
183+ *
184+ * Similar to uses() but does _not_ instantate a new class; files are merely included.
185+ * die() is called on a failure to include the file for a class.
186+ *
187+ * @param string $classes A list of plugin classes to be loaded (e.g. their files will be included);
188+ * it's a comma-separated string.
189+ *
190+ * @return void
191+ */
126192 function load ($ classes ) {
127-
128193 global $ conf ;
129194
195+ /** @var array|null List of classes to be loaded, as an array, after successful 'explosion' */
130196 $ cl = explode (', ' , $ classes );
131197 if (is_array ($ cl )) {
132198 foreach ($ cl as $ classname ) {
133- if (is_file ($ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' ) && (DEVSYSTEM || !is_link ($ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' ))) {
134- include_once $ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' ;
199+ if (is_file ($ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' ) && (DEVSYSTEM || !is_link ($ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' ))) {
200+ include_once $ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' ;
135201 } else {
136- die ('Unable to load: ' . $ conf ['classpath ' ]. '/ ' . $ classname. '.inc.php ' );
202+ die ('Unable to load: ' . $ conf ['classpath ' ] . '/ ' . $ classname . '.inc.php ' );
137203 }
138204 }
139205 }
140206 }
141207
142- /*
143- 0 = DEBUG
144- 1 = WARNING
145- 2 = ERROR
146- */
147-
208+ /**
209+ * Logs a message with a certain priority to the different log backends.
210+ *
211+ * This method will check if the priority is equal or larger than what the user has
212+ * defined as the minimum logging level, and will output to several logging facilities:
213+ * - At the very least, the message will _usually_ go to stdout;
214+ * - It may optionally also go to the file log (usually `/var/log/ispconfig/ispconfig.log`)
215+ * which will be created if it doesn't exist;
216+ * - When the $dblog parameter is set to true (the default), the message will also be logged
217+ * to the database;
218+ * - If the system is configured to send email messages to the administrator,
219+ * this method will also handle those (assuming, again, that the priority matches).
220+ *
221+ * Debugging messages will also have the name of the calling module/script as well as a line number
222+ * to assist error tracking (gwyneth 20220315). This incurs in a slight performance hit.
223+ *
224+ * @param string $msg The message to be logged.
225+ * @param int $priority Should be set to 0 = DEBUG, 1 = WARNING or 2 = ERROR; anything else
226+ * will skip setting the priority textual variable.
227+ * @param bool $dblog Should the message also be logged to the database? (Default is _true_)
228+ *
229+ * @return void
230+ *
231+ * @note The error() method below seems to write to an invalid priority (3), which will cause
232+ * no message priority text to be emitted, and will _force_ a database write and/or sending
233+ * an email to the administrator.
234+ */
148235 function log ($ msg , $ priority = 0 , $ dblog = true ) {
149-
150236 global $ conf ;
151237
238+ /**
239+ * @var string $file_line_caller
240+ *
241+ * For debugging, deal with retrieving caller information from the stack. (gwyneth 20220315)
242+ * See https://stackoverflow.com/q/1252529/1035977 (including the precious comments!) for an explanation
243+ * of how this works.
244+ **/
245+ $ file_line_caller = "" ;
246+ /** @var string Defined here because recent versions of PHP are stricter with scoping issues. (gwyneth 20220315) */
247+ $ priority_txt = '' ;
248+
152249 switch ($ priority ) {
153250 case 0 :
154- $ priority_txt = 'DEBUG ' ;
155- break ;
251+ $ priority_txt = 'DEBUG ' ;
252+ $ bt = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS , 1 ); // we don't need _all_ data, so we save some processing time here (gwyneth 20220315)
253+ $ caller = array_shift ($ bt );
254+ $ file_line_caller = '[ ' . strtr (basename ($ caller ['file ' ], '.php ' ), '_ ' , ' ' ) . ': ' . $ caller ['line ' ] . '] ' ;
255+ break ;
156256 case 1 :
157- $ priority_txt = 'WARNING ' ;
158- break ;
257+ $ priority_txt = 'WARNING ' ;
258+ break ;
159259 case 2 :
160- $ priority_txt = 'ERROR ' ;
161- break ;
260+ $ priority_txt = 'ERROR ' ;
261+ break ;
262+ // Note: $this->error() seems to use case 3 to deliberately skip setting a priority text.
263+ // It will also *force* a write to the logs and/or send emails. (gwyneth 20220315)
162264 }
163- $ log_msg = @date ('d.m.Y-H:i ' ).' - ' .$ priority_txt .' - ' . $ msg ;
164265
266+ /** @var string Formatted message to be sent to the logging subsystems. */
267+ $ log_msg = @date ('d.m.Y-H:i ' ) . ' - ' . $ priority_txt .' ' . $ file_line_caller . '- ' . $ msg ;
268+
269+ // Check if the user-set priority defines that this message should be output at all.
165270 if ($ priority >= $ conf ['log_priority ' ]) {
166- //if (is_writable($conf["log_file"])) {
167- if (!$ fp = fopen ($ conf ['log_file ' ], 'a ' )) {
271+ // Prepare to add a line on the logfile, or to create the logfile in
272+ // append mode if it doesn't exist yet. Failure means that die() is called.
273+
274+ //if(is_writable($conf["log_file"])) {
275+ if (!$ fp = fopen ($ conf ['log_file ' ], 'a ' )) {
168276 die ('Unable to open logfile. ' );
169277 }
170278
171- if (!fwrite ($ fp , $ log_msg. " \r\n" )) {
279+ if (!fwrite ($ fp , $ log_msg . ' \r\n ' )) {
172280 die ('Unable to write to logfile. ' );
173281 }
174282
175- echo $ log_msg. "\n" ;
283+ echo $ log_msg . "\n" ;
176284 fclose ($ fp );
177285
178- // Log to database
286+ // Log to database.
179287 if ($ dblog === true && isset ($ this ->dbmaster )) {
180288 $ server_id = $ conf ['server_id ' ];
181289 $ loglevel = $ priority ;
182290 $ message = $ msg ;
183- $ datalog_id = (isset ($ this ->modules ->current_datalog_id ) && $ this ->modules ->current_datalog_id > 0 )?$ this ->modules ->current_datalog_id : 0 ;
291+ $ datalog_id = (isset ($ this ->modules ->current_datalog_id ) && $ this ->modules ->current_datalog_id > 0 )? $ this ->modules ->current_datalog_id : 0 ;
184292 if ($ datalog_id > 0 ) {
185293 $ tmp_rec = $ this ->dbmaster ->queryOneRecord ("SELECT count(syslog_id) as number FROM sys_log WHERE datalog_id = ? AND loglevel = ? " , $ datalog_id , LOGLEVEL_ERROR );
186294 //* Do not insert duplicate errors into the web log.
@@ -198,18 +306,18 @@ function log($msg, $priority = 0, $dblog = true) {
198306 // die("Unable to write to logfile.");
199307 //}
200308
201-
202309 } // if
203310
311+ // Send an email to the administrator if the current priority demands it.
204312 if (isset ($ conf ['admin_notify_priority ' ]) && $ priority >= $ conf ['admin_notify_priority ' ] && $ conf ['admin_mail ' ] != '' ) {
205313 if ($ conf ['hostname ' ] != 'localhost ' && $ conf ['hostname ' ] != '' ) {
206314 $ hostname = $ conf ['hostname ' ];
207315 } else {
208316 $ hostname = exec ('hostname -f ' );
209317 }
210- // send notification to admin
318+ // Send notification to admin.
211319 $ mailBody = $ hostname . " - " . $ log_msg ;
212- $ mailSubject = substr ("[ " . $ hostname . "] " . " " . $ log_msg , 0 , 70 ). '... ' ;
320+ $ mailSubject = substr ("[ " . $ hostname . "] " . " " . $ log_msg , 0 , 70 ) . '... ' ;
213321 $ mailHeaders = "MIME-Version: 1.0 " . "\n" ;
214322 $ mailHeaders .= "Content-type: text/plain; charset=utf-8 " . "\n" ;
215323 $ mailHeaders .= "Content-Transfer-Encoding: 8bit " . "\n" ;
@@ -218,26 +326,30 @@ function log($msg, $priority = 0, $dblog = true) {
218326
219327 mail ($ conf ['admin_mail ' ], $ mailSubject , $ mailBody , $ mailHeaders );
220328 }
221- } // func
222-
223-
224- /*
225- 0 = DEBUG
226- 1 = WARNING
227- 2 = ERROR
228- */
329+ } // func log
229330
331+ /**
332+ * Logs a message with an undefined priority (3) and dies.
333+ *
334+ * This method writes to an invalid/undefined priority level (3), which will cause
335+ * no message priority text to be emitted, but will _force_ a database write and/or sending
336+ * an email to the administrator.
337+ *
338+ * @param string $msg The message to be logged.
339+ *
340+ * @return void
341+ */
230342 function error ($ msg ) {
231- $ this ->log ($ msg , 3 );
343+ $ this ->log ($ msg , 3 ); // isn't this supposed to be error code 2? (gwyneth 20220315)
232344 die ($ msg );
233345 }
234-
235346}
236347
237- /*
238- Initialize application (app) object
239- */
240-
348+ /**
349+ * @var \app $app
350+ *
351+ * Initialize application object.
352+ */
241353$ app = new app ;
242354
243355?>
0 commit comments