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