]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/History.php
Switch to PSR12, phpcbf fix
[galette.git] / galette / lib / Galette / Core / History.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * History management
7 *
8 * PHP version 5
9 *
10 * Copyright © 2009-2014 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Core
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2009-2014 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @version SVN: $Id$
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.7dev - 2009-02-09
36 */
37
38 namespace Galette\Core;
39
40 use Analog\Analog;
41 use Galette\Filters\HistoryList;
42 use Laminas\Db\Sql\Expression;
43 use Laminas\Db\Adapter\Adapter;
44 use Galette\Core\Preferences;
45
46 /**
47 * History management
48 *
49 * @category Core
50 * @name History
51 * @package Galette
52 * @author Johan Cwiklinski <johan@x-tnd.be>
53 * @copyright 2009-2014 The Galette Team
54 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
55 * @link http://galette.tuxfamily.org
56 * @since Available since 0.7dev - 2009-02-09
57 */
58
59 class History
60 {
61 const TABLE = 'logs';
62 const PK = 'id_log';
63
64 protected $count;
65 protected $zdb;
66 protected $login;
67 protected $filters;
68
69 protected $users;
70 protected $actions;
71
72 protected $with_lists = true;
73
74 /**
75 * Default constructor
76 *
77 * @param Db $zdb Database
78 * @param Login $login Login
79 * @param HistoryList $filters Filtering
80 */
81 public function __construct(Db $zdb, Login $login, $filters = null)
82 {
83 $this->zdb = $zdb;
84 $this->login = $login;
85
86 if ($filters === null) {
87 $this->filters = new HistoryList();
88 } else {
89 $this->filters = $filters;
90 }
91 }
92
93 /**
94 * Helper function to find the user IP address
95 *
96 * This function uses the client address or the appropriate part of
97 * X-Forwarded-For, if present and the configuration specifies it.
98 * (blindly trusting X-Forwarded-For would make the IP address logging
99 * very easy to deveive.
100 *
101 * @return string
102 */
103 public static function findUserIPAddress()
104 {
105 if (
106 defined('GALETTE_X_FORWARDED_FOR_INDEX')
107 && isset($_SERVER['HTTP_X_FORWARDED_FOR'])
108 ) {
109 $split_xff = preg_split('/,\s*/', $_SERVER['HTTP_X_FORWARDED_FOR']);
110 return $split_xff[count($split_xff) - GALETTE_X_FORWARDED_FOR_INDEX];
111 }
112 return $_SERVER['REMOTE_ADDR'];
113 }
114
115 /**
116 * Add a new entry
117 *
118 * @param string $action the action to log
119 * @param string $argument the argument
120 * @param string $query the query (if relevant)
121 *
122 * @return bool true if entry was successfully added, false otherwise
123 */
124 public function add($action, $argument = '', $query = '')
125 {
126 global $preferences;
127
128 if ($preferences->pref_log == Preferences::LOG_DISABLED) {
129 //logs are disabled
130 return true;
131 }
132
133 $ip = null;
134 if (PHP_SAPI === 'cli') {
135 $ip = '127.0.0.1';
136 } else {
137 $ip = self::findUserIpAddress();
138 }
139
140 try {
141 $values = array(
142 'date_log' => date('Y-m-d H:i:s'),
143 'ip_log' => $ip,
144 'adh_log' => $this->login->login,
145 'action_log' => $action,
146 'text_log' => $argument,
147 'sql_log' => $query
148 );
149
150 $insert = $this->zdb->insert($this->getTableName());
151 $insert->values($values);
152 $this->zdb->execute($insert);
153 } catch (\Exception $e) {
154 Analog::log(
155 "An error occurred trying to add log entry. " . $e->getMessage(),
156 Analog::ERROR
157 );
158 return false;
159 }
160
161 return true;
162 }
163
164 /**
165 * Delete all entries
166 *
167 * @return boolean
168 */
169 public function clean()
170 {
171 try {
172 $result = $this->zdb->db->query(
173 'TRUNCATE TABLE ' . $this->getTableName(true),
174 Adapter::QUERY_MODE_EXECUTE
175 );
176
177 if (!$result) {
178 Analog::log(
179 'An error occurred cleaning history. ',
180 Analog::WARNING
181 );
182 $this->add('Error flushing logs');
183 return false;
184 }
185 $this->add('Logs flushed');
186 $this->filters = new HistoryList();
187 return true;
188 } catch (\Exception $e) {
189 Analog::log(
190 'Unable to flush logs. | ' . $e->getMessage(),
191 Analog::WARNING
192 );
193 return false;
194 }
195 }
196
197 /**
198 * Get the entire history list
199 *
200 * @return array
201 */
202 public function getHistory()
203 {
204 try {
205 $select = $this->zdb->select($this->getTableName());
206 $this->buildWhereClause($select);
207 $select->order($this->buildOrderClause());
208 if ($this->with_lists === true) {
209 $this->buildLists($select);
210 }
211 $this->proceedCount($select);
212 //add limits to retrieve only relavant rows
213 $this->filters->setLimits($select);
214 $results = $this->zdb->execute($select);
215
216 $entries = [];
217 foreach ($results as $result) {
218 $entries[] = $result;
219 }
220
221 return $entries;
222 } catch (\Exception $e) {
223 Analog::log(
224 'Unable to get history. | ' . $e->getMessage(),
225 Analog::WARNING
226 );
227 return false;
228 }
229 }
230
231 /**
232 * Builds users and actions lists
233 *
234 * @param Select $select Original select
235 *
236 * @return void
237 */
238 private function buildLists($select)
239 {
240 try {
241 $usersSelect = clone $select;
242 $usersSelect->reset($usersSelect::COLUMNS);
243 $usersSelect->reset($usersSelect::ORDER);
244 $usersSelect->quantifier('DISTINCT')->columns(['adh_log']);
245 $usersSelect->order(['adh_log ASC']);
246
247 $results = $this->zdb->execute($usersSelect);
248
249 $this->users = [];
250 foreach ($results as $result) {
251 $this->users[] = $result->adh_log;
252 }
253 } catch (\Exception $e) {
254 Analog::log(
255 'Cannot list members from history! | ' . $e->getMessage(),
256 Analog::WARNING
257 );
258 }
259
260 try {
261 $actionsSelect = clone $select;
262 $actionsSelect->reset($actionsSelect::COLUMNS);
263 $actionsSelect->reset($actionsSelect::ORDER);
264 $actionsSelect->quantifier('DISTINCT')->columns(['action_log']);
265 $actionsSelect->order(['action_log ASC']);
266
267 $results = $this->zdb->execute($actionsSelect);
268
269 $this->actions = [];
270 foreach ($results as $result) {
271 $this->actions[] = $result->action_log;
272 }
273 } catch (\Exception $e) {
274 Analog::log(
275 'Cannot list actions from history! | ' . $e->getMessage(),
276 Analog::WARNING
277 );
278 }
279 }
280
281 /**
282 * Builds the order clause
283 *
284 * @return string SQL ORDER clause
285 */
286 protected function buildOrderClause()
287 {
288 $order = array();
289
290 switch ($this->filters->orderby) {
291 case HistoryList::ORDERBY_DATE:
292 $order[] = 'date_log ' . $this->filters->ordered;
293 break;
294 case HistoryList::ORDERBY_IP:
295 $order[] = 'ip_log ' . $this->filters->ordered;
296 break;
297 case HistoryList::ORDERBY_USER:
298 $order[] = 'adh_log ' . $this->filters->ordered;
299 break;
300 case HistoryList::ORDERBY_ACTION:
301 $order[] = 'action_log ' . $this->filters->ordered;
302 break;
303 }
304
305 return $order;
306 }
307
308 /**
309 * Builds where clause, for filtering on simple list mode
310 *
311 * @param Select $select Original select
312 *
313 * @return string SQL WHERE clause
314 */
315 private function buildWhereClause($select)
316 {
317 try {
318 if ($this->filters->start_date_filter != null) {
319 $d = new \DateTime($this->filters->raw_start_date_filter);
320 $d->setTime(0, 0, 0);
321 $select->where->greaterThanOrEqualTo(
322 'date_log',
323 $d->format('Y-m-d H:i:s')
324 );
325 }
326
327 if ($this->filters->end_date_filter != null) {
328 $d = new \DateTime($this->filters->raw_end_date_filter);
329 $d->setTime(23, 59, 59);
330 $select->where->lessThanOrEqualTo(
331 'date_log',
332 $d->format('Y-m-d H:i:s')
333 );
334 }
335
336 if ($this->filters->user_filter != null && $this->filters->user_filter != '0') {
337 $select->where->equalTo(
338 'adh_log',
339 $this->filters->user_filter
340 );
341 }
342
343 if ($this->filters->action_filter != null && $this->filters->action_filter != '0') {
344 $select->where->equalTo(
345 'action_log',
346 $this->filters->action_filter
347 );
348 }
349 } catch (\Exception $e) {
350 Analog::log(
351 __METHOD__ . ' | ' . $e->getMessage(),
352 Analog::WARNING
353 );
354 }
355 }
356
357 /**
358 * Count history entries from the query
359 *
360 * @param Select $select Original select
361 *
362 * @return void
363 */
364 private function proceedCount($select)
365 {
366 try {
367 $countSelect = clone $select;
368 $countSelect->reset($countSelect::COLUMNS);
369 $countSelect->reset($countSelect::JOINS);
370 $countSelect->reset($countSelect::ORDER);
371 $countSelect->columns(
372 array(
373 $this->getPk() => new Expression('COUNT(' . $this->getPk() . ')')
374 )
375 );
376
377 $results = $this->zdb->execute($countSelect);
378 $result = $results->current();
379
380 $k = $this->getPk();
381 $this->count = $result->$k;
382 if ($this->count > 0) {
383 $this->filters->setCounter($this->count);
384 }
385 } catch (\Exception $e) {
386 Analog::log(
387 'Cannot count history | ' . $e->getMessage(),
388 Analog::WARNING
389 );
390 return false;
391 }
392 }
393
394 /**
395 * Global getter method
396 *
397 * @param string $name name of the property we want to retrive
398 *
399 * @return false|object the called property
400 */
401 public function __get($name)
402 {
403 Analog::log(
404 '[History] Getting property `' . $name . '`',
405 Analog::DEBUG
406 );
407
408 $forbidden = array();
409 if (!in_array($name, $forbidden)) {
410 switch ($name) {
411 case 'fdate':
412 //return formatted datemime
413 try {
414 $d = new \DateTime($this->$name);
415 return $d->format(__("Y-m-d H:i:s"));
416 } catch (\Exception $e) {
417 //oops, we've got a bad date :/
418 Analog::log(
419 'Bad date (' . $this->$name . ') | ' .
420 $e->getMessage(),
421 Analog::INFO
422 );
423 return $this->$name;
424 }
425 break;
426 default:
427 return $this->$name;
428 break;
429 }
430 } else {
431 Analog::log(
432 '[History] Unable to get proprety `' . $name . '`',
433 Analog::WARNING
434 );
435 }
436 }
437
438 /**
439 * Global setter method
440 *
441 * @param string $name name of the property we want to assign a value to
442 * @param object $value a relevant value for the property
443 *
444 * @return void
445 */
446 public function __set($name, $value)
447 {
448 Analog::log(
449 '[History] Setting property `' . $name . '`',
450 Analog::DEBUG
451 );
452
453 $forbidden = array();
454 if (!in_array($name, $forbidden)) {
455 switch ($name) {
456 default:
457 $this->$name = $value;
458 break;
459 }
460 } else {
461 Analog::log(
462 '[History] Unable to set proprety `' . $name . '`',
463 Analog::WARNING
464 );
465 }
466 }
467
468 /**
469 * Get table's name
470 *
471 * @param boolean $prefixed Whether table name should be prefixed
472 *
473 * @return string
474 */
475 protected function getTableName($prefixed = false)
476 {
477 if ($prefixed === true) {
478 return PREFIX_DB . self::TABLE;
479 } else {
480 return self::TABLE;
481 }
482 }
483
484 /**
485 * Get table's PK
486 *
487 * @return string
488 */
489 protected function getPk()
490 {
491 return self::PK;
492 }
493
494 /**
495 * Set filters
496 *
497 * @param HistoryList $filters Filters
498 *
499 * @return History
500 */
501 public function setFilters(HistoryList $filters)
502 {
503 $this->filters = $filters;
504 return $this;
505 }
506
507 /**
508 * Get count for current query
509 *
510 * @return int
511 */
512 public function getCount()
513 {
514 return $this->count;
515 }
516
517 /**
518 * Get users list
519 *
520 * @return array
521 */
522 public function getUsersList()
523 {
524 return $this->users;
525 }
526
527 /**
528 * Get actions list
529 *
530 * @return array
531 */
532 public function getActionsList()
533 {
534 return $this->actions;
535 }
536 }