]> git.mxchange.org Git - friendica.git/blob - src/Worker/CronJobs.php
Revert "Move Objects to Model"
[friendica.git] / src / Worker / CronJobs.php
1 <?php
2
3 /**
4  * @file src/worker/CronJobs.php
5  */
6
7 namespace Friendica\Worker;
8
9 use Friendica\App;
10 use Friendica\Core\Cache;
11 use Friendica\Core\Config;
12 use Friendica\Database\DBM;
13 use Friendica\Model\GlobalContact;
14 use Friendica\Network\Probe;
15 use Friendica\Object\Contact;
16 use Friendica\Protocol\PortableContact;
17 use dba;
18
19 class CronJobs
20 {
21         public static function execute($command = '')
22         {
23                 global $a;
24
25                 require_once 'include/datetime.php';
26                 require_once 'include/post_update.php';
27                 require_once 'mod/nodeinfo.php';
28                 require_once 'include/photos.php';
29
30                 // No parameter set? So return
31                 if ($command == '') {
32                         return;
33                 }
34
35                 logger("Starting cronjob " . $command, LOGGER_DEBUG);
36
37                 // Call possible post update functions
38                 // see include/post_update.php for more details
39                 if ($command == 'post_update') {
40                         post_update();
41                         return;
42                 }
43
44                 // update nodeinfo data
45                 if ($command == 'nodeinfo') {
46                         nodeinfo_cron();
47                         return;
48                 }
49
50                 // Expire and remove user entries
51                 if ($command == 'expire_and_remove_users') {
52                         self::expireAndRemoveUsers();
53                         return;
54                 }
55
56                 if ($command == 'update_contact_birthdays') {
57                         update_contact_birthdays();
58                         return;
59                 }
60
61                 if ($command == 'update_photo_albums') {
62                         self::updatePhotoAlbums();
63                         return;
64                 }
65
66                 // Clear cache entries
67                 if ($command == 'clear_cache') {
68                         self::clearCache($a);
69                         return;
70                 }
71
72                 // Repair missing Diaspora values in contacts
73                 if ($command == 'repair_diaspora') {
74                         self::repairDiaspora($a);
75                         return;
76                 }
77
78                 // Repair entries in the database
79                 if ($command == 'repair_database') {
80                         self::repairDatabase();
81                         return;
82                 }
83
84                 logger("Xronjob " . $command . " is unknown.", LOGGER_DEBUG);
85
86                 return;
87         }
88
89         /**
90          * @brief Update the cached values for the number of photo albums per user
91          */
92         private static function updatePhotoAlbums()
93         {
94                 $r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`");
95                 if (!DBM::is_result($r)) {
96                         return;
97                 }
98
99                 foreach ($r AS $user) {
100                         photo_albums($user['uid'], true);
101                 }
102         }
103
104         /**
105          * @brief Expire and remove user entries
106          */
107         private static function expireAndRemoveUsers()
108         {
109                 // expire any expired accounts
110                 q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
111                         AND `account_expires_on` > '%s'
112                         AND `account_expires_on` < UTC_TIMESTAMP()", dbesc(NULL_DATE));
113
114                 // delete user records for recently removed accounts
115                 $r = q("SELECT * FROM `user` WHERE `account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
116                 if (DBM::is_result($r)) {
117                         foreach ($r as $user) {
118                                 dba::delete('user', array('uid' => $user['uid']));
119                         }
120                 }
121         }
122
123         /**
124          * @brief Clear cache entries
125          *
126          * @param App $a
127          */
128         private static function clearCache(App $a)
129         {
130                 $last = Config::get('system', 'cache_last_cleared');
131
132                 if ($last) {
133                         $next = $last + (3600); // Once per hour
134                         $clear_cache = ($next <= time());
135                 } else {
136                         $clear_cache = true;
137                 }
138
139                 if (!$clear_cache) {
140                         return;
141                 }
142
143                 // clear old cache
144                 Cache::clear();
145
146                 // clear old item cache files
147                 clear_cache();
148
149                 // clear cache for photos
150                 clear_cache($a->get_basepath(), $a->get_basepath() . "/photo");
151
152                 // clear smarty cache
153                 clear_cache($a->get_basepath() . "/view/smarty3/compiled", $a->get_basepath() . "/view/smarty3/compiled");
154
155                 // clear cache for image proxy
156                 if (!Config::get("system", "proxy_disabled")) {
157                         clear_cache($a->get_basepath(), $a->get_basepath() . "/proxy");
158
159                         $cachetime = Config::get('system', 'proxy_cache_time');
160                         if (!$cachetime) {
161                                 $cachetime = PROXY_DEFAULT_TIME;
162                         }
163                         $condition = array('`uid` = 0 AND `resource-id` LIKE "pic:%" AND `created` < NOW() - INTERVAL ? SECOND', $cachetime);
164                         dba::delete('photo', $condition);
165                 }
166
167                 // Delete the cached OEmbed entries that are older than three month
168                 dba::delete('oembed', array("`created` < NOW() - INTERVAL 3 MONTH"));
169
170                 // Delete the cached "parse_url" entries that are older than three month
171                 dba::delete('parsed_url', array("`created` < NOW() - INTERVAL 3 MONTH"));
172
173                 // Maximum table size in megabyte
174                 $max_tablesize = intval(Config::get('system', 'optimize_max_tablesize')) * 1000000;
175                 if ($max_tablesize == 0) {
176                         $max_tablesize = 100 * 1000000; // Default are 100 MB
177                 }
178                 if ($max_tablesize > 0) {
179                         // Minimum fragmentation level in percent
180                         $fragmentation_level = intval(Config::get('system', 'optimize_fragmentation')) / 100;
181                         if ($fragmentation_level == 0) {
182                                 $fragmentation_level = 0.3; // Default value is 30%
183                         }
184
185                         // Optimize some tables that need to be optimized
186                         $r = q("SHOW TABLE STATUS");
187                         foreach ($r as $table) {
188
189                                 // Don't optimize tables that are too large
190                                 if ($table["Data_length"] > $max_tablesize) {
191                                         continue;
192                                 }
193
194                                 // Don't optimize empty tables
195                                 if ($table["Data_length"] == 0) {
196                                         continue;
197                                 }
198
199                                 // Calculate fragmentation
200                                 $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]);
201
202                                 logger("Table " . $table["Name"] . " - Fragmentation level: " . round($fragmentation * 100, 2), LOGGER_DEBUG);
203
204                                 // Don't optimize tables that needn't to be optimized
205                                 if ($fragmentation < $fragmentation_level) {
206                                         continue;
207                                 }
208
209                                 // So optimize it
210                                 logger("Optimize Table " . $table["Name"], LOGGER_DEBUG);
211                                 q("OPTIMIZE TABLE `%s`", dbesc($table["Name"]));
212                         }
213                 }
214
215                 Config::set('system', 'cache_last_cleared', time());
216         }
217
218         /**
219          * @brief Repair missing values in Diaspora contacts
220          *
221          * @param App $a
222          */
223         private static function repairDiaspora(App $a)
224         {
225                 $starttime = time();
226
227                 $r = q("SELECT `id`, `url` FROM `contact`
228                         WHERE `network` = '%s' AND (`batch` = '' OR `notify` = '' OR `poll` = '' OR pubkey = '')
229                                 ORDER BY RAND() LIMIT 50", dbesc(NETWORK_DIASPORA));
230                 if (!DBM::is_result($r)) {
231                         return;
232                 }
233
234                 foreach ($r AS $contact) {
235                         // Quit the loop after 3 minutes
236                         if (time() > ($starttime + 180)) {
237                                 return;
238                         }
239
240                         if (!PortableContact::reachable($contact["url"])) {
241                                 continue;
242                         }
243
244                         $data = Probe::uri($contact["url"]);
245                         if ($data["network"] != NETWORK_DIASPORA) {
246                                 continue;
247                         }
248
249                         logger("Repair contact " . $contact["id"] . " " . $contact["url"], LOGGER_DEBUG);
250                         q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d",
251                                 dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]),
252                                 intval($contact["id"]));
253                 }
254         }
255
256         /**
257          * @brief Do some repairs in database entries
258          *
259          */
260         private static function repairDatabase()
261         {
262                 // Sometimes there seem to be issues where the "self" contact vanishes.
263                 // We haven't found the origin of the problem by now.
264                 $r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)");
265                 if (DBM::is_result($r)) {
266                         foreach ($r AS $user) {
267                                 logger('Create missing self contact for user ' . $user['uid']);
268                                 Contact::createSelfFromUserId($user['uid']);
269                         }
270                 }
271
272                 // Set the parent if it wasn't set. (Shouldn't happen - but does sometimes)
273                 // This call is very "cheap" so we can do it at any time without a problem
274                 q("UPDATE `item` INNER JOIN `item` AS `parent` ON `parent`.`uri` = `item`.`parent-uri` AND `parent`.`uid` = `item`.`uid` SET `item`.`parent` = `parent`.`id` WHERE `item`.`parent` = 0");
275
276                 // There was an issue where the nick vanishes from the contact table
277                 q("UPDATE `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` SET `nick` = `nickname` WHERE `self` AND `nick`=''");
278
279                 // Update the global contacts for local users
280                 $r = q("SELECT `uid` FROM `user` WHERE `verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`");
281                 if (DBM::is_result($r)) {
282                         foreach ($r AS $user) {
283                                 GlobalContact::updateForUser($user["uid"]);
284                         }
285                 }
286
287                 /// @todo
288                 /// - remove thread entries without item
289                 /// - remove sign entries without item
290                 /// - remove children when parent got lost
291                 /// - set contact-id in item when not present
292         }
293 }