3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
10 * Copyright © 2009-2023 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
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.
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.
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/>.
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2009-2023 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 * @link http://galette.tuxfamily.org
34 * @since Available since 0.7dev - 2009-02-09
37 namespace Galette\Core
;
41 use Galette\Filters\HistoryList
;
42 use Laminas\Db\Sql\Expression
;
43 use Laminas\Db\Adapter\Adapter
;
44 use Laminas\Db\Sql\Select
;
52 * @author Johan Cwiklinski <johan@x-tnd.be>
53 * @copyright 2009-2023 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
58 * @property HistoryList $filters
63 public const TABLE
= 'logs';
64 public const PK
= 'id_log';
69 protected $preferences;
75 protected $with_lists = true;
80 * @param Db $zdb Database
81 * @param Login $login Login
82 * @param Preferences $preferences Preferences
83 * @param HistoryList $filters Filtering
85 public function __construct(Db
$zdb, Login
$login, Preferences
$preferences, $filters = null)
88 $this->login
= $login;
89 $this->preferences
= $preferences;
91 if ($filters === null) {
92 $this->filters
= new HistoryList();
94 $this->filters
= $filters;
99 * Helper function to find the user IP address
101 * This function uses the client address or the appropriate part of
102 * X-Forwarded-For, if present and the configuration specifies it.
103 * (blindly trusting X-Forwarded-For would make the IP address logging
104 * very easy to deveive.
108 public static function findUserIPAddress()
111 defined('GALETTE_X_FORWARDED_FOR_INDEX')
112 && isset($_SERVER['HTTP_X_FORWARDED_FOR'])
114 $split_xff = preg_split('/,\s*/', $_SERVER['HTTP_X_FORWARDED_FOR']);
115 return $split_xff[count($split_xff) - GALETTE_X_FORWARDED_FOR_INDEX
];
117 return $_SERVER['REMOTE_ADDR'];
123 * @param string $action the action to log
124 * @param string $argument the argument
125 * @param string $query the query (if relevant)
127 * @return bool true if entry was successfully added, false otherwise
129 public function add($action, $argument = '', $query = '')
131 if ($this->preferences
->pref_log
== Preferences
::LOG_DISABLED
) {
137 if (PHP_SAPI
=== 'cli') {
140 $ip = self
::findUserIpAddress();
145 'date_log' => date('Y-m-d H:i:s'),
147 'adh_log' => $this->login
->login
,
148 'action_log' => $action,
149 'text_log' => $argument,
153 $insert = $this->zdb
->insert($this->getTableName());
154 $insert->values($values);
155 $this->zdb
->execute($insert);
156 } catch (Throwable
$e) {
158 "An error occurred trying to add log entry. " . $e->getMessage(),
172 public function clean()
175 $result = $this->zdb
->db
->query(
176 'TRUNCATE TABLE ' . $this->getTableName(true),
177 Adapter
::QUERY_MODE_EXECUTE
182 'An error occurred cleaning history. ',
185 $this->add('Error flushing logs');
188 $this->add('Logs flushed');
189 $this->filters
= new HistoryList();
191 } catch (Throwable
$e) {
193 'Unable to flush logs. | ' . $e->getMessage(),
201 * Get the entire history list
205 public function getHistory()
208 $select = $this->zdb
->select($this->getTableName());
209 $this->buildWhereClause($select);
210 $select->order($this->buildOrderClause());
211 if ($this->with_lists
=== true) {
212 $this->buildLists($select);
214 $this->proceedCount($select);
215 //add limits to retrieve only relavant rows
216 $this->filters
->setLimits($select);
217 $results = $this->zdb
->execute($select);
220 foreach ($results as $result) {
221 $entries[] = $result;
225 } catch (Throwable
$e) {
227 'Unable to get history. | ' . $e->getMessage(),
235 * Builds users and actions lists
237 * @param Select $select Original select
241 private function buildLists(Select
$select)
244 $usersSelect = clone $select;
245 $usersSelect->reset($usersSelect::COLUMNS
);
246 $usersSelect->reset($usersSelect::ORDER
);
247 $usersSelect->quantifier('DISTINCT')->columns(['adh_log']);
248 $usersSelect->order(['adh_log ASC']);
250 $results = $this->zdb
->execute($usersSelect);
253 foreach ($results as $result) {
254 $this->users
[] = $result->adh_log
;
256 } catch (Throwable
$e) {
258 'Cannot list members from history! | ' . $e->getMessage(),
264 $actionsSelect = clone $select;
265 $actionsSelect->reset($actionsSelect::COLUMNS
);
266 $actionsSelect->reset($actionsSelect::ORDER
);
267 $actionsSelect->quantifier('DISTINCT')->columns(['action_log']);
268 $actionsSelect->order(['action_log ASC']);
270 $results = $this->zdb
->execute($actionsSelect);
273 foreach ($results as $result) {
274 $this->actions
[] = $result->action_log
;
276 } catch (Throwable
$e) {
278 'Cannot list actions from history! | ' . $e->getMessage(),
286 * Builds the order clause
288 * @return array SQL ORDER clauses
290 protected function buildOrderClause()
294 switch ($this->filters
->orderby
) {
295 case HistoryList
::ORDERBY_DATE
:
296 $order[] = 'date_log ' . $this->filters
->ordered
;
298 case HistoryList
::ORDERBY_IP
:
299 $order[] = 'ip_log ' . $this->filters
->ordered
;
301 case HistoryList
::ORDERBY_USER
:
302 $order[] = 'adh_log ' . $this->filters
->ordered
;
304 case HistoryList
::ORDERBY_ACTION
:
305 $order[] = 'action_log ' . $this->filters
->ordered
;
313 * Builds where clause, for filtering on simple list mode
315 * @param Select $select Original select
319 private function buildWhereClause(Select
$select)
322 if ($this->filters
->start_date_filter
!= null) {
323 $d = new \
DateTime($this->filters
->raw_start_date_filter
);
324 $d->setTime(0, 0, 0);
325 $select->where
->greaterThanOrEqualTo(
327 $d->format('Y-m-d H:i:s')
331 if ($this->filters
->end_date_filter
!= null) {
332 $d = new \
DateTime($this->filters
->raw_end_date_filter
);
333 $d->setTime(23, 59, 59);
334 $select->where
->lessThanOrEqualTo(
336 $d->format('Y-m-d H:i:s')
340 if ($this->filters
->user_filter
!= null && $this->filters
->user_filter
!= '0') {
341 $select->where
->equalTo(
343 $this->filters
->user_filter
347 if ($this->filters
->action_filter
!= null && $this->filters
->action_filter
!= '0') {
348 $select->where
->equalTo(
350 $this->filters
->action_filter
353 } catch (Throwable
$e) {
355 __METHOD__
. ' | ' . $e->getMessage(),
363 * Count history entries from the query
365 * @param Select $select Original select
369 private function proceedCount(Select
$select)
372 $countSelect = clone $select;
373 $countSelect->reset($countSelect::COLUMNS
);
374 $countSelect->reset($countSelect::JOINS
);
375 $countSelect->reset($countSelect::ORDER
);
376 $countSelect->columns(
378 $this->getPk() => new Expression('COUNT(' . $this->getPk() . ')')
382 $results = $this->zdb
->execute($countSelect);
383 $result = $results->current();
386 $this->count
= $result->$k;
387 if ($this->count
> 0) {
388 $this->filters
->setCounter($this->count
);
390 } catch (Throwable
$e) {
392 'Cannot count history | ' . $e->getMessage(),
400 * Global getter method
402 * @param string $name name of the property we want to retrieve
404 * @return mixed the called property
406 public function __get($name)
409 '[History] Getting property `' . $name . '`',
413 $forbidden = array();
414 if (!in_array($name, $forbidden)) {
418 '[History] Unable to get property `' . $name . '`',
425 * Global isset method
426 * Required for twig to access properties via __get
428 * @param string $name name of the property we want to retrieve
432 public function __isset($name)
434 if (isset($this->$name)) {
441 * Global setter method
443 * @param string $name name of the property we want to assign a value to
444 * @param object $value a relevant value for the property
448 public function __set($name, $value)
451 '[History] Setting property `' . $name . '`',
455 $forbidden = array();
456 if (!in_array($name, $forbidden)) {
459 $this->$name = $value;
464 '[History] Unable to set property `' . $name . '`',
473 * @param boolean $prefixed Whether table name should be prefixed
477 protected function getTableName($prefixed = false)
479 if ($prefixed === true) {
480 return PREFIX_DB
. self
::TABLE
;
491 protected function getPk()
499 * @param HistoryList $filters Filters
503 public function setFilters(HistoryList
$filters)
505 $this->filters
= $filters;
510 * Get count for current query
514 public function getCount()
524 public function getUsersList()
534 public function getActionsList()
536 return $this->actions
;