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