[FEATURE] Add scheduler task to anonymize IP addresses of tables
[Packages/TYPO3.CMS.git] / typo3 / sysext / scheduler / Classes / Task / IpAnonymizationTask.php
1 <?php
2
3 namespace TYPO3\CMS\Scheduler\Task;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\Database\ConnectionPool;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\IpAnonymizationUtility;
21
22 /**
23 * Anonymize IP addresses in records
24 *
25 * This task anonymizes IP addresses in tables older than the given number of days.
26 *
27 * Available tables must be registered in
28 * $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']
29 * See ext_localconf.php of scheduler extension for an example
30 */
31 class IpAnonymizationTask extends AbstractTask
32 {
33
34 /**
35 * @var int Number of days
36 */
37 public $numberOfDays = 180;
38
39 /**
40 * @var int mask level see \TYPO3\CMS\Core\Utility\IpAnonymizationUtility::anonymizeIp
41 */
42 public $mask = 2;
43
44 /**
45 * @var string Table to clean up
46 */
47 public $table = '';
48
49 /**
50 * Execute garbage collection, called by scheduler.
51 *
52 * @throws \RuntimeException If configured table was not cleaned up
53 * @return bool TRUE if task run was successful
54 */
55 public function execute()
56 {
57 $configuration = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][self::class]['options']['tables'][$this->table] ?? [];
58 if (empty($configuration)) {
59 throw new \RuntimeException(self::class . ' misconfiguration: ' . $this->table . ' does not exist in configuration', 1524502548);
60 }
61 $this->handleTable($this->table, $configuration);
62 return true;
63 }
64
65 /**
66 * Execute clean up of a specific table
67 *
68 * @throws \RuntimeException If table configuration is broken
69 * @param string $table The table to handle
70 * @param array $configuration Clean up configuration
71 * @return bool TRUE if cleanup was successful
72 */
73 protected function handleTable($table, array $configuration)
74 {
75 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
76 $queryBuilder = $connection->createQueryBuilder();
77 $queryBuilder->getRestrictions()->removeAll();
78
79 if (empty($configuration['dateField'])) {
80 throw new \RuntimeException(self::class . ' misconfiguration: "dateField" must be defined for table ' . $table, 1524502549);
81 }
82 if (empty($configuration['ipField'])) {
83 throw new \RuntimeException(self::class . ' misconfiguration: "ipField" must be defined for table ' . $table, 1524502666);
84 }
85 $deleteTimestamp = strtotime('-' . $this->numberOfDays . 'days');
86 if ($deleteTimestamp === false) {
87 throw new \RuntimeException(self::class . ' misconfiguration: number of days could not be calculated for table ' . $table, 1524526354);
88 }
89 try {
90 $result = $queryBuilder
91 ->select('uid', $configuration['ipField'])
92 ->where(
93 $queryBuilder->expr()->lt(
94 $configuration['dateField'],
95 $queryBuilder->createNamedParameter($deleteTimestamp, \PDO::PARAM_INT)
96 ),
97 $queryBuilder->expr()->neq(
98 $configuration['ipField'],
99 $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
100 ),
101 $queryBuilder->expr()->isNotNull($configuration['ipField']),
102 $queryBuilder->expr()->notLike(
103 $configuration['ipField'],
104 $queryBuilder->createNamedParameter('%.0.0', \PDO::PARAM_STR)
105 ),
106 $queryBuilder->expr()->notLike(
107 $configuration['ipField'],
108 $queryBuilder->createNamedParameter('%::', \PDO::PARAM_STR)
109 )
110 )
111 ->from($table)
112 ->execute();
113
114 while ($row = $result->fetch()) {
115 $ip = (string)$row[$configuration['ipField']];
116
117 $connection->update(
118 $table,
119 [
120 $configuration['ipField'] => IpAnonymizationUtility::anonymizeIp($ip, $this->mask)
121 ],
122 [
123 'uid' => $row['uid']
124 ]
125 );
126 }
127 } catch (\Exception $e) {
128 throw new \RuntimeException(self::class . ' failed for table ' . $this->table . ' with error: ' . $e->getMessage(), 1524502550);
129 }
130 return true;
131 }
132
133 /**
134 * This method returns the selected table as additional information
135 *
136 * @return string Information to display
137 */
138 public function getAdditionalInformation()
139 {
140 return sprintf($GLOBALS['LANG']->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.ipAnonymization.additionalInformationTable'), $this->table, $this->numberOfDays);
141 }
142 }