]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/History.php
10c9968c7863ad43198c68ed99316b20ef2b74b2
[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 (defined('GALETTE_X_FORWARDED_FOR_INDEX')
106 && isset($_SERVER['HTTP_X_FORWARDED_FOR'])
107 ) {
108 $split_xff = preg_split('/,\s*/', $_SERVER['HTTP_X_FORWARDED_FOR']);
109 return $split_xff[count($split_xff) - GALETTE_X_FORWARDED_FOR_INDEX];
110 }
111 return $_SERVER['REMOTE_ADDR'];
112 }
113
114 /**
115 * Add a new entry
116 *
117 * @param string $action the action to log
118 * @param string $argument the argument
119 * @param string $query the query (if relevant)
120 *
121 * @return bool true if entry was successfully added, false otherwise
122 */
123 public function add($action, $argument = '', $query = '')
124 {
125 global $preferences;
126
127 if ($preferences->pref_log == Preferences::LOG_DISABLED) {
128 //logs are disabled
129 return true;
130 }
131
132 $ip = null;
133 if (PHP_SAPI === 'cli') {
134 $ip = '127.0.0.1';
135 } else {
136 $ip = self::findUserIpAddress();
137 }
138
139 try {
140 $values = array(
141 'date_log' => date('Y-m-d H:i:s'),
142 'ip_log' => $ip,
143 'adh_log' => $this->login->login,
144 'action_log' => $action,
145 'text_log' => $argument,
146 'sql_log' => $query
147 );
148
149 $insert = $this->zdb->insert($this->getTableName());
150 $insert->values($values);
151 $this->zdb->execute($insert);
152 } catch (\Exception $e) {
153 Analog::log(
154 "An error occurred trying to add log entry. " . $e->getMessage(),
155 Analog::ERROR
156 );
157 return false;
158 }
159
160 return true;
161 }
162
163 /**
164 * Delete all entries
165 *
166 * @return boolean
167 */
168 public function clean()
169 {
170 try {
171 $result = $this->zdb->db->query(
172 'TRUNCATE TABLE ' . $this->getTableName(true),
173 Adapter::QUERY_MODE_EXECUTE
174 );
175
176 if (!$result) {
177 Analog::log(
178 'An error occurred cleaning history. ',
179 Analog::WARNING
180 );
181 $this->add('Error flushing logs');
182 return false;
183 }
184 $this->add('Logs flushed');
185 $this->filters = new HistoryList();
186 return true;
187 } catch (\Exception $e) {
188 Analog::log(
189 'Unable to flush logs. | ' . $e->getMessage(),
190 Analog::WARNING
191 );
192 return false;
193 }
194 }
195
196 /**
197 * Get the entire history list
198 *
199 * @return array
200 */
201 public function getHistory()
202 {
203 try {
204 $select = $this->zdb->select($this->getTableName());
205 $this->buildWhereClause($select);
206 $select->order($this->buildOrderClause());
207 if ($this->with_lists === true) {
208 $this->buildLists($select);
209 }
210 $this->proceedCount($select);
211 //add limits to retrieve only relavant rows
212 $this->filters->setLimits($select);
213 $results = $this->zdb->execute($select);
214
215 $entries = [];
216 foreach ($results as $result) {
217 $entries[] = $result;
218 }
219
220 return $entries;
221 } catch (\Exception $e) {
222 Analog::log(
223 'Unable to get history. | ' . $e->getMessage(),
224 Analog::WARNING
225 );
226 return false;
227 }
228 }
229
230 /**
231 * Builds users and actions lists
232 *
233 * @param Select $select Original select
234 *
235 * @return void
236 */
237 private function buildLists($select)
238 {
239 try {
240 $usersSelect = clone $select;
241 $usersSelect->reset($usersSelect::COLUMNS);
242 $usersSelect->reset($usersSelect::ORDER);
243 $usersSelect->quantifier('DISTINCT')->columns(['adh_log']);
244 $usersSelect->order(['adh_log ASC']);
245
246 $results = $this->zdb->execute($usersSelect);
247
248 $this->users = [];
249 foreach ($results as $result) {
250 $this->users[] = $result->adh_log;
251 }
252 } catch (\Exception $e) {
253 Analog::log(
254 'Cannot list members from history! | ' . $e->getMessage(),
255 Analog::WARNING
256 );
257 }
258
259 try {
260 $actionsSelect = clone $select;
261 $actionsSelect->reset($actionsSelect::COLUMNS);
262 $actionsSelect->reset($actionsSelect::ORDER);
263 $actionsSelect->quantifier('DISTINCT')->columns(['action_log']);
264 $actionsSelect->order(['action_log ASC']);
265
266 $results = $this->zdb->execute($actionsSelect);
267
268 $this->actions = [];
269 foreach ($results as $result) {
270 $this->actions[] = $result->action_log;
271 }
272 } catch (\Exception $e) {
273 Analog::log(
274 'Cannot list actions from history! | ' . $e->getMessage(),
275 Analog::WARNING
276 );
277 }
278 }
279
280 /**
281 * Builds the order clause
282 *
283 * @return string SQL ORDER clause
284 */
285 protected function buildOrderClause()
286 {
287 $order = array();
288
289 switch ($this->filters->orderby) {
290 case HistoryList::ORDERBY_DATE:
291 $order[] = 'date_log ' . $this->filters->ordered;
292 break;
293 case HistoryList::ORDERBY_IP:
294 $order[] = 'ip_log ' . $this->filters->ordered;
295 break;
296 case HistoryList::ORDERBY_USER:
297 $order[] = 'adh_log ' . $this->filters->ordered;
298 break;
299 case HistoryList::ORDERBY_ACTION:
300 $order[] = 'action_log ' . $this->filters->ordered;
301 break;
302 }
303
304 return $order;
305 }
306
307 /**
308 * Builds where clause, for filtering on simple list mode
309 *
310 * @param Select $select Original select
311 *
312 * @return string SQL WHERE clause
313 */
314 private function buildWhereClause($select)
315 {
316 try {
317 if ($this->filters->start_date_filter != null) {
318 $d = new \DateTime($this->filters->raw_start_date_filter);
319 $d->setTime(0, 0, 0);
320 $select->where->greaterThanOrEqualTo(
321 'date_log',
322 $d->format('Y-m-d H:i:s')
323 );
324 }
325
326 if ($this->filters->end_date_filter != null) {
327 $d = new \DateTime($this->filters->raw_end_date_filter);
328 $d->setTime(23, 59, 59);
329 $select->where->lessThanOrEqualTo(
330 'date_log',
331 $d->format('Y-m-d H:i:s')
332 );
333 }
334
335 if ($this->filters->user_filter != null && $this->filters->user_filter != '0') {
336 $select->where->equalTo(
337 'adh_log',
338 $this->filters->user_filter
339 );
340 }
341
342 if ($this->filters->action_filter != null && $this->filters->action_filter != '0') {
343 $select->where->equalTo(
344 'action_log',
345 $this->filters->action_filter
346 );
347 }
348 } catch (\Exception $e) {
349 Analog::log(
350 __METHOD__ . ' | ' . $e->getMessage(),
351 Analog::WARNING
352 );
353 }
354 }
355
356 /**
357 * Count history entries from the query
358 *
359 * @param Select $select Original select
360 *
361 * @return void
362 */
363 private function proceedCount($select)
364 {
365 try {
366 $countSelect = clone $select;
367 $countSelect->reset($countSelect::COLUMNS);
368 $countSelect->reset($countSelect::JOINS);
369 $countSelect->reset($countSelect::ORDER);
370 $countSelect->columns(
371 array(
372 $this->getPk() => new Expression('COUNT(' . $this->getPk() . ')')
373 )
374 );
375
376 $results = $this->zdb->execute($countSelect);
377 $result = $results->current();
378
379 $k = $this->getPk();
380 $this->count = $result->$k;
381 if ($this->count > 0) {
382 $this->filters->setCounter($this->count);
383 }
384 } catch (\Exception $e) {
385 Analog::log(
386 'Cannot count history | ' . $e->getMessage(),
387 Analog::WARNING
388 );
389 return false;
390 }
391 }
392
393 /**
394 * Global getter method
395 *
396 * @param string $name name of the property we want to retrive
397 *
398 * @return false|object the called property
399 */
400 public function __get($name)
401 {
402 Analog::log(
403 '[History] Getting property `' . $name . '`',
404 Analog::DEBUG
405 );
406
407 $forbidden = array();
408 if (!in_array($name, $forbidden)) {
409 switch ($name) {
410 case 'fdate':
411 //return formatted datemime
412 try {
413 $d = new \DateTime($this->$name);
414 return $d->format(__("Y-m-d H:i:s"));
415 } catch (\Exception $e) {
416 //oops, we've got a bad date :/
417 Analog::log(
418 'Bad date (' . $this->$name . ') | ' .
419 $e->getMessage(),
420 Analog::INFO
421 );
422 return $this->$name;
423 }
424 break;
425 default:
426 return $this->$name;
427 break;
428 }
429 } else {
430 Analog::log(
431 '[History] Unable to get proprety `' .$name . '`',
432 Analog::WARNING
433 );
434 }
435 }
436
437 /**
438 * Global setter method
439 *
440 * @param string $name name of the property we want to assign a value to
441 * @param object $value a relevant value for the property
442 *
443 * @return void
444 */
445 public function __set($name, $value)
446 {
447 Analog::log(
448 '[History] Setting property `' . $name . '`',
449 Analog::DEBUG
450 );
451
452 $forbidden = array();
453 if (!in_array($name, $forbidden)) {
454 switch ($name) {
455 default:
456 $this->$name = $value;
457 break;
458 }
459 } else {
460 Analog::log(
461 '[History] Unable to set proprety `' .$name . '`',
462 Analog::WARNING
463 );
464 }
465 }
466
467 /**
468 * Get table's name
469 *
470 * @param boolean $prefixed Whether table name should be prefixed
471 *
472 * @return string
473 */
474 protected function getTableName($prefixed = false)
475 {
476 if ($prefixed === true) {
477 return PREFIX_DB . self::TABLE;
478 } else {
479 return self::TABLE;
480 }
481 }
482
483 /**
484 * Get table's PK
485 *
486 * @return string
487 */
488 protected function getPk()
489 {
490 return self::PK;
491 }
492
493 /**
494 * Set filters
495 *
496 * @param HistoryList $filters Filters
497 *
498 * @return History
499 */
500 public function setFilters(HistoryList $filters)
501 {
502 $this->filters = $filters;
503 return $this;
504 }
505
506 /**
507 * Get count for current query
508 *
509 * @return int
510 */
511 public function getCount()
512 {
513 return $this->count;
514 }
515
516 /**
517 * Get users list
518 *
519 * @return array
520 */
521 public function getUsersList()
522 {
523 return $this->users;
524 }
525
526 /**
527 * Get actions list
528 *
529 * @return array
530 */
531 public function getActionsList()
532 {
533 return $this->actions;
534 }
535 }