Completed
Push — master ( bc0916...92f140 )
by cam
04:43
created

upgrade.php ➔ maj_base()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 14
nop 3
dl 0
loc 48
rs 7.8901
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
 * Mise à jour de la base de données
15
 *
16
 * @package SPIP\Core\SQL\Upgrade
17
 */
18
19
if (!defined('_ECRIRE_INC_VERSION')) {
20
	return;
21
}
22
23
if (!defined('_UPGRADE_TIME_OUT')) {
24
	/**
25
	 * Durée en secondes pour relancer les scripts de mises à jour, x secondes
26
	 * avant que la durée d'exécution du script provoque un timeout
27
	 *
28
	 * @var int
29
	 **/
30
	define('_UPGRADE_TIME_OUT', 20);
31
}
32
33
/**
34
 * Programme de mise à jour des tables SQL lors d'un changement de version.
35
 *
36
 * L'entrée dans cette fonction est reservée aux mises à jour de SPIP coeur.
37
 *
38
 * Marche aussi pour les plugins en appelant directement la fonction `maj_plugin`
39
 * Pour que ceux-ci profitent aussi de la reprise sur interruption,
40
 * ils doivent simplement indiquer leur numero de version installée dans une meta
41
 * et fournir le tableau `$maj` à la fonction `maj_plugin`.
42
 * La reprise sur timeout se fait alors par la page admin_plugin et jamais par ici.
43
 *
44
 * @uses creer_base()
45
 * @uses maj_base()
46
 * @uses auth_synchroniser_distant()
47
 *
48
 * @param string $titre
49
 * @param string $reprise Inutilisé
50
 * @return void
51
 */
52
function base_upgrade_dist($titre = '', $reprise = '') {
0 ignored issues
show
Unused Code introduced by
The parameter $reprise 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...
53
	if (!$titre) {
54
		return;
55
	} // anti-testeur automatique
56
	if ($GLOBALS['spip_version_base'] != $GLOBALS['meta']['version_installee']) {
57
		if (!is_numeric(_request('reinstall'))) {
58
			include_spip('base/create');
59
			spip_log('recree les tables eventuellement disparues', 'maj.' . _LOG_INFO_IMPORTANTE);
60
			creer_base();
61
		}
62
63
		// quand on rentre par ici, c'est toujours une mise a jour de SPIP
64
		// lancement de l'upgrade SPIP
65
		$res = maj_base();
66
67
		if ($res) {
68
			// on arrete tout ici !
69
			exit;
70
		}
71
	}
72
	spip_log('Fin de mise a jour SQL. Debut m-a-j acces et config', 'maj.' . _LOG_INFO_IMPORTANTE);
73
74
	// supprimer quelques fichiers temporaires qui peuvent se retrouver invalides
75
	@spip_unlink(_CACHE_RUBRIQUES);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
76
	@spip_unlink(_CACHE_PIPELINES);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
77
	@spip_unlink(_CACHE_PLUGINS_PATH);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
78
	@spip_unlink(_CACHE_PLUGINS_OPT);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
79
	@spip_unlink(_CACHE_PLUGINS_FCT);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
80
	@spip_unlink(_CACHE_CHEMIN);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
81
	@spip_unlink(_DIR_TMP . 'plugin_xml_cache.gz');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
82
83
	include_spip('inc/auth');
84
	auth_synchroniser_distant();
85
	$config = charger_fonction('config', 'inc');
86
	$config();
87
}
88
89
/**
90
 * Mise à jour de base de SPIP
91
 *
92
 * Exécute toutes les fonctions de mises à jour de SPIP nécessaires,
93
 * en fonction de la meta `version_installee` indiquant le numéro de
94
 * schéma actuel de la base de données.
95
 *
96
 * Les fonctions de mises à jour se trouvent dans `ecrire/maj/`
97
 * 
98
 * @note
99
 *     Si version nulle ou inexistante, c'est une nouvelle installation,
100
 *     on ne passe pas par le processus de mise à jour.
101
 * 
102
 *     De même en cas de version supérieure: ca devait être un test,
103
 *     il y a eu le message d'avertissement il doit savoir ce qu'il fait
104
 * 
105
 *     version_installee = YYYYMMDDNN; quand on a besoin de forcer une MAJ
106
 *     tel que 2021021800 où 00 est un incrément.
107
 *
108
 * @uses upgrade_test()
109
 * @uses maj_while()
110
 *
111
 * @param int $version_cible
112
 * @param string $redirect
113
 * @return array|bool
114
 */
115
function maj_base($version_cible = 0, $redirect = '', $debut_page = true) {
116
117
	$version_installee = $GLOBALS['meta']['version_installee'] ?? null;
118
119
	spip_log(
120
		"Version anterieure: $version_installee. Courante: " . $GLOBALS['spip_version_base'],
121
		'maj.' . _LOG_INFO_IMPORTANTE
122
	);
123
	if (!$version_installee or ($GLOBALS['spip_version_base'] < $version_installee)) {
124
		sql_replace(
125
			'spip_meta',
126
			array(
127
				'nom' => 'version_installee',
128
				'valeur' => $GLOBALS['spip_version_base'],
129
				'impt' => 'non'
130
			)
131
		);
132
		return false;
133
	}
134
	if (!upgrade_test()) {
135
		return true;
136
	}
137
138
	$cible = ($version_cible ? $version_cible : $GLOBALS['spip_version_base']);
139
140
	if ($version_installee < 2021010100) {
141
		include_spip('maj/legacy/v21');
142
		include_spip('maj/legacy/v30');
143
		include_spip('maj/legacy/v31');
144
		include_spip('maj/legacy/v32');
145
		include_spip('maj/legacy/v40');
146
	}
147
148
	include_spip('maj/2021');
149
150
	ksort($GLOBALS['maj']);
151
	$res = maj_while($version_installee, $cible, $GLOBALS['maj'], 'version_installee', 'meta', $redirect, $debut_page);
152
	if ($res) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $res 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...
153
		if (!is_array($res)) {
154
			spip_log("Pb d'acces SQL a la mise a jour", 'maj.' . _LOG_INFO_ERREUR);
155
		} else {
156
			echo _T('avis_operation_echec') . ' ' . join(' ', $res);
157
			echo install_fin_html();
158
		}
159
	}
160
161
	return $res;
162
}
163
164
/**
165
 * Mise à jour d'un plugin de SPIP
166
 *
167
 * Fonction appelée par la fonction de mise à jour d'un plugin.
168
 * On lui fournit un tableau de fonctions élementaires
169
 * dont l'indice est la version.
170
 *
171
 * @uses maj_while()
172
 *
173
 * @param string $nom_meta_base_version
174
 *     Nom de la meta informant de la version du schéma de données du plugin installé dans SPIP
175
 * @param string $version_cible
176
 *     Version du schéma de données dans le plugin (déclaré dans paquet.xml)
177
 * @param array $maj
178
 *     Tableau d'actions à faire à l'installation (clé `create`) et pour chaque
179
 *     version intermédiaire entre la version actuelle du schéma du plugin dans SPIP
180
 *     et la version du schéma déclaré dans le plugin (ex. clé `1.1.0`).
181
 *
182
 *     Chaque valeur est un tableau contenant une liste de fonctions à exécuter,
183
 *     cette liste étant elle-même un tableau avec premier paramètre le nom de la fonction
184
 *     et les suivant les paramètres à lui passer
185
 *
186
 *     Exemple :
187
 *
188
 *         ```
189
 *         array(
190
 *             'create' => array(
191
 *                 array('maj_tables', array('spip_rubriques', 'spip_articles')),
192
 *                 array('creer_base)),
193
 *             '1.1.0' => array(
194
 *                 array('sql_alter', 'TABLE spip_articles ADD INDEX truc (truc)'))
195
 *         )
196
 *         ```
197
 * @param string $table_meta
198
 *     Nom de la table meta (sans le prefixe spip_) dans laquelle trouver la meta $nom_meta_base_version
199
 * @return void
200
 */
201
function maj_plugin($nom_meta_base_version, $version_cible, $maj, $table_meta = 'meta') {
202
203
	if ($table_meta !== 'meta') {
204
		installer_table_meta($table_meta);
205
	}
206
207
	$current_version = null;
208
209
	if ((!isset($GLOBALS[$table_meta][$nom_meta_base_version]))
210
		|| (!spip_version_compare($current_version = $GLOBALS[$table_meta][$nom_meta_base_version], $version_cible, '='))
211
	) {
212
		// $maj['create'] contient les directives propres a la premiere creation de base
213
		// c'est une operation derogatoire qui fait aboutir directement dans la version_cible
214
		if (isset($maj['create'])) {
215
			if (!isset($GLOBALS[$table_meta][$nom_meta_base_version])) {
216
				// installation : on ne fait que l'operation create
217
				$maj = array('init' => $maj['create']);
218
				// et on lui ajoute un appel a inc/config
219
				// pour creer les metas par defaut
220
				$config = charger_fonction('config', 'inc');
221
				$maj[$version_cible] = array(array($config));
222
			}
223
			// dans tous les cas enlever cet index du tableau
224
			unset($maj['create']);
225
		}
226
		// si init, deja dans le bon ordre
227
		if (!isset($maj['init'])) {
228
			include_spip('inc/plugin'); // pour spip_version_compare
229
			uksort($maj, 'spip_version_compare');
230
		}
231
232
		// la redirection se fait par defaut sur la page d'administration des plugins
233
		// sauf lorsque nous sommes sur l'installation de SPIP
234
		// ou define _REDIRECT_MAJ_PLUGIN
235
		$redirect = (defined('_REDIRECT_MAJ_PLUGIN') ? _REDIRECT_MAJ_PLUGIN : generer_url_ecrire('admin_plugin'));
236
		if (defined('_ECRIRE_INSTALL')) {
237
			$redirect = parametre_url(generer_url_ecrire('install'), 'etape', _request('etape'));
238
		}
239
240
		$res = maj_while($current_version, $version_cible, $maj, $nom_meta_base_version, $table_meta, $redirect);
241
		if ($res) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $res 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...
242
			if (!is_array($res)) {
243
				spip_log("Pb d'acces SQL a la mise a jour", 'maj.' . _LOG_INFO_ERREUR);
244
			} else {
245
				echo '<p>' . _T('avis_operation_echec') . ' ' . join(' ', $res) . '</p>';
246
			}
247
		}
248
	}
249
}
250
251
/**
252
 * Relancer le hit de mise à jour avant timeout
253
 *
254
 * si pas de redirect fourni, on redirige vers `exec=upgrade` pour finir
255
 * ce qui doit être une mise à jour SPIP
256
 *
257
 * @uses redirige_formulaire()
258
 *
259
 * @param string $meta
260
 * @param string $table
261
 * @param string $redirect
262
 * @return void
263
 */
264
function relance_maj($meta, $table, $redirect = '') {
265
	include_spip('inc/headers');
266
	if (!$redirect) {
267
		// recuperer la valeur installee en cours
268
		// on la tronque numeriquement, elle ne sert pas reellement
269
		// sauf pour verifier que ce n'est pas oui ou non
270
		// sinon is_numeric va echouer sur un numero de version 1.2.3
271
		$installee = intval($GLOBALS[$table][$meta]);
272
		$redirect = generer_url_ecrire('upgrade', "reinstall=$installee&meta=$meta&table=$table", true);
273
	}
274
	echo redirige_formulaire($redirect);
275
	exit();
276
}
277
278
/**
279
 * Initialiser la page pour l'affichage des progrès de l'upgrade
280
 * uniquement si la page n'a pas déjà été initilalisée
281
 *
282
 * @param string $installee
283
 * @param string $meta
284
 * @param string $table
285
 * @return void
286
 */
287
function maj_debut_page($installee, $meta, $table) {
288
	static $done = false;
289
	if ($done) {
290
		return;
291
	}
292
	include_spip('inc/minipres');
293
	@ini_set('zlib.output_compression', '0'); // pour permettre l'affichage au fur et a mesure
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
294
	$timeout = _UPGRADE_TIME_OUT * 2;
295
	$titre = _T('titre_page_upgrade');
296
	$balise_img = charger_filtre('balise_img');
297
	$titre .= $balise_img(chemin_image('loader.svg'),'','loader');
298
	echo(install_debut_html($titre));
299
	// script de rechargement auto sur timeout
300
	$redirect = generer_url_ecrire('upgrade', "reinstall=$installee&meta=$meta&table=$table", true);
301
	echo http_script("window.setTimeout('location.href=\"" . $redirect . "\";'," . ($timeout * 1000) . ')');
302
	echo "<div style='text-align: left'>\n";
303
	if (ob_get_level()) {
304
		ob_flush();
305
	}
306
	flush();
307
	$done = true;
308
}
309
310
311
/**
312
 * Gestion des mises à jour de SPIP et des plugins
313
 *
314
 * À partir des versions > 1.926 (i.e SPIP > 1.9.2), cette fonction gere les MAJ.
315
 *
316
 * Se relancer soi-même pour éviter l'interruption pendant une operation SQL
317
 * (qu'on espère pas trop longue chacune) évidemment en ecrivant dans la meta
318
 * à quel numero on en est.
319
 *
320
 * Cette fonction peut servir aux plugins qui doivent donner comme arguments :
321
 *
322
 * 1. le numero de version courant (numéro de version 1.2.3 ou entier)
323
 * 2. le numero de version à atteindre (numéro de version 1.2.3 ou entier)
324
 * 3. le tableau des instructions de mise à jour à exécuter
325
 *    Pour profiter du mécanisme de reprise sur interruption il faut de plus
326
 * 4. le nom de la meta permettant de retrouver tout ca
327
 * 5. la table des meta ou elle se trouve (`$table_prefix . '_meta'` par défaut)
328
 *    (cf début de fichier)
329
 *
330
 * les fonctions `sql_xx` appelées lors des mises à jour sont supposées
331
 * atomiques et ne sont pas relancées en cas de timeout, mais les fonctions
332
 * spécifiques sont relancées jusqu'à ce qu'elles finissent.
333
 * Elles doivent donc s'assurer de progresser à chaque reprise.
334
 *
335
 * @uses maj_debut_page()
336
 * @uses serie_alter()
337
 * @uses relance_maj()
338
 *
339
 * @param string $installee
340
 * @param string $cible
341
 * @param array $maj
342
 * @param string $meta
343
 * @param string $table
344
 * @param string $redirect
345
 * @param bool $debut_page
346
 * @return array
347
 *    - tableau (étape, sous-étape) en cas d'échec,
348
 *    - tableau vide sinon.
349
 */
350
function maj_while($installee, $cible, $maj, $meta = '', $table = 'meta', $redirect = '', $debut_page = false) {
351
	# inclusions pour que les procedures d'upgrade disposent des fonctions de base
352
	include_spip('base/create');
353
	include_spip('base/abstract_sql');
354
	$trouver_table = charger_fonction('trouver_table', 'base');
355
	include_spip('inc/plugin'); // pour spip_version_compare
356
	$n = 0;
0 ignored issues
show
Unused Code introduced by
$n is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
357
	$time = time();
358
359
	if (!defined('_TIME_OUT')) {
360
		/**
361
		 * Définir le timeout qui peut-être utilisé dans les fonctions
362
		 * de mises à jour qui durent trop longtemps
363
		 *
364
		 * À utiliser tel que : `if (time() >= _TIME_OUT)`
365
		 *
366
		 * @var int
367
		 */
368
		define('_TIME_OUT', $time + _UPGRADE_TIME_OUT);
369
	}
370
371
	foreach ($maj as $v => $operations) {
372
		// si une maj pour cette version
373
		if ($v == 'init' or
374
			(spip_version_compare($v, $installee, '>')
375
				and spip_version_compare($v, $cible, '<='))
376
		) {
377
			if ($debut_page) {
378
				maj_debut_page($v, $meta, $table);
379
			}
380
			echo "MAJ $v";
381
			$etape = serie_alter($v, $operations, $meta, $table, $redirect);
382
			$trouver_table(''); // vider le cache des descriptions de table
383
			# echec sur une etape en cours ?
384
			# on sort
385
			if ($etape) {
386
				return array($v, $etape);
387
			}
388
			$n = time() - $time;
389
			spip_log("$table $meta: $v en $n secondes", 'maj.' . _LOG_INFO_IMPORTANTE);
390
			if ($meta) {
391
				ecrire_meta($meta, $installee = $v, 'oui', $table);
392
			}
393
			echo '<br />';
394
		}
395
		if (time() >= _TIME_OUT) {
396
			relance_maj($meta, $table, $redirect);
397
		}
398
	}
399
	$trouver_table(''); // vider le cache des descriptions de table
400
	// indispensable pour les chgt de versions qui n'ecrivent pas en base
401
	// tant pis pour la redondance eventuelle avec ci-dessus
402
	if ($meta) {
403
		ecrire_meta($meta, $cible, 'oui', $table);
404
	}
405
	spip_log("MAJ terminee. $meta: $installee", 'maj.' . _LOG_INFO_IMPORTANTE);
406
407
	return array();
408
}
409
410
/**
411
 * Appliquer une serie de changements qui risquent de partir en timeout
412
 *
413
 * Alter crée une copie temporaire d'une table, c'est lourd.
414
 *
415
 * @uses relance_maj()
416
 *
417
 * @param string $serie
418
 *   numero de version upgrade
419
 * @param array $q
420
 *   tableau des operations pour cette version
421
 * @param string $meta
422
 *   nom de la meta qui contient le numero de version
423
 * @param string $table
424
 *   nom de la table meta
425
 * @param string $redirect
426
 *   url de redirection en cas d'interruption
427
 * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
428
 */
429
function serie_alter($serie, $q = array(), $meta = '', $table = 'meta', $redirect = '') {
430
	$meta2 = $meta . '_maj_' . $serie;
431
	$etape = 0;
432
	if (isset($GLOBALS[$table][$meta2])) {
433
		$etape = intval($GLOBALS[$table][$meta2]);
434
	}
435
	foreach ($q as $i => $r) {
436
		if ($i >= $etape) {
437
			$msg = "maj $table $meta2 etape $i";
438
			if (is_array($r)
439
				and function_exists($f = array_shift($r))
440
			) {
441
				// note: $r (arguments de la fonction $f) peut avoir des données tabulaires
442
				spip_log("$msg: $f " . @join(',', $r), 'maj.' . _LOG_INFO_IMPORTANTE);
443
				// pour les fonctions atomiques sql_xx
444
				// on enregistre le meta avant de lancer la fonction,
445
				// de maniere a eviter de boucler sur timeout
446
				// mais pour les fonctions complexes,
447
				// il faut les rejouer jusqu'a achevement.
448
				// C'est a elle d'assurer qu'elles progressent a chaque rappel
449
				if (strncmp($f, 'sql_', 4) == 0) {
450
					ecrire_meta($meta2, $i + 1, 'non', $table);
451
				}
452
				echo " <span title='$i'>.</span>";
453
				call_user_func_array($f, $r);
454
				// si temps imparti depasse, on relance sans ecrire en meta
455
				// car on est peut etre sorti sur timeout si c'est une fonction longue
456
				if (time() >= _TIME_OUT) {
457
					relance_maj($meta, $table, $redirect);
458
				}
459
				ecrire_meta($meta2, $i + 1, 'non', $table);
460
				spip_log("$meta2: ok", 'maj.' . _LOG_INFO_IMPORTANTE);
461
			} else {
462
				if (!is_array($r)) {
463
					spip_log("maj $i format incorrect", 'maj.' . _LOG_ERREUR);
464
				} else {
465
					spip_log("maj $i fonction $f non definie", 'maj.' . _LOG_ERREUR);
0 ignored issues
show
Bug introduced by
The variable $f does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
466
				}
467
				// en cas d'erreur serieuse, on s'arrete
468
				// mais on permet de passer par dessus en rechargeant la page.
469
				return $i + 1;
470
			}
471
		}
472
	}
473
	effacer_meta($meta2, $table);
474
475
	return 0;
476
}
477
478
479
/**
480
 * Mise à jour des types MIME de documents
481
 *
482
 * Fonction utilisé par les vieilles mises à jour de SPIP, à appeler dans
483
 * le tableau `$maj` quand on rajoute des types MIME. Remplacé actuellement
484
 * par le plugin Medias.
485
 *
486
 * @deprecated 3.1
487
 * @see Utiliser directement `creer_base_types_doc()` du plugin Medias
488
 * @example
489
 *     ```
490
 *     $GLOBALS['maj'][1953] = array(array('upgrade_types_documents'));
491
 *
492
 *     ```
493
 * @uses creer_base_types_doc()
494
 *
495
 **/
496
function upgrade_types_documents() {
497
	if (include_spip('base/medias')
498
		and function_exists('creer_base_types_doc')
499
	) {
500
		creer_base_types_doc();
501
	}
502
}
503
504
/**
505
 * Vérifie qu'il est possible d'ajouter une colonne à une table SQL
506
 *
507
 * @return bool True si possible.
508
 **/
509
function upgrade_test() {
510
	sql_drop_table('spip_test', true);
511
	sql_create('spip_test', array('a' => 'int'));
512
	sql_alter('TABLE spip_test ADD b INT');
513
	sql_insertq('spip_test', array('b' => 1), array('field' => array('b' => 'int')));
514
	$result = sql_select('b', 'spip_test');
515
	// ne pas garder le resultat de la requete sinon sqlite3
516
	// ne peut pas supprimer la table spip_test lors du sql_alter qui suit
517
	// car cette table serait alors 'verouillee'
518
	$result = $result ? true : false;
519
	sql_alter('TABLE spip_test DROP b');
520
521
	return $result;
522
}
523