Completed
Push — master ( 8dedb1...3e6f39 )
by cam
04:51
created

optimiser.php ➔ optimiser_caches_contextes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
/***************************************************************************\
4
 *  SPIP, Système de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright © avec tendresse depuis 2001                                 *
7
 *  Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James  *
8
 *                                                                         *
9
 *  Ce programme est un logiciel libre distribué sous licence GNU/GPL.     *
10
 *  Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne.   *
11
\***************************************************************************/
12
13
/**
14
 * Gestion des optimisations de la base de données en cron
15
 *
16
 * @package SPIP\Core\Genie\Optimiser
17
 **/
18
19
if (!defined('_ECRIRE_INC_VERSION')) {
20
	return;
21
}
22
23
include_spip('base/abstract_sql');
24
include_spip('inc/config');
25
26
/**
27
 * Cron d'optimisation de la base de données
28
 *
29
 * Tache appelée régulièrement
30
 *
31
 * @param int $t
32
 *     Timestamp de la date de dernier appel de la tâche
33
 * @return int
34
 *     Timestamp de la date du prochain appel de la tâche
35
 **/
36
function genie_optimiser_dist($t) {
0 ignored issues
show
Unused Code introduced by
The parameter $t is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
37
38
	optimiser_base_une_table();
39
	optimiser_base();
40
	optimiser_caches_contextes();
41
42
	// la date souhaitee pour le tour suivant = apres-demain a 4h du mat ;
43
	// sachant qu'on a un delai de 48h, on renvoie aujourd'hui a 4h du mat
44
	// avec une periode de flou entre 2h et 6h pour ne pas saturer un hebergeur
45
	// qui aurait beaucoup de sites SPIP
46
	return -(mktime(2, 0, 0) + rand(0, 3600 * 4));
47
}
48
49
/**
50
 * Vider les contextes ajax de plus de 48h
51
 */
52
function optimiser_caches_contextes() {
53
	sous_repertoire(_DIR_CACHE, 'contextes');
54
	if (is_dir( $d = _DIR_CACHE . 'contextes')) {
55
		include_spip('inc/invalideur');
56
		purger_repertoire($d, ['mtime' => time() - 48*24*3600, 'limit' => 10000]);
57
	}
58
}
59
60
/**
61
 * Optimise la base de données
62
 *
63
 * Supprime les relicats d'éléments qui ont disparu
64
 *
65
 * @note
66
 *     Heure de référence pour le garbage collector = 24h auparavant
67
 * @param int $attente
68
 *     Attente entre 2 exécutions de la tache en secondes
69
 * @return void
70
 **/
71
function optimiser_base($attente = 86400) {
72
	optimiser_base_disparus($attente);
73
}
74
75
76
/**
77
 * Lance une requête d'optimisation sur une des tables SQL de la
78
 * base de données.
79
 *
80
 * À chaque appel, une nouvelle table est optimisée (la suivante dans la
81
 * liste par rapport à la dernière fois).
82
 *
83
 * @see sql_optimize()
84
 *
85
 * @global int $GLOBALS ['meta']['optimiser_table']
86
 **/
87
function optimiser_base_une_table() {
88
89
	$tables = array();
90
	$result = sql_showbase();
91
92
	// on n'optimise qu'une seule table a chaque fois,
93
	// pour ne pas vautrer le systeme
94
	// lire http://dev.mysql.com/doc/refman/5.0/fr/optimize-table.html
95
	while ($row = sql_fetch($result)) {
96
		$tables[] = array_shift($row);
97
	}
98
99
	spip_log("optimiser_base_une_table ".json_encode($tables), 'genie'._LOG_DEBUG);
100
	if ($tables) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tables of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
101
		$table_op = intval(lire_config('optimiser_table', 0) + 1) % sizeof($tables);
102
		ecrire_config('optimiser_table', $table_op);
103
		$q = $tables[$table_op];
104
		spip_log("optimiser_base_une_table : debut d'optimisation de la table $q", 'genie'._LOG_DEBUG);
105
		if (sql_optimize($q)) {
106
			spip_log("optimiser_base_une_table : fin d'optimisation de la table $q", 'genie'._LOG_DEBUG);
107
		} else {
108
			spip_log("optimiser_base_une_table : Pas d'optimiseur necessaire", 'genie'._LOG_DEBUG);
109
		}
110
	}
111
}
112
113
114
/**
115
 * Supprime des enregistrements d'une table SQL dont les ids à supprimer
116
 * se trouvent dans les résultats de ressource SQL transmise, sous la colonne 'id'
117
 *
118
 * @note
119
 *     Mysql < 4.0 refuse les requetes DELETE multi table
120
 *     et elles ont une syntaxe differente entre 4.0 et 4.1
121
 *     On passe donc par un SELECT puis DELETE avec IN
122
 *
123
 * @param string $table
124
 *     Nom de la table SQL, exemple : spip_articles
125
 * @param string $id
126
 *     Nom de la clé primaire de la table, exemple : id_article
127
 * @param Resource $sel
128
 *     Ressource SQL issue d'une sélection (sql_select) et contenant une
129
 *     colonne 'id' ayant l'identifiant de la clé primaire à supprimer
130
 * @param string $and
131
 *     Condition AND à appliquer en plus sur la requête de suppression
132
 * @return int
133
 *     Nombre de suppressions
134
 **/
135
function optimiser_sansref($table, $id, $sel, $and = '') {
136
	$in = array();
137
	while ($row = sql_fetch($sel)) {
138
		$in[$row['id']] = true;
139
	}
140
	sql_free($sel);
141
142
	if ($in) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $in of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
143
		sql_delete($table, sql_in($id, array_keys($in)) . ($and ? " AND $and" : ''));
144
		spip_log("optimiser_sansref: Numeros des entrees $id supprimees dans la table $table: " . implode(', ', array_keys($in)), 'genie'._LOG_DEBUG);
145
	}
146
147
	return count($in);
148
}
149
150
151
/**
152
 * Suppression des liens morts entre tables
153
 *
154
 * Supprime des liens morts entre tables suite à la suppression d'articles,
155
 * d'auteurs, etc...
156
 *
157
 * @note
158
 *     Maintenant que MySQL 5 a des Cascades on pourrait faire autrement
159
 *     mais on garde la compatibilité avec les versions précédentes.
160
 *
161
 * @pipeline_appel optimiser_base_disparus
162
 *
163
 * @param int $attente
164
 *     Attente entre 2 exécutions de la tache en secondes
165
 * @return void
166
 **/
167
function optimiser_base_disparus($attente = 86400) {
168
169
	# format = 20060610110141, si on veut forcer une optimisation tout de suite
170
	$mydate = date("Y-m-d H:i:s", time() - $attente);
171
	$mydate_quote = sql_quote($mydate);
172
173
	$n = 0;
174
175
	//
176
	// Rubriques
177
	//
178
179
	# les articles qui sont dans une id_rubrique inexistante
180
	# attention on controle id_rubrique>0 pour ne pas tuer les articles
181
	# specialement affectes a une rubrique non-existante (plugin,
182
	# cf. https://core.spip.net/issues/1549 )
183
	$res = sql_select("A.id_article AS id",
184
		"spip_articles AS A
185
		        LEFT JOIN spip_rubriques AS R
186
		          ON A.id_rubrique=R.id_rubrique",
187
		"A.id_rubrique > 0
188
			 AND R.id_rubrique IS NULL
189
		         AND A.maj < $mydate_quote");
190
191
	$n += optimiser_sansref('spip_articles', 'id_article', $res);
192
193
	// les articles a la poubelle
194
	sql_delete("spip_articles", "statut='poubelle' AND maj < $mydate_quote");
195
196
	//
197
	// Auteurs
198
	//
199
200
	include_spip('action/editer_liens');
201
	// optimiser les liens de tous les auteurs vers des objets effaces
202
	// et depuis des auteurs effaces
203
	$n += objet_optimiser_liens(array('auteur' => '*'), '*');
204
205
	# effacer les auteurs poubelle qui ne sont lies a rien
206
	$res = sql_select("A.id_auteur AS id",
207
		"spip_auteurs AS A
208
		      	LEFT JOIN spip_auteurs_liens AS L
209
		          ON L.id_auteur=A.id_auteur",
210
		"L.id_auteur IS NULL
211
		       	AND A.statut='5poubelle' AND A.maj < $mydate_quote");
212
213
	$n += optimiser_sansref('spip_auteurs', 'id_auteur', $res);
214
215
	# supprimer les auteurs 'nouveau' qui n'ont jamais donne suite
216
	# au mail de confirmation (45 jours pour repondre, ca devrait suffire)
217
	if (!defined('_AUTEURS_DELAI_REJET_NOUVEAU')) {
218
		define('_AUTEURS_DELAI_REJET_NOUVEAU', 45 * 24 * 3600);
219
	}
220
	sql_delete("spip_auteurs", "statut='nouveau' AND maj < " . sql_quote(date('Y-m-d', time() - intval(_AUTEURS_DELAI_REJET_NOUVEAU))));
221
222
	/**
223
	 * Permet aux plugins de compléter l'optimisation suite aux éléments disparus
224
	 *
225
	 * L'index 'data' est un entier indiquant le nombre d'optimisations
226
	 * qui ont été réalisées (par exemple le nombre de suppressions faites)
227
	 * et qui doit être incrémenté par les fonctions
228
	 * utilisant ce pipeline si elles suppriment des éléments.
229
	 *
230
	 * @pipeline_appel optimiser_base_disparus
231
	 */
232
	$n = pipeline('optimiser_base_disparus', array(
233
		'args' => array(
234
			'attente' => $attente,
235
			'date' => $mydate
236
		),
237
		'data' => $n
238
	));
239
240
241
	spip_log("optimiser_base_disparus : {$n} lien(s) mort(s)", 'genie'._LOG_DEBUG);
242
}
243