Passed
Push — master ( f13f78...5c1b24 )
by Ismayil
04:22
created

engine/classes/Elgg/Logger.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Elgg;
3
4
/**
5
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
6
 *
7
 * Use the elgg_* versions instead.
8
 *
9
 * @access private
10
 *
11
 * @package    Elgg.Core
12
 * @subpackage Logging
13
 * @since      1.9.0
14
 */
15
class Logger {
16
17
	const OFF = 0;
18
	const ERROR = 400;
19
	const WARNING = 300;
20
	const NOTICE = 250;
21
	const INFO = 200;
22
23
	protected static $levels = [
24
		0 => 'OFF',
25
		200 => 'INFO',
26
		250 => 'NOTICE',
27
		300 => 'WARNING',
28
		400 => 'ERROR',
29
	];
30
31
	/**
32
	 * @var int The logging level
33
	 */
34
	protected $level = self::ERROR;
35
36
	/**
37
	 * @var bool Display to user?
38
	 */
39
	protected $display = false;
40
41
	/**
42
	 * @var PluginHooksService
43
	 */
44
	protected $hooks;
45
46
	/**
47
	 * @var Context
48
	 */
49
	private $context;
50
51
	/**
52
	 * @var array
53
	 */
54
	private $disabled_stack;
55
56
	/**
57
	 * @var callable
58
	 */
59
	private $printer;
60
61
	/**
62
	 * Constructor
63
	 *
64
	 * @param PluginHooksService $hooks   Hooks service
65
	 * @param Context            $context Context service
66
	 */
67 257
	public function __construct(PluginHooksService $hooks, Context $context) {
68 257
		$this->hooks = $hooks;
69 257
		$this->context = $context;
70 257
	}
71
72
	/**
73
	 * Set the logging level
74
	 *
75
	 * @param int $level The logging level
76
	 * @return void
77
	 */
78 200
	public function setLevel($level) {
79 200
		if (!$level) {
80
			// 0 or empty string
81 1
			$this->level = self::OFF;
82 1
			return;
83
		}
84
85
		// @todo Elgg has used string constants for logging levels
86 199
		if (is_string($level)) {
87 198
			$level = strtoupper($level);
88 198
			$level = array_search($level, self::$levels);
89
90 198
			if ($level !== false) {
91 198
				$this->level = $level;
92
			} else {
93
				$this->warn(__METHOD__ .": invalid level ignored.");
94
			}
95 198
			return;
96
		}
97
98 1
		if (isset(self::$levels[$level])) {
99 1
			$this->level = $level;
100
		} else {
101
			$this->warn(__METHOD__ .": invalid level ignored.");
102
		}
103 1
	}
104
105
	/**
106
	 * Get the current logging level
107
	 *
108
	 * @return int
109
	 */
110 36
	public function getLevel() {
111 36
		return $this->level;
112
	}
113
114
	/**
115
	 * Set whether the logging should be displayed to the user
116
	 *
117
	 * Whether data is actually displayed to the user depends on this setting
118
	 * and other factors such as whether we are generating a JavaScript or CSS
119
	 * file.
120
	 *
121
	 * @param bool $display Whether to display logging
122
	 * @return void
123
	 */
124
	public function setDisplay($display) {
125
		$this->display = $display;
126
	}
127
128
	/**
129
	 * Set custom printer
130
	 *
131
	 * @param callable $printer Printer
132
	 * @return void
133
	 */
134
	public function setPrinter(callable $printer) {
135
		if (is_callable($printer)) {
136
			$this->printer = $printer;
137
		}
138
	}
139
140
	/**
141
	 * Add a message to the log
142
	 *
143
	 * @param string $message The message to log
144
	 * @param int    $level   The logging level
145
	 * @return bool Whether the messages was logged
146
	 */
147 384
	public function log($message, $level = self::NOTICE) {
148 384
		if ($this->disabled_stack) {
149
			// capture to top of stack
150 224
			end($this->disabled_stack);
151 224
			$key = key($this->disabled_stack);
152 224
			$this->disabled_stack[$key][] = [
153 224
				'message' => $message,
154 224
				'level' => $level,
155
			];
156
		}
157
158 384
		if ($this->level == self::OFF || $level < $this->level) {
159 287
			return false;
160
		}
161
162 112
		if (!array_key_exists($level, self::$levels)) {
163
			return false;
164
		}
165
166
		// when capturing, still use consistent return value
167 112
		if ($this->disabled_stack) {
168 106
			return true;
169
		}
170
171 7
		$levelString = self::$levels[$level];
172
173
		// notices and below never displayed to user
174 7
		$display = $this->display && $level > self::NOTICE;
175
176 7
		$this->process("$levelString: $message", $display, $level);
177
178 7
		return true;
179
	}
180
181
	/**
182
	 * Log message at the ERROR level
183
	 *
184
	 * @param string $message The message to log
185
	 * @return bool
186
	 */
187 30
	public function error($message) {
188 30
		return $this->log($message, self::ERROR);
189
	}
190
191
	/**
192
	 * Log message at the WARNING level
193
	 *
194
	 * @param string $message The message to log
195
	 * @return bool
196
	 */
197 13
	public function warn($message) {
198 13
		return $this->log($message, self::WARNING);
199
	}
200
201
	/**
202
	 * Log message at the NOTICE level
203
	 *
204
	 * @param string $message The message to log
205
	 * @return bool
206
	 */
207 88
	public function notice($message) {
208 88
		return $this->log($message, self::NOTICE);
209
	}
210
211
	/**
212
	 * Log message at the INFO level
213
	 *
214
	 * @param string $message The message to log
215
	 * @return bool
216
	 */
217 284
	public function info($message) {
218 284
		return $this->log($message, self::INFO);
219
	}
220
221
	/**
222
	 * Dump data to log or screen
223
	 *
224
	 * @param mixed $data    The data to log
225
	 * @param bool  $display Whether to include this in the HTML page
226
	 * @return void
227
	 */
228
	public function dump($data, $display = true) {
229
		$this->process($data, $display, self::ERROR);
230
	}
231
232
	/**
233
	 * Process logging data
234
	 *
235
	 * @param mixed $data    The data to process
236
	 * @param bool  $display Whether to display the data to the user. Otherwise log it.
237
	 * @param int   $level   The logging level for this data
238
	 * @return void
239
	 */
240 7
	protected function process($data, $display, $level) {
241
		
242
		// plugin can return false to stop the default logging method
243
		$params = [
244 7
			'level' => $level,
245 7
			'msg' => $data,
246 7
			'display' => $display,
247 7
			'to_screen' => $display,
248
		];
249
250 7
		if (!$this->hooks->trigger('debug', 'log', $params, true)) {
251 1
			return;
252
		}
253
254
		// Do not want to write to JS or CSS pages
255 6
		if ($this->context->contains('js') || $this->context->contains('css')) {
256
			$display = false;
257
		}
258
259
		// don't display in simplecache requests
260 6
		$path = substr(current_page_url(), strlen(elgg_get_site_url()));
261 6
		if (preg_match('~^(cache|action|serve-file)/~', $path)) {
262
			$display = false;
263
		}
264
265 6
		if ($display == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
266
			if ($this->printer) {
267
				call_user_func($this->printer, $data, $level);
268
			} else {
269
				echo '<pre class="elgg-logger-data">';
270
				echo htmlspecialchars(print_r($data, true), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
271
				echo '</pre>';
272
			}
273
		}
274
		
275 6
		error_log(print_r($data, true));
276 6
	}
277
278
	/**
279
	 * Temporarily disable logging and capture logs (before tests)
280
	 *
281
	 * Call disable() before your tests and enable() after. enable() will return a list of
282
	 * calls to log() (and helper methods) that were not acted upon.
283
	 *
284
	 * @note This behaves like a stack. You must call enable() for each disable() call.
285
	 *
286
	 * @return void
287
	 * @see enable
288
	 * @access private
289
	 * @internal
290
	 */
291 281
	public function disable() {
292 281
		$this->disabled_stack[] = [];
293 281
	}
294
295
	/**
296
	 * Restore logging and get record of log calls (after tests)
297
	 *
298
	 * @return array
299
	 * @see disable
300
	 * @access private
301
	 * @internal
302
	 */
303 262
	public function enable() {
304 262
		return array_pop($this->disabled_stack);
305
	}
306
307
	/**
308
	 * Reset the hooks service for this instance (testing)
309
	 *
310
	 * @return void
311
	 * @access private
312
	 * @internal
313
	 */
314 1
	public function setHooks(PluginHooksService $hooks) {
315 1
		$this->hooks = $hooks;
316 1
	}
317
}
318
319