Completed
Push — master ( c3d345...31d75f )
by cam
01:10
created
prive/formulaires/editer_auteur.php 1 patch
Indentation   +364 added lines, -364 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@  discard block
 block discarded – undo
7 7
  **/
8 8
 
9 9
 if (!defined('_ECRIRE_INC_VERSION')) {
10
-	return;
10
+    return;
11 11
 }
12 12
 
13 13
 include_spip('inc/actions');
@@ -37,21 +37,21 @@  discard block
 block discarded – undo
37 37
  *     Environnement du formulaire
38 38
  **/
39 39
 function formulaires_editer_auteur_charger_dist(
40
-	$id_auteur = 'new',
41
-	$retour = '',
42
-	$associer_objet = '',
43
-	$config_fonc = 'auteurs_edit_config',
44
-	$row = [],
45
-	$hidden = ''
40
+    $id_auteur = 'new',
41
+    $retour = '',
42
+    $associer_objet = '',
43
+    $config_fonc = 'auteurs_edit_config',
44
+    $row = [],
45
+    $hidden = ''
46 46
 ) {
47
-	$valeurs = formulaires_editer_objet_charger('auteur', $id_auteur, 0, 0, $retour, $config_fonc, $row, $hidden);
48
-	$valeurs['new_login'] = $valeurs['login'];
47
+    $valeurs = formulaires_editer_objet_charger('auteur', $id_auteur, 0, 0, $retour, $config_fonc, $row, $hidden);
48
+    $valeurs['new_login'] = $valeurs['login'];
49 49
 
50
-	if (!autoriser('modifier', 'auteur', intval($id_auteur))) {
51
-		$valeurs['editable'] = '';
52
-	}
50
+    if (!autoriser('modifier', 'auteur', intval($id_auteur))) {
51
+        $valeurs['editable'] = '';
52
+    }
53 53
 
54
-	return $valeurs;
54
+    return $valeurs;
55 55
 }
56 56
 
57 57
 /**
@@ -75,14 +75,14 @@  discard block
 block discarded – undo
75 75
  *     Hash du formulaire
76 76
  */
77 77
 function formulaires_editer_auteur_identifier_dist(
78
-	$id_auteur = 'new',
79
-	$retour = '',
80
-	$associer_objet = '',
81
-	$config_fonc = 'auteurs_edit_config',
82
-	$row = [],
83
-	$hidden = ''
78
+    $id_auteur = 'new',
79
+    $retour = '',
80
+    $associer_objet = '',
81
+    $config_fonc = 'auteurs_edit_config',
82
+    $row = [],
83
+    $hidden = ''
84 84
 ) {
85
-	return serialize([intval($id_auteur), $associer_objet]);
85
+    return serialize([intval($id_auteur), $associer_objet]);
86 86
 }
87 87
 
88 88
 
@@ -96,27 +96,27 @@  discard block
 block discarded – undo
96 96
  */
97 97
 function auteurs_edit_config(array $row): array {
98 98
 
99
-	$config = [];
100
-	$config['lignes'] = 8;
101
-	$config['langue'] = $GLOBALS['spip_lang'];
102
-
103
-	// pour instituer_auteur
104
-	$config['auteur'] = $row;
105
-
106
-	//$config['restreint'] = ($row['statut'] == 'publie');
107
-	$auth_methode = $row['source'];
108
-	include_spip('inc/auth');
109
-	$config['edit_login'] =
110
-		(auth_autoriser_modifier_login($auth_methode)
111
-			and autoriser('modifier', 'auteur', $row['id_auteur'], null, ['login' => true])
112
-			// legacy : ne pas risquer d'autoriser la modif login si fonction d'autorisation pas mise a jour et ne teste que l'option email
113
-			and autoriser('modifier', 'auteur', $row['id_auteur'], null, ['email' => true])
114
-		);
115
-	$config['edit_pass'] =
116
-		(auth_autoriser_modifier_pass($auth_methode)
117
-			and autoriser('modifier', 'auteur', $row['id_auteur']));
118
-
119
-	return $config;
99
+    $config = [];
100
+    $config['lignes'] = 8;
101
+    $config['langue'] = $GLOBALS['spip_lang'];
102
+
103
+    // pour instituer_auteur
104
+    $config['auteur'] = $row;
105
+
106
+    //$config['restreint'] = ($row['statut'] == 'publie');
107
+    $auth_methode = $row['source'];
108
+    include_spip('inc/auth');
109
+    $config['edit_login'] =
110
+        (auth_autoriser_modifier_login($auth_methode)
111
+            and autoriser('modifier', 'auteur', $row['id_auteur'], null, ['login' => true])
112
+            // legacy : ne pas risquer d'autoriser la modif login si fonction d'autorisation pas mise a jour et ne teste que l'option email
113
+            and autoriser('modifier', 'auteur', $row['id_auteur'], null, ['email' => true])
114
+        );
115
+    $config['edit_pass'] =
116
+        (auth_autoriser_modifier_pass($auth_methode)
117
+            and autoriser('modifier', 'auteur', $row['id_auteur']));
118
+
119
+    return $config;
120 120
 }
121 121
 
122 122
 /**
@@ -146,143 +146,143 @@  discard block
 block discarded – undo
146 146
  *     Erreurs des saisies
147 147
  **/
148 148
 function formulaires_editer_auteur_verifier_dist(
149
-	$id_auteur = 'new',
150
-	$retour = '',
151
-	$associer_objet = '',
152
-	$config_fonc = 'auteurs_edit_config',
153
-	$row = [],
154
-	$hidden = ''
149
+    $id_auteur = 'new',
150
+    $retour = '',
151
+    $associer_objet = '',
152
+    $config_fonc = 'auteurs_edit_config',
153
+    $row = [],
154
+    $hidden = ''
155 155
 ) {
156
-	// auto-renseigner le nom si il n'existe pas, sans couper
157
-	titre_automatique('nom', ['email', 'login'], 255);
158
-
159
-	$oblis = ['nom'];
160
-	// si on veut renvoyer des identifiants il faut un email et un login
161
-	if (_request('reset_password')) {
162
-		$oblis[] = 'email';
163
-		$oblis[] = 'new_login';
164
-	}
165
-	// mais il reste obligatoire si on a rien trouve
166
-	$erreurs = formulaires_editer_objet_verifier('auteur', $id_auteur, $oblis);
167
-	if (isset($erreurs['new_login'])) {
168
-		$erreurs['login'] = $erreurs['new_login'];
169
-		unset($erreurs['new_login']);
170
-	}
171
-
172
-	$auth_methode = sql_getfetsel('source', 'spip_auteurs', 'id_auteur=' . intval($id_auteur));
173
-	$auth_methode = ($auth_methode ?: 'spip');
174
-	include_spip('inc/auth');
175
-
176
-	if (!nom_acceptable(_request('nom'))) {
177
-		$erreurs['nom'] = _T('info_nom_pas_conforme');
178
-	}
179
-
180
-	if ($email = _request('email')) {
181
-		include_spip('inc/filtres');
182
-		include_spip('inc/autoriser');
183
-		// un redacteur qui modifie son email n'a pas le droit de le vider si il y en avait un
184
-		if (
185
-			!autoriser('modifier', 'auteur', $id_auteur, null, ['email' => '?'])
186
-			and $GLOBALS['visiteur_session']['id_auteur'] == $id_auteur
187
-			and !strlen(trim($email))
188
-			and $email != ($email_ancien = sql_getfetsel('email', 'spip_auteurs', 'id_auteur=' . intval($id_auteur)))
189
-		) {
190
-			$erreurs['email'] = (($id_auteur == $GLOBALS['visiteur_session']['id_auteur']) ? _T('form_email_non_valide') : _T('form_prop_indiquer_email'));
191
-		} else {
192
-			if (!email_valide($email)) {
193
-				$erreurs['email'] = (($id_auteur == $GLOBALS['visiteur_session']['id_auteur']) ? _T('form_email_non_valide') : _T('form_prop_indiquer_email'));
194
-			}
195
-		}
196
-		# Ne pas autoriser d'avoir deux auteurs avec le même email
197
-		# cette fonctionalité nécessite que la base soit clean à l'activation : pas de
198
-		# doublon sur la requête select email,count(*) from spip_auteurs group by email ;
199
-		if (defined('_INTERDIRE_AUTEUR_MEME_EMAIL')) {
200
-			#Nouvel auteur
201
-			if (intval($id_auteur) == 0) {
202
-				#Un auteur existe deja avec cette adresse ?
203
-				if (sql_countsel('spip_auteurs', 'email=' . sql_quote($email)) > 0) {
204
-					$erreurs['email'] = _T('erreur_email_deja_existant');
205
-				}
206
-			} else {
207
-				#Un auteur existe deja avec cette adresse ? et n'est pas le user courant.
208
-				if (
209
-					(sql_countsel(
210
-						'spip_auteurs',
211
-						'email=' . sql_quote($email)
212
-					) > 0) and ($id_auteur != ($id_auteur_ancien = sql_getfetsel(
213
-						'id_auteur',
214
-						'spip_auteurs',
215
-						'email=' . sql_quote($email)
216
-					)))
217
-				) {
218
-					$erreurs['email'] = _T('erreur_email_deja_existant');
219
-				}
220
-			}
221
-		}
222
-	}
223
-
224
-	// quand c'est un auteur existant on fait le reset password ici
225
-	if (!(is_countable($erreurs) ? count($erreurs) : 0) and _request('reset_password') and intval($id_auteur)) {
226
-		$erreurs = auteur_reset_password($id_auteur, $erreurs);
227
-		return $erreurs;
228
-	}
229
-
230
-	// corriger un cas si frequent : www.example.org sans le http:// qui precede
231
-	if ($url = _request('url_site') and !tester_url_absolue($url)) {
232
-		if (strpos($url, ':') === false and strncasecmp($url, 'www.', 4) === 0) {
233
-			$url = 'http://' . $url;
234
-			set_request('url_site', $url);
235
-		}
236
-	}
237
-	// traiter les liens implicites avant de tester l'url
238
-	include_spip('inc/lien');
239
-	if ($url = calculer_url(_request('url_site')) and !tester_url_absolue($url)) {
240
-		$erreurs['url_site'] = _T('info_url_site_pas_conforme');
241
-	}
242
-
243
-	$erreurs['message_erreur'] = '';
244
-	if (_request('login')) {
245
-		// on n'est jamais cense poster le name 'login'
246
-		$erreurs['login'] = _T('info_non_modifiable');
247
-	}
248
-	elseif (
249
-		($login = _request('new_login')) and
250
-		$login !== sql_getfetsel('login', 'spip_auteurs', 'id_auteur=' . intval($id_auteur))
251
-	) {
252
-		// on verifie la meme chose que dans auteurs_edit_config()
253
-		if (
254
-			! auth_autoriser_modifier_login($auth_methode)
255
-			or !autoriser('modifier', 'auteur', intval($id_auteur), null, ['login' => true])
256
-			// legacy : ne pas risquer d'autoriser la modif login si fonction d'autorisation pas mise a jour et ne teste que l'option email
257
-			or !autoriser('modifier', 'auteur', intval($id_auteur), null, ['email' => true])
258
-		) {
259
-			$erreurs['login'] = _T('info_non_modifiable');
260
-		}
261
-	}
262
-
263
-	if (empty($erreurs['login'])) {
264
-		if ($err = auth_verifier_login($auth_methode, _request('new_login'), $id_auteur)) {
265
-			$erreurs['login'] = $err;
266
-			$erreurs['message_erreur'] .= $err;
267
-		} else {
268
-			// pass trop court ou confirmation non identique
269
-			if ($p = _request('new_pass')) {
270
-				if ($p != _request('new_pass2')) {
271
-					$erreurs['new_pass'] = _T('info_passes_identiques');
272
-					$erreurs['message_erreur'] .= _T('info_passes_identiques');
273
-				} elseif ($err = auth_verifier_pass($auth_methode, _request('new_login'), $p, $id_auteur)) {
274
-					$erreurs['new_pass'] = $err;
275
-					$erreurs['message_erreur'] .= $err;
276
-				}
277
-			}
278
-		}
279
-	}
280
-
281
-	if (!$erreurs['message_erreur']) {
282
-		unset($erreurs['message_erreur']);
283
-	}
284
-
285
-	return $erreurs;
156
+    // auto-renseigner le nom si il n'existe pas, sans couper
157
+    titre_automatique('nom', ['email', 'login'], 255);
158
+
159
+    $oblis = ['nom'];
160
+    // si on veut renvoyer des identifiants il faut un email et un login
161
+    if (_request('reset_password')) {
162
+        $oblis[] = 'email';
163
+        $oblis[] = 'new_login';
164
+    }
165
+    // mais il reste obligatoire si on a rien trouve
166
+    $erreurs = formulaires_editer_objet_verifier('auteur', $id_auteur, $oblis);
167
+    if (isset($erreurs['new_login'])) {
168
+        $erreurs['login'] = $erreurs['new_login'];
169
+        unset($erreurs['new_login']);
170
+    }
171
+
172
+    $auth_methode = sql_getfetsel('source', 'spip_auteurs', 'id_auteur=' . intval($id_auteur));
173
+    $auth_methode = ($auth_methode ?: 'spip');
174
+    include_spip('inc/auth');
175
+
176
+    if (!nom_acceptable(_request('nom'))) {
177
+        $erreurs['nom'] = _T('info_nom_pas_conforme');
178
+    }
179
+
180
+    if ($email = _request('email')) {
181
+        include_spip('inc/filtres');
182
+        include_spip('inc/autoriser');
183
+        // un redacteur qui modifie son email n'a pas le droit de le vider si il y en avait un
184
+        if (
185
+            !autoriser('modifier', 'auteur', $id_auteur, null, ['email' => '?'])
186
+            and $GLOBALS['visiteur_session']['id_auteur'] == $id_auteur
187
+            and !strlen(trim($email))
188
+            and $email != ($email_ancien = sql_getfetsel('email', 'spip_auteurs', 'id_auteur=' . intval($id_auteur)))
189
+        ) {
190
+            $erreurs['email'] = (($id_auteur == $GLOBALS['visiteur_session']['id_auteur']) ? _T('form_email_non_valide') : _T('form_prop_indiquer_email'));
191
+        } else {
192
+            if (!email_valide($email)) {
193
+                $erreurs['email'] = (($id_auteur == $GLOBALS['visiteur_session']['id_auteur']) ? _T('form_email_non_valide') : _T('form_prop_indiquer_email'));
194
+            }
195
+        }
196
+        # Ne pas autoriser d'avoir deux auteurs avec le même email
197
+        # cette fonctionalité nécessite que la base soit clean à l'activation : pas de
198
+        # doublon sur la requête select email,count(*) from spip_auteurs group by email ;
199
+        if (defined('_INTERDIRE_AUTEUR_MEME_EMAIL')) {
200
+            #Nouvel auteur
201
+            if (intval($id_auteur) == 0) {
202
+                #Un auteur existe deja avec cette adresse ?
203
+                if (sql_countsel('spip_auteurs', 'email=' . sql_quote($email)) > 0) {
204
+                    $erreurs['email'] = _T('erreur_email_deja_existant');
205
+                }
206
+            } else {
207
+                #Un auteur existe deja avec cette adresse ? et n'est pas le user courant.
208
+                if (
209
+                    (sql_countsel(
210
+                        'spip_auteurs',
211
+                        'email=' . sql_quote($email)
212
+                    ) > 0) and ($id_auteur != ($id_auteur_ancien = sql_getfetsel(
213
+                        'id_auteur',
214
+                        'spip_auteurs',
215
+                        'email=' . sql_quote($email)
216
+                    )))
217
+                ) {
218
+                    $erreurs['email'] = _T('erreur_email_deja_existant');
219
+                }
220
+            }
221
+        }
222
+    }
223
+
224
+    // quand c'est un auteur existant on fait le reset password ici
225
+    if (!(is_countable($erreurs) ? count($erreurs) : 0) and _request('reset_password') and intval($id_auteur)) {
226
+        $erreurs = auteur_reset_password($id_auteur, $erreurs);
227
+        return $erreurs;
228
+    }
229
+
230
+    // corriger un cas si frequent : www.example.org sans le http:// qui precede
231
+    if ($url = _request('url_site') and !tester_url_absolue($url)) {
232
+        if (strpos($url, ':') === false and strncasecmp($url, 'www.', 4) === 0) {
233
+            $url = 'http://' . $url;
234
+            set_request('url_site', $url);
235
+        }
236
+    }
237
+    // traiter les liens implicites avant de tester l'url
238
+    include_spip('inc/lien');
239
+    if ($url = calculer_url(_request('url_site')) and !tester_url_absolue($url)) {
240
+        $erreurs['url_site'] = _T('info_url_site_pas_conforme');
241
+    }
242
+
243
+    $erreurs['message_erreur'] = '';
244
+    if (_request('login')) {
245
+        // on n'est jamais cense poster le name 'login'
246
+        $erreurs['login'] = _T('info_non_modifiable');
247
+    }
248
+    elseif (
249
+        ($login = _request('new_login')) and
250
+        $login !== sql_getfetsel('login', 'spip_auteurs', 'id_auteur=' . intval($id_auteur))
251
+    ) {
252
+        // on verifie la meme chose que dans auteurs_edit_config()
253
+        if (
254
+            ! auth_autoriser_modifier_login($auth_methode)
255
+            or !autoriser('modifier', 'auteur', intval($id_auteur), null, ['login' => true])
256
+            // legacy : ne pas risquer d'autoriser la modif login si fonction d'autorisation pas mise a jour et ne teste que l'option email
257
+            or !autoriser('modifier', 'auteur', intval($id_auteur), null, ['email' => true])
258
+        ) {
259
+            $erreurs['login'] = _T('info_non_modifiable');
260
+        }
261
+    }
262
+
263
+    if (empty($erreurs['login'])) {
264
+        if ($err = auth_verifier_login($auth_methode, _request('new_login'), $id_auteur)) {
265
+            $erreurs['login'] = $err;
266
+            $erreurs['message_erreur'] .= $err;
267
+        } else {
268
+            // pass trop court ou confirmation non identique
269
+            if ($p = _request('new_pass')) {
270
+                if ($p != _request('new_pass2')) {
271
+                    $erreurs['new_pass'] = _T('info_passes_identiques');
272
+                    $erreurs['message_erreur'] .= _T('info_passes_identiques');
273
+                } elseif ($err = auth_verifier_pass($auth_methode, _request('new_login'), $p, $id_auteur)) {
274
+                    $erreurs['new_pass'] = $err;
275
+                    $erreurs['message_erreur'] .= $err;
276
+                }
277
+            }
278
+        }
279
+    }
280
+
281
+    if (!$erreurs['message_erreur']) {
282
+        unset($erreurs['message_erreur']);
283
+    }
284
+
285
+    return $erreurs;
286 286
 }
287 287
 
288 288
 
@@ -319,149 +319,149 @@  discard block
 block discarded – undo
319 319
  *     Retour des traitements
320 320
  **/
321 321
 function formulaires_editer_auteur_traiter_dist(
322
-	$id_auteur = 'new',
323
-	$retour = '',
324
-	$associer_objet = '',
325
-	$config_fonc = 'auteurs_edit_config',
326
-	$row = [],
327
-	$hidden = ''
322
+    $id_auteur = 'new',
323
+    $retour = '',
324
+    $associer_objet = '',
325
+    $config_fonc = 'auteurs_edit_config',
326
+    $row = [],
327
+    $hidden = ''
328 328
 ) {
329
-	if (_request('saisie_webmestre') or _request('webmestre')) {
330
-		set_request('webmestre', _request('webmestre') ?: 'non');
331
-	}
332
-
333
-	// si il y a des modifs sensibles (statut, mot de passe), on refuse le traitement en ajax
334
-	// le formulaire ne peut être traité depuis une XMLHttpRequest
335
-	$prev = formulaires_editer_objet_charger('auteur', $id_auteur, 0, 0, $retour, $config_fonc, $row, $hidden);
336
-	if (
337
-		_request('new_pass') // nouveau mot de passe
338
-		or empty($prev['statut']) // creation auteur
339
-		or (_request('email') and $prev['email'] !== _request('email')) // modification email
340
-		or (_request('statut') === '0minirezo' and $prev['statut'] !== '0minirezo') // promotion 0minirezo
341
-		or (_request('statut') and intval(_request('statut')) < intval($prev['statut'])) // promotion de statut
342
-		or (_request('webmestre') and _request('webmestre') !== 'non' and $prev['webmestre'] !== 'oui') // promotion webmestre
343
-	) {
344
-		refuser_traiter_formulaire_ajax();
345
-		// si on arrive là encore en ajax c'est pas OK, on genere une erreur
346
-		if (_AJAX or !empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
347
-			return [
348
-				'message_erreur' => _T('erreur_technique_ajaxform')
349
-			];
350
-		}
351
-	}
352
-
353
-	$id_objet = null;
354
-	$retour = parametre_url($retour, 'email_confirm', '');
355
-
356
-	if ($restreintes = _request('restreintes')) {
357
-		foreach ($restreintes as $k => $v) {
358
-			if (strpos($v, 'rubrique|') === 0) {
359
-				$restreintes[$k] = substr($v, 9);
360
-			}
361
-		}
362
-		set_request('restreintes', $restreintes);
363
-	}
364
-
365
-	set_request(
366
-		'email',
367
-		email_valide(_request('email'))
368
-	); // eviter d'enregistrer les cas qui sont acceptés par email_valide dans le verifier :
369
-	// "[email protected]  " ou encore "Marie Toto <[email protected]>"
370
-
371
-	include_spip('inc/autoriser');
372
-	if (!autoriser('modifier', 'auteur', $id_auteur, null, ['email' => '?'])) {
373
-		$email_nouveau = _request('email');
374
-		set_request('email'); // vider la saisie car l'auteur n'a pas le droit de modifier cet email
375
-		// mais si c'est son propre profil on lui envoie un email à l'adresse qu'il a indique
376
-		// pour qu'il confirme qu'il possede bien cette adresse
377
-		// son clic sur l'url du message permettre de confirmer le changement
378
-		// et de revenir sur son profil
379
-		if (
380
-			$GLOBALS['visiteur_session']['id_auteur'] == $id_auteur
381
-			and $email_nouveau !=
382
-				($email_ancien = sql_getfetsel('email', 'spip_auteurs', 'id_auteur=' . intval($id_auteur)))
383
-		) {
384
-			$envoyer_mail = charger_fonction('envoyer_mail', 'inc');
385
-			$texte = _T(
386
-				'form_auteur_mail_confirmation',
387
-				[
388
-					'url' => generer_action_auteur(
389
-						'confirmer_email',
390
-						$email_nouveau,
391
-						parametre_url($retour, 'email_modif', 'ok')
392
-					)
393
-				]
394
-			);
395
-			$envoyer_mail($email_nouveau, _T('form_auteur_confirmation'), $texte);
396
-			set_request('email_confirm', $email_nouveau);
397
-			if ($email_ancien) {
398
-				$envoyer_mail(
399
-					$email_ancien,
400
-					_T('form_auteur_confirmation'),
401
-					_T('form_auteur_envoi_mail_confirmation', ['email' => $email_nouveau])
402
-				);
403
-			}
404
-			$retour = parametre_url($retour, 'email_confirm', $email_nouveau);
405
-		}
406
-	}
407
-
408
-	$res = formulaires_editer_objet_traiter('auteur', $id_auteur, 0, 0, $retour, $config_fonc, $row, $hidden);
409
-
410
-	if (_request('reset_password') and !intval($id_auteur) and intval($res['id_auteur'])) {
411
-		$erreurs = [];
412
-		$erreurs = auteur_reset_password($res['id_auteur'], $erreurs);
413
-		if (isset($erreurs['message_ok'])) {
414
-			if (!isset($res['message_ok'])) { $res['message_ok'] = '';
415
-			}
416
-			$res['message_ok'] = trim($res['message_ok'] . ' ' . $erreurs['message_ok']);
417
-		}
418
-		if (isset($erreurs['message_erreur']) and $erreurs['message_erreur']) {
419
-			if (!isset($res['message_erreur'])) { $res['message_erreur'] = '';
420
-			}
421
-			$res['message_erreur'] = trim($res['message_erreur'] . ' ' . $erreurs['message_erreur']);
422
-		}
423
-	}
424
-
425
-	// Un lien auteur a prendre en compte ?
426
-	if ($associer_objet and $id_auteur = $res['id_auteur']) {
427
-		$objet = '';
428
-		if (intval($associer_objet)) {
429
-			$objet = 'article';
430
-			$id_objet = intval($associer_objet);
431
-		} elseif (preg_match(',^\w+\|[0-9]+$,', $associer_objet)) {
432
-			[$objet, $id_objet] = explode('|', $associer_objet);
433
-		}
434
-		if ($objet and $id_objet and autoriser('modifier', $objet, $id_objet)) {
435
-			include_spip('action/editer_auteur');
436
-			auteur_associer($id_auteur, [$objet => $id_objet]);
437
-			if (isset($res['redirect'])) {
438
-				$res['redirect'] = parametre_url($res['redirect'], 'id_lien_ajoute', $id_auteur, '&');
439
-			}
440
-		}
441
-	}
442
-
443
-	return $res;
329
+    if (_request('saisie_webmestre') or _request('webmestre')) {
330
+        set_request('webmestre', _request('webmestre') ?: 'non');
331
+    }
332
+
333
+    // si il y a des modifs sensibles (statut, mot de passe), on refuse le traitement en ajax
334
+    // le formulaire ne peut être traité depuis une XMLHttpRequest
335
+    $prev = formulaires_editer_objet_charger('auteur', $id_auteur, 0, 0, $retour, $config_fonc, $row, $hidden);
336
+    if (
337
+        _request('new_pass') // nouveau mot de passe
338
+        or empty($prev['statut']) // creation auteur
339
+        or (_request('email') and $prev['email'] !== _request('email')) // modification email
340
+        or (_request('statut') === '0minirezo' and $prev['statut'] !== '0minirezo') // promotion 0minirezo
341
+        or (_request('statut') and intval(_request('statut')) < intval($prev['statut'])) // promotion de statut
342
+        or (_request('webmestre') and _request('webmestre') !== 'non' and $prev['webmestre'] !== 'oui') // promotion webmestre
343
+    ) {
344
+        refuser_traiter_formulaire_ajax();
345
+        // si on arrive là encore en ajax c'est pas OK, on genere une erreur
346
+        if (_AJAX or !empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
347
+            return [
348
+                'message_erreur' => _T('erreur_technique_ajaxform')
349
+            ];
350
+        }
351
+    }
352
+
353
+    $id_objet = null;
354
+    $retour = parametre_url($retour, 'email_confirm', '');
355
+
356
+    if ($restreintes = _request('restreintes')) {
357
+        foreach ($restreintes as $k => $v) {
358
+            if (strpos($v, 'rubrique|') === 0) {
359
+                $restreintes[$k] = substr($v, 9);
360
+            }
361
+        }
362
+        set_request('restreintes', $restreintes);
363
+    }
364
+
365
+    set_request(
366
+        'email',
367
+        email_valide(_request('email'))
368
+    ); // eviter d'enregistrer les cas qui sont acceptés par email_valide dans le verifier :
369
+    // "[email protected]  " ou encore "Marie Toto <[email protected]>"
370
+
371
+    include_spip('inc/autoriser');
372
+    if (!autoriser('modifier', 'auteur', $id_auteur, null, ['email' => '?'])) {
373
+        $email_nouveau = _request('email');
374
+        set_request('email'); // vider la saisie car l'auteur n'a pas le droit de modifier cet email
375
+        // mais si c'est son propre profil on lui envoie un email à l'adresse qu'il a indique
376
+        // pour qu'il confirme qu'il possede bien cette adresse
377
+        // son clic sur l'url du message permettre de confirmer le changement
378
+        // et de revenir sur son profil
379
+        if (
380
+            $GLOBALS['visiteur_session']['id_auteur'] == $id_auteur
381
+            and $email_nouveau !=
382
+                ($email_ancien = sql_getfetsel('email', 'spip_auteurs', 'id_auteur=' . intval($id_auteur)))
383
+        ) {
384
+            $envoyer_mail = charger_fonction('envoyer_mail', 'inc');
385
+            $texte = _T(
386
+                'form_auteur_mail_confirmation',
387
+                [
388
+                    'url' => generer_action_auteur(
389
+                        'confirmer_email',
390
+                        $email_nouveau,
391
+                        parametre_url($retour, 'email_modif', 'ok')
392
+                    )
393
+                ]
394
+            );
395
+            $envoyer_mail($email_nouveau, _T('form_auteur_confirmation'), $texte);
396
+            set_request('email_confirm', $email_nouveau);
397
+            if ($email_ancien) {
398
+                $envoyer_mail(
399
+                    $email_ancien,
400
+                    _T('form_auteur_confirmation'),
401
+                    _T('form_auteur_envoi_mail_confirmation', ['email' => $email_nouveau])
402
+                );
403
+            }
404
+            $retour = parametre_url($retour, 'email_confirm', $email_nouveau);
405
+        }
406
+    }
407
+
408
+    $res = formulaires_editer_objet_traiter('auteur', $id_auteur, 0, 0, $retour, $config_fonc, $row, $hidden);
409
+
410
+    if (_request('reset_password') and !intval($id_auteur) and intval($res['id_auteur'])) {
411
+        $erreurs = [];
412
+        $erreurs = auteur_reset_password($res['id_auteur'], $erreurs);
413
+        if (isset($erreurs['message_ok'])) {
414
+            if (!isset($res['message_ok'])) { $res['message_ok'] = '';
415
+            }
416
+            $res['message_ok'] = trim($res['message_ok'] . ' ' . $erreurs['message_ok']);
417
+        }
418
+        if (isset($erreurs['message_erreur']) and $erreurs['message_erreur']) {
419
+            if (!isset($res['message_erreur'])) { $res['message_erreur'] = '';
420
+            }
421
+            $res['message_erreur'] = trim($res['message_erreur'] . ' ' . $erreurs['message_erreur']);
422
+        }
423
+    }
424
+
425
+    // Un lien auteur a prendre en compte ?
426
+    if ($associer_objet and $id_auteur = $res['id_auteur']) {
427
+        $objet = '';
428
+        if (intval($associer_objet)) {
429
+            $objet = 'article';
430
+            $id_objet = intval($associer_objet);
431
+        } elseif (preg_match(',^\w+\|[0-9]+$,', $associer_objet)) {
432
+            [$objet, $id_objet] = explode('|', $associer_objet);
433
+        }
434
+        if ($objet and $id_objet and autoriser('modifier', $objet, $id_objet)) {
435
+            include_spip('action/editer_auteur');
436
+            auteur_associer($id_auteur, [$objet => $id_objet]);
437
+            if (isset($res['redirect'])) {
438
+                $res['redirect'] = parametre_url($res['redirect'], 'id_lien_ajoute', $id_auteur, '&');
439
+            }
440
+        }
441
+    }
442
+
443
+    return $res;
444 444
 }
445 445
 
446 446
 
447 447
 function auteur_reset_password($id_auteur, $erreurs = []) {
448
-	$auteur = sql_fetsel('*', 'spip_auteurs', 'id_auteur=' . intval($id_auteur));
449
-	$config = auteurs_edit_config($auteur);
450
-
451
-	if ($config['edit_pass']) {
452
-		if ($email = auteur_regenerer_identifiants($id_auteur)) {
453
-			$erreurs['message_ok'] = _T('message_nouveaux_identifiants_ok', ['email' => $email]);
454
-			$erreurs['message_erreur'] = '';
455
-		} elseif ($email === false) {
456
-			$erreurs['message_erreur'] = _T('message_nouveaux_identifiants_echec_envoi');
457
-		} else {
458
-			$erreurs['message_erreur'] = _T('message_nouveaux_identifiants_echec');
459
-		}
460
-	} else {
461
-		$erreurs['message_erreur'] = _T('message_nouveaux_identifiants_echec');
462
-	}
463
-
464
-	return $erreurs;
448
+    $auteur = sql_fetsel('*', 'spip_auteurs', 'id_auteur=' . intval($id_auteur));
449
+    $config = auteurs_edit_config($auteur);
450
+
451
+    if ($config['edit_pass']) {
452
+        if ($email = auteur_regenerer_identifiants($id_auteur)) {
453
+            $erreurs['message_ok'] = _T('message_nouveaux_identifiants_ok', ['email' => $email]);
454
+            $erreurs['message_erreur'] = '';
455
+        } elseif ($email === false) {
456
+            $erreurs['message_erreur'] = _T('message_nouveaux_identifiants_echec_envoi');
457
+        } else {
458
+            $erreurs['message_erreur'] = _T('message_nouveaux_identifiants_echec');
459
+        }
460
+    } else {
461
+        $erreurs['message_erreur'] = _T('message_nouveaux_identifiants_echec');
462
+    }
463
+
464
+    return $erreurs;
465 465
 }
466 466
 
467 467
 /**
@@ -472,53 +472,53 @@  discard block
 block discarded – undo
472 472
  * @return string
473 473
  */
474 474
 function auteur_regenerer_identifiants($id_auteur, $notifier = true, $contexte = []) {
475
-	if ($id_auteur) {
476
-		$set = [];
477
-		include_spip('inc/access');
478
-		$set['pass'] = creer_pass_aleatoire(max(_PASS_LONGUEUR_MINI, 16));
479
-
480
-		include_spip('action/editer_auteur');
481
-		auteur_modifier($id_auteur, $set);
482
-
483
-		$row = sql_fetsel('*', 'spip_auteurs', 'id_auteur=' . intval($id_auteur));
484
-		include_spip('inc/filtres');
485
-		if (
486
-			$notifier
487
-			and $row['email']
488
-			and email_valide($row['email'])
489
-			and trouver_fond($fond = 'modeles/mail_nouveaux_identifiants')
490
-		) {
491
-			// envoyer l'email avec login/pass
492
-			$c = [
493
-				'id_auteur' => $id_auteur,
494
-				'nom' => $row['nom'],
495
-				'mode' => $row['statut'],
496
-				'email' => $row['email'],
497
-				'pass' => $set['pass'],
498
-			];
499
-			// on merge avec les champs fournit en appel, qui sont passes au modele de notification donc
500
-			$contexte = array_merge($contexte, $c);
501
-			// si pas de langue explicitement demandee, prendre celle de l'auteur si on la connait, ou a defaut celle du site
502
-			// plutot que celle de l'admin qui vient de cliquer sur le bouton
503
-			if (!isset($contexte['lang']) or !$contexte['lang']) {
504
-				if (isset($row['lang']) and $row['lang']) {
505
-					$contexte['lang'] = $row['lang'];
506
-				}
507
-				else {
508
-					$contexte['lang'] = $GLOBALS['meta']['langue_site'];
509
-				}
510
-			}
511
-			lang_select($contexte['lang']);
512
-			$message = recuperer_fond($fond, $contexte);
513
-			include_spip('inc/notifications');
514
-			notifications_envoyer_mails($row['email'], $message);
515
-			lang_select();
516
-
517
-			return $row['email'];
518
-		}
519
-
520
-		return false;
521
-	}
522
-
523
-	return '';
475
+    if ($id_auteur) {
476
+        $set = [];
477
+        include_spip('inc/access');
478
+        $set['pass'] = creer_pass_aleatoire(max(_PASS_LONGUEUR_MINI, 16));
479
+
480
+        include_spip('action/editer_auteur');
481
+        auteur_modifier($id_auteur, $set);
482
+
483
+        $row = sql_fetsel('*', 'spip_auteurs', 'id_auteur=' . intval($id_auteur));
484
+        include_spip('inc/filtres');
485
+        if (
486
+            $notifier
487
+            and $row['email']
488
+            and email_valide($row['email'])
489
+            and trouver_fond($fond = 'modeles/mail_nouveaux_identifiants')
490
+        ) {
491
+            // envoyer l'email avec login/pass
492
+            $c = [
493
+                'id_auteur' => $id_auteur,
494
+                'nom' => $row['nom'],
495
+                'mode' => $row['statut'],
496
+                'email' => $row['email'],
497
+                'pass' => $set['pass'],
498
+            ];
499
+            // on merge avec les champs fournit en appel, qui sont passes au modele de notification donc
500
+            $contexte = array_merge($contexte, $c);
501
+            // si pas de langue explicitement demandee, prendre celle de l'auteur si on la connait, ou a defaut celle du site
502
+            // plutot que celle de l'admin qui vient de cliquer sur le bouton
503
+            if (!isset($contexte['lang']) or !$contexte['lang']) {
504
+                if (isset($row['lang']) and $row['lang']) {
505
+                    $contexte['lang'] = $row['lang'];
506
+                }
507
+                else {
508
+                    $contexte['lang'] = $GLOBALS['meta']['langue_site'];
509
+                }
510
+            }
511
+            lang_select($contexte['lang']);
512
+            $message = recuperer_fond($fond, $contexte);
513
+            include_spip('inc/notifications');
514
+            notifications_envoyer_mails($row['email'], $message);
515
+            lang_select();
516
+
517
+            return $row['email'];
518
+        }
519
+
520
+        return false;
521
+    }
522
+
523
+    return '';
524 524
 }
Please login to merge, or discard this patch.
ecrire/src/Chiffrer/SpipCles.php 1 patch
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -14,171 +14,171 @@
 block discarded – undo
14 14
 
15 15
 /** Gestion des clés d’authentification / chiffrement de SPIP */
16 16
 final class SpipCles {
17
-	private static array $instances = [];
18
-
19
-	private string $file = _DIR_ETC . 'cles.php';
20
-	private Cles $cles;
21
-
22
-	public static function instance(string $file = ''): self {
23
-		if (empty(self::$instances[$file])) {
24
-			self::$instances[$file] = new self($file);
25
-		}
26
-		return self::$instances[$file];
27
-	}
28
-
29
-	/**
30
-	 * Retourne le secret du site (shorthand)
31
-	 * @uses self::getSecretSite()
32
-	 */
33
-	public static function secret_du_site(): ?string {
34
-		return (self::instance())->getSecretSite();
35
-	}
36
-
37
-	private function __construct(string $file = '') {
38
-		if ($file) {
39
-			$this->file = $file;
40
-		}
41
-		$this->cles = new Cles($this->read());
42
-	}
43
-
44
-	/**
45
-	 * Renvoyer le secret du site
46
-	 *
47
-	 * Le secret du site doit rester aussi secret que possible, et est eternel
48
-	 * On ne doit pas l'exporter
49
-	 *
50
-	 * Le secret est partagé entre une clé disque et une clé bdd
51
-	 *
52
-	 * @return string
53
-	 */
54
-	public function getSecretSite(bool $autoInit = true): ?string {
55
-		$key = $this->getKey('secret_du_site', $autoInit);
56
-		$meta = $this->getMetaKey('secret_du_site', $autoInit);
57
-		// conserve la même longeur.
58
-		return $key ^ $meta;
59
-	}
60
-
61
-	/** Renvoyer le secret des authentifications */
62
-	public function getSecretAuth(bool $autoInit = false): ?string {
63
-		return $this->getKey('secret_des_auth', $autoInit);
64
-	}
65
-	public function save(): bool {
66
-		return ecrire_fichier_securise($this->file, $this->cles->toJson());
67
-	}
68
-
69
-	/**
70
-	 * Fournir une sauvegarde chiffree des cles (a l'aide d'une autre clé, comme le pass d'un auteur)
71
-	 *
72
-	 * @param string $withKey Clé de chiffrage de la sauvegarde
73
-	 * @return string Contenu de la sauvegarde chiffrée générée
74
-	 */
75
-	public function backup(
76
-		#[\SensitiveParameter]
77
-		string $withKey
78
-	): string {
79
-		if (count($this->cles)) {
80
-			return Chiffrement::chiffrer($this->cles->toJson(), $withKey);
81
-		}
82
-		return '';
83
-	}
84
-
85
-	/**
86
-	 * Restaurer les cles manquantes depuis une sauvegarde chiffree des cles
87
-	 * (si la sauvegarde est bien valide)
88
-	 *
89
-	 * @param string $backup Sauvegarde chiffrée (générée par backup())
90
-	 * @param int $id_auteur
91
-	 * @param string $pass
92
-	 * @return void
93
-	 */
94
-	public function restore(
95
-		string $backup,
96
-		#[\SensitiveParameter]
97
-		string $password_clair,
98
-		#[\SensitiveParameter]
99
-		string $password_hash,
100
-		int $id_auteur
101
-	): bool {
102
-		if (empty($backup)) {
103
-			return false;
104
-		}
105
-
106
-		$sauvegarde = Chiffrement::dechiffrer($backup, $password_clair);
107
-		$json = json_decode($sauvegarde, true);
108
-		if (!$json) {
109
-			return false;
110
-		}
111
-
112
-		// cela semble une sauvegarde valide
113
-		$cles_potentielles = array_map('base64_decode', $json);
114
-
115
-		// il faut faire une double verif sur secret_des_auth
116
-		// pour s'assurer qu'elle permet bien de decrypter le pass de l'auteur qui fournit la sauvegarde
117
-		// et par extension tous les passwords
118
-		if (!empty($cles_potentielles['secret_des_auth'])) {
119
-			if (!Password::verifier($password_clair, $password_hash, $cles_potentielles['secret_des_auth'])) {
120
-				spip_log("Restauration de la cle `secret_des_auth` par id_auteur $id_auteur erronnee, on ignore", 'chiffrer' . _LOG_INFO_IMPORTANTE);
121
-				unset($cles_potentielles['secret_des_auth']);
122
-			}
123
-		}
124
-
125
-		// on merge les cles pour recuperer les cles manquantes
126
-		$restauration = false;
127
-		foreach ($cles_potentielles as $name => $key) {
128
-			if (!$this->cles->has($name)) {
129
-				$this->cles->set($name, $key);
130
-				spip_log("Restauration de la cle $name par id_auteur $id_auteur", 'chiffrer' . _LOG_INFO_IMPORTANTE);
131
-				$restauration = true;
132
-			}
133
-		}
134
-		return $restauration;
135
-	}
136
-
137
-	private function getKey(string $name, bool $autoInit): ?string {
138
-		if ($this->cles->has($name)) {
139
-			return $this->cles->get($name);
140
-		}
141
-		if ($autoInit) {
142
-			$this->cles->generate($name);
143
-			// si l'ecriture de fichier a bien marche on peut utiliser la cle
144
-			if ($this->save()) {
145
-				return $this->cles->get($name);
146
-			}
147
-			// sinon loger et annule la cle generee car il ne faut pas l'utiliser
148
-			spip_log('Echec ecriture du fichier cle ' . $this->file . " ; impossible de generer une cle $name", 'chiffrer' . _LOG_ERREUR);
149
-			$this->cles->delete($name);
150
-		}
151
-		return null;
152
-	}
153
-
154
-	private function getMetaKey(string $name, bool $autoInit = true): ?string {
155
-		if (!isset($GLOBALS['meta'][$name])) {
156
-			include_spip('base/abstract_sql');
157
-			$GLOBALS['meta'][$name] = sql_getfetsel('valeur', 'spip_meta', 'nom = ' . sql_quote($name, '', 'string'));
158
-		}
159
-		$key = base64_decode($GLOBALS['meta'][$name] ?? '');
160
-		if (strlen($key) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
161
-			return $key;
162
-		}
163
-		if (!$autoInit) {
164
-			return null;
165
-		}
166
-		$key = Chiffrement::keygen();
167
-		ecrire_meta($name, base64_encode($key), 'non');
168
-		lire_metas(); // au cas ou ecrire_meta() ne fonctionne pas
169
-
170
-		return $key;
171
-	}
172
-
173
-	private function read(): array {
174
-		lire_fichier_securise($this->file, $json);
175
-		if (
176
-			$json
177
-			and $json = \json_decode($json, true)
178
-			and is_array($json)
179
-		) {
180
-			return array_map('base64_decode', $json);
181
-		}
182
-		return [];
183
-	}
17
+    private static array $instances = [];
18
+
19
+    private string $file = _DIR_ETC . 'cles.php';
20
+    private Cles $cles;
21
+
22
+    public static function instance(string $file = ''): self {
23
+        if (empty(self::$instances[$file])) {
24
+            self::$instances[$file] = new self($file);
25
+        }
26
+        return self::$instances[$file];
27
+    }
28
+
29
+    /**
30
+     * Retourne le secret du site (shorthand)
31
+     * @uses self::getSecretSite()
32
+     */
33
+    public static function secret_du_site(): ?string {
34
+        return (self::instance())->getSecretSite();
35
+    }
36
+
37
+    private function __construct(string $file = '') {
38
+        if ($file) {
39
+            $this->file = $file;
40
+        }
41
+        $this->cles = new Cles($this->read());
42
+    }
43
+
44
+    /**
45
+     * Renvoyer le secret du site
46
+     *
47
+     * Le secret du site doit rester aussi secret que possible, et est eternel
48
+     * On ne doit pas l'exporter
49
+     *
50
+     * Le secret est partagé entre une clé disque et une clé bdd
51
+     *
52
+     * @return string
53
+     */
54
+    public function getSecretSite(bool $autoInit = true): ?string {
55
+        $key = $this->getKey('secret_du_site', $autoInit);
56
+        $meta = $this->getMetaKey('secret_du_site', $autoInit);
57
+        // conserve la même longeur.
58
+        return $key ^ $meta;
59
+    }
60
+
61
+    /** Renvoyer le secret des authentifications */
62
+    public function getSecretAuth(bool $autoInit = false): ?string {
63
+        return $this->getKey('secret_des_auth', $autoInit);
64
+    }
65
+    public function save(): bool {
66
+        return ecrire_fichier_securise($this->file, $this->cles->toJson());
67
+    }
68
+
69
+    /**
70
+     * Fournir une sauvegarde chiffree des cles (a l'aide d'une autre clé, comme le pass d'un auteur)
71
+     *
72
+     * @param string $withKey Clé de chiffrage de la sauvegarde
73
+     * @return string Contenu de la sauvegarde chiffrée générée
74
+     */
75
+    public function backup(
76
+        #[\SensitiveParameter]
77
+        string $withKey
78
+    ): string {
79
+        if (count($this->cles)) {
80
+            return Chiffrement::chiffrer($this->cles->toJson(), $withKey);
81
+        }
82
+        return '';
83
+    }
84
+
85
+    /**
86
+     * Restaurer les cles manquantes depuis une sauvegarde chiffree des cles
87
+     * (si la sauvegarde est bien valide)
88
+     *
89
+     * @param string $backup Sauvegarde chiffrée (générée par backup())
90
+     * @param int $id_auteur
91
+     * @param string $pass
92
+     * @return void
93
+     */
94
+    public function restore(
95
+        string $backup,
96
+        #[\SensitiveParameter]
97
+        string $password_clair,
98
+        #[\SensitiveParameter]
99
+        string $password_hash,
100
+        int $id_auteur
101
+    ): bool {
102
+        if (empty($backup)) {
103
+            return false;
104
+        }
105
+
106
+        $sauvegarde = Chiffrement::dechiffrer($backup, $password_clair);
107
+        $json = json_decode($sauvegarde, true);
108
+        if (!$json) {
109
+            return false;
110
+        }
111
+
112
+        // cela semble une sauvegarde valide
113
+        $cles_potentielles = array_map('base64_decode', $json);
114
+
115
+        // il faut faire une double verif sur secret_des_auth
116
+        // pour s'assurer qu'elle permet bien de decrypter le pass de l'auteur qui fournit la sauvegarde
117
+        // et par extension tous les passwords
118
+        if (!empty($cles_potentielles['secret_des_auth'])) {
119
+            if (!Password::verifier($password_clair, $password_hash, $cles_potentielles['secret_des_auth'])) {
120
+                spip_log("Restauration de la cle `secret_des_auth` par id_auteur $id_auteur erronnee, on ignore", 'chiffrer' . _LOG_INFO_IMPORTANTE);
121
+                unset($cles_potentielles['secret_des_auth']);
122
+            }
123
+        }
124
+
125
+        // on merge les cles pour recuperer les cles manquantes
126
+        $restauration = false;
127
+        foreach ($cles_potentielles as $name => $key) {
128
+            if (!$this->cles->has($name)) {
129
+                $this->cles->set($name, $key);
130
+                spip_log("Restauration de la cle $name par id_auteur $id_auteur", 'chiffrer' . _LOG_INFO_IMPORTANTE);
131
+                $restauration = true;
132
+            }
133
+        }
134
+        return $restauration;
135
+    }
136
+
137
+    private function getKey(string $name, bool $autoInit): ?string {
138
+        if ($this->cles->has($name)) {
139
+            return $this->cles->get($name);
140
+        }
141
+        if ($autoInit) {
142
+            $this->cles->generate($name);
143
+            // si l'ecriture de fichier a bien marche on peut utiliser la cle
144
+            if ($this->save()) {
145
+                return $this->cles->get($name);
146
+            }
147
+            // sinon loger et annule la cle generee car il ne faut pas l'utiliser
148
+            spip_log('Echec ecriture du fichier cle ' . $this->file . " ; impossible de generer une cle $name", 'chiffrer' . _LOG_ERREUR);
149
+            $this->cles->delete($name);
150
+        }
151
+        return null;
152
+    }
153
+
154
+    private function getMetaKey(string $name, bool $autoInit = true): ?string {
155
+        if (!isset($GLOBALS['meta'][$name])) {
156
+            include_spip('base/abstract_sql');
157
+            $GLOBALS['meta'][$name] = sql_getfetsel('valeur', 'spip_meta', 'nom = ' . sql_quote($name, '', 'string'));
158
+        }
159
+        $key = base64_decode($GLOBALS['meta'][$name] ?? '');
160
+        if (strlen($key) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
161
+            return $key;
162
+        }
163
+        if (!$autoInit) {
164
+            return null;
165
+        }
166
+        $key = Chiffrement::keygen();
167
+        ecrire_meta($name, base64_encode($key), 'non');
168
+        lire_metas(); // au cas ou ecrire_meta() ne fonctionne pas
169
+
170
+        return $key;
171
+    }
172
+
173
+    private function read(): array {
174
+        lire_fichier_securise($this->file, $json);
175
+        if (
176
+            $json
177
+            and $json = \json_decode($json, true)
178
+            and is_array($json)
179
+        ) {
180
+            return array_map('base64_decode', $json);
181
+        }
182
+        return [];
183
+    }
184 184
 }
Please login to merge, or discard this patch.
ecrire/inc/modifier.php 1 patch
Indentation   +261 added lines, -261 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
  **/
18 18
 
19 19
 if (!defined('_ECRIRE_INC_VERSION')) {
20
-	return;
20
+    return;
21 21
 }
22 22
 
23 23
 /**
@@ -39,28 +39,28 @@  discard block
 block discarded – undo
39 39
  *     Tableau des champs et valeurs collectées
40 40
  */
41 41
 function collecter_requests($include_list, $exclude_list = [], $set = null, $tous = false) {
42
-	$c = $set;
43
-	if (!$c) {
44
-		$c = [];
45
-		foreach ($include_list as $champ) {
46
-			// on ne collecte que les champs reellement envoyes par defaut.
47
-			// le cas d'un envoi de valeur NULL peut du coup poser probleme.
48
-			$val = _request($champ);
49
-			if ($tous or $val !== null) {
50
-				$c[$champ] = $val;
51
-			}
52
-		}
53
-		// on ajoute toujours la lang en saisie possible
54
-		// meme si pas prevu au depart pour l'objet concerne
55
-		if ($l = _request('changer_lang')) {
56
-			$c['lang'] = $l;
57
-		}
58
-	}
59
-	foreach ($exclude_list as $champ) {
60
-		unset($c[$champ]);
61
-	}
62
-
63
-	return $c;
42
+    $c = $set;
43
+    if (!$c) {
44
+        $c = [];
45
+        foreach ($include_list as $champ) {
46
+            // on ne collecte que les champs reellement envoyes par defaut.
47
+            // le cas d'un envoi de valeur NULL peut du coup poser probleme.
48
+            $val = _request($champ);
49
+            if ($tous or $val !== null) {
50
+                $c[$champ] = $val;
51
+            }
52
+        }
53
+        // on ajoute toujours la lang en saisie possible
54
+        // meme si pas prevu au depart pour l'objet concerne
55
+        if ($l = _request('changer_lang')) {
56
+            $c['lang'] = $l;
57
+        }
58
+    }
59
+    foreach ($exclude_list as $champ) {
60
+        unset($c[$champ]);
61
+    }
62
+
63
+    return $c;
64 64
 }
65 65
 
66 66
 /**
@@ -97,242 +97,242 @@  discard block
 block discarded – undo
97 97
  *     - chaîne : Texte d'un message d'erreur
98 98
  */
99 99
 function objet_modifier_champs($objet, $id_objet, $options, $c = null, $serveur = '') {
100
-	if (!$id_objet = intval($id_objet)) {
101
-		spip_log('Erreur $id_objet non defini', 'warn');
102
-
103
-		return _T('erreur_technique_enregistrement_impossible');
104
-	}
105
-
106
-	include_spip('inc/filtres');
107
-
108
-	$table_objet = table_objet($objet, $serveur);
109
-	$spip_table_objet = table_objet_sql($objet, $serveur);
110
-	$id_table_objet = id_table_objet($objet, $serveur);
111
-	$trouver_table = charger_fonction('trouver_table', 'base');
112
-	$desc = $trouver_table($spip_table_objet, $serveur);
113
-
114
-	// Appels incomplets (sans $c)
115
-	if (!is_array($c)) {
116
-		spip_log('erreur appel objet_modifier_champs(' . $objet . '), manque $c');
117
-
118
-		return _T('erreur_technique_enregistrement_impossible');
119
-	}
120
-
121
-	// Securite : certaines variables ne sont jamais acceptees ici
122
-	// car elles ne relevent pas de autoriser(xxx, modifier) ;
123
-	// il faut passer par instituer_XX()
124
-	// TODO: faut-il passer ces variables interdites
125
-	// dans un fichier de description separe ?
126
-	unset($c['statut']);
127
-	unset($c['id_parent']);
128
-	unset($c['id_rubrique']);
129
-	unset($c['id_secteur']);
130
-
131
-	// Gerer les champs non vides
132
-	if (isset($options['nonvide']) and is_array($options['nonvide'])) {
133
-		foreach ($options['nonvide'] as $champ => $sinon) {
134
-			if (isset($c[$champ]) and $c[$champ] === '') {
135
-				$c[$champ] = $sinon;
136
-			}
137
-		}
138
-	}
139
-
140
-	// N'accepter que les champs qui existent dans la table
141
-	$champs = array_intersect_key($c, $desc['field']);
142
-	// et dont la valeur n'est pas null
143
-	$champs = array_filter($champs, static function ($var) {
144
-		return $var !== null;
145
-	});
146
-	// TODO: ici aussi on peut valider les contenus
147
-	// en fonction du type
148
-
149
-	// Nettoyer les valeurs
150
-	$champs = array_map('corriger_caracteres', $champs);
151
-
152
-	// On récupère l'état avant toute modification
153
-	$row = sql_fetsel('*', $spip_table_objet, $id_table_objet . '=' . $id_objet);
154
-
155
-	// Envoyer aux plugins
156
-	$champs = pipeline(
157
-		'pre_edition',
158
-		[
159
-			'args' => [
160
-				'table' => $spip_table_objet, // compatibilite
161
-				'table_objet' => $table_objet,
162
-				'spip_table_objet' => $spip_table_objet,
163
-				'desc' => $desc,
164
-				'type' => $objet,
165
-				'id_objet' => $id_objet,
166
-				'data' => $options['data'] ?? null,
167
-				'champs' => $options['champs'] ?? [], // [doc] c'est quoi ?
168
-				'champs_anciens' => $row, // état du contenu avant modif
169
-				'serveur' => $serveur,
170
-				'action' => $options['action'] ?? 'modifier'
171
-			],
172
-			'data' => $champs
173
-		]
174
-	);
175
-
176
-	if (!$champs) {
177
-		return false;
178
-	}
179
-
180
-
181
-	// marquer le fait que l'objet est travaille par toto a telle date
182
-	include_spip('inc/config');
183
-	if (lire_config('articles_modif', 'non') !== 'non') {
184
-		include_spip('inc/drapeau_edition');
185
-		signale_edition($id_objet, $GLOBALS['visiteur_session'], $objet);
186
-	}
187
-
188
-	// Verifier si les mises a jour sont pertinentes, datees, en conflit etc
189
-	include_spip('inc/editer');
190
-	if (!isset($options['data']) or is_null($options['data'])) {
191
-		$options['data'] = &$_POST;
192
-	}
193
-	$conflits = controler_md5($champs, $options['data'], $objet, $id_objet, $serveur);
194
-	// cas hypothetique : normalement inc/editer verifie en amont le conflit edition
195
-	// et gere l'interface
196
-	// ici on ne renvoie donc qu'un messsage d'erreur, au cas ou on y arrive quand meme
197
-	if ($conflits) {
198
-		return _T('titre_conflit_edition');
199
-	}
200
-
201
-	if ($champs) {
202
-		// cas particulier de la langue : passer par instituer_langue_objet
203
-		if (isset($champs['lang'])) {
204
-			if ($changer_lang = $champs['lang']) {
205
-				$id_rubrique = 0;
206
-				if (isset($desc['field']['id_rubrique'])) {
207
-					$parent = ($objet == 'rubrique') ? 'id_parent' : 'id_rubrique';
208
-					$id_rubrique = sql_getfetsel($parent, $spip_table_objet, "$id_table_objet=" . intval($id_objet));
209
-				}
210
-				$instituer_langue_objet = charger_fonction('instituer_langue_objet', 'action');
211
-				$champs['lang'] = $instituer_langue_objet($objet, $id_objet, $id_rubrique, $changer_lang, $serveur);
212
-			}
213
-			// on laisse 'lang' dans $champs,
214
-			// ca permet de passer dans le pipeline post_edition et de journaliser
215
-			// et ca ne gene pas qu'on refasse un sql_updateq dessus apres l'avoir
216
-			// deja pris en compte
217
-		}
218
-
219
-		// la modif peut avoir lieu
220
-
221
-		// faut-il ajouter date_modif ?
222
-		if (
223
-			!empty($options['date_modif'])
224
-			and !isset($champs[$options['date_modif']])
225
-		) {
226
-			$champs[$options['date_modif']] = date('Y-m-d H:i:s');
227
-		}
228
-
229
-		// allez on commit la modif
230
-		sql_updateq($spip_table_objet, $champs, "$id_table_objet=" . intval($id_objet), [], $serveur);
231
-
232
-		// on verifie si elle est bien passee
233
-		$moof = sql_fetsel(
234
-			array_keys($champs),
235
-			$spip_table_objet,
236
-			"$id_table_objet=" . intval($id_objet),
237
-			[],
238
-			[],
239
-			'',
240
-			[],
241
-			$serveur
242
-		);
243
-		// si difference entre les champs, reperer les champs mal enregistres
244
-		if ($moof != $champs) {
245
-			$liste = [];
246
-			foreach ($moof as $k => $v) {
247
-				if (
248
-					$v !== $champs[$k]
249
-					// ne pas alerter si le champ est numerique est que les valeurs sont equivalentes
250
-					and (!is_numeric($v) or intval($v) !== intval($champs[$k]))
251
-					// ne pas alerter si le champ est date, qu'on a envoye une valeur vide et qu'on recupere une date nulle
252
-					and (strlen($champs[$k]) or !in_array($v, ['0000-00-00 00:00:00', '0000-00-00']))
253
-				) {
254
-					$liste[] = $k;
255
-					$conflits[$k]['post'] = $champs[$k];
256
-					$conflits[$k]['save'] = $v;
257
-
258
-					// cas specifique MySQL+emoji : si l'un est la
259
-					// conversion utf8_noplanes de l'autre alors c'est OK
260
-					if (defined('_MYSQL_NOPLANES') && _MYSQL_NOPLANES) {
261
-						include_spip('inc/charsets');
262
-						if ($v == utf8_noplanes($champs[$k])) {
263
-							array_pop($liste);
264
-						}
265
-					}
266
-				}
267
-			}
268
-			// si un champ n'a pas ete correctement enregistre, loger et retourner une erreur
269
-			// c'est un cas exceptionnel
270
-			if (count($liste)) {
271
-				spip_log(
272
-					"Erreur enregistrement en base $objet/$id_objet champs :" . var_export($conflits, true),
273
-					'modifier.' . _LOG_CRITIQUE
274
-				);
275
-
276
-				return _T(
277
-					'erreur_technique_enregistrement_champs',
278
-					['champs' => "<i>'" . implode("'</i>,<i>'", $liste) . "'</i>"]
279
-				);
280
-			}
281
-		}
282
-
283
-		// Invalider les caches
284
-		if (isset($options['invalideur']) and $options['invalideur']) {
285
-			include_spip('inc/invalideur');
286
-			if (is_array($options['invalideur'])) {
287
-				array_map('suivre_invalideur', $options['invalideur']);
288
-			} else {
289
-				suivre_invalideur($options['invalideur']);
290
-			}
291
-		}
292
-
293
-		// Notifications, gestion des revisions...
294
-		// en standard, appelle |nouvelle_revision ci-dessous
295
-		pipeline(
296
-			'post_edition',
297
-			[
298
-				'args' => [
299
-					'table' => $spip_table_objet,
300
-					'table_objet' => $table_objet,
301
-					'spip_table_objet' => $spip_table_objet,
302
-					'desc' => $desc,
303
-					'type' => $objet,
304
-					'id_objet' => $id_objet,
305
-					'champs' => $options['champs'] ?? [], // [doc] kesako ?
306
-					'champs_anciens' => $row, // état du contenu avant modif
307
-					'serveur' => $serveur,
308
-					'action' => $options['action'] ?? 'modifier'
309
-				],
310
-				'data' => $champs
311
-			]
312
-		);
313
-	}
314
-
315
-	// journaliser l'affaire
316
-	// message a affiner :-)
317
-	include_spip('inc/filtres_mini');
318
-	$qui = '';
319
-	if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
320
-		$qui .= ' #id_auteur:' . $GLOBALS['visiteur_session']['id_auteur'] . '#';
321
-	}
322
-	if (!empty($GLOBALS['visiteur_session']['nom'])) {
323
-		$qui .= ' #nom:' . $GLOBALS['visiteur_session']['nom'] . '#';
324
-	}
325
-	if ($qui == '') {
326
-		$qui = '#ip:' . $GLOBALS['ip'] . '#';
327
-	}
328
-	journal(_L($qui . ' a édité ' . $objet . ' ' . $id_objet . ' (' . join(
329
-		'+',
330
-		array_diff(array_keys($champs), ['date_modif'])
331
-	) . ')'), [
332
-		'faire' => 'modifier',
333
-		'quoi' => $objet,
334
-		'id' => $id_objet
335
-	]);
336
-
337
-	return '';
100
+    if (!$id_objet = intval($id_objet)) {
101
+        spip_log('Erreur $id_objet non defini', 'warn');
102
+
103
+        return _T('erreur_technique_enregistrement_impossible');
104
+    }
105
+
106
+    include_spip('inc/filtres');
107
+
108
+    $table_objet = table_objet($objet, $serveur);
109
+    $spip_table_objet = table_objet_sql($objet, $serveur);
110
+    $id_table_objet = id_table_objet($objet, $serveur);
111
+    $trouver_table = charger_fonction('trouver_table', 'base');
112
+    $desc = $trouver_table($spip_table_objet, $serveur);
113
+
114
+    // Appels incomplets (sans $c)
115
+    if (!is_array($c)) {
116
+        spip_log('erreur appel objet_modifier_champs(' . $objet . '), manque $c');
117
+
118
+        return _T('erreur_technique_enregistrement_impossible');
119
+    }
120
+
121
+    // Securite : certaines variables ne sont jamais acceptees ici
122
+    // car elles ne relevent pas de autoriser(xxx, modifier) ;
123
+    // il faut passer par instituer_XX()
124
+    // TODO: faut-il passer ces variables interdites
125
+    // dans un fichier de description separe ?
126
+    unset($c['statut']);
127
+    unset($c['id_parent']);
128
+    unset($c['id_rubrique']);
129
+    unset($c['id_secteur']);
130
+
131
+    // Gerer les champs non vides
132
+    if (isset($options['nonvide']) and is_array($options['nonvide'])) {
133
+        foreach ($options['nonvide'] as $champ => $sinon) {
134
+            if (isset($c[$champ]) and $c[$champ] === '') {
135
+                $c[$champ] = $sinon;
136
+            }
137
+        }
138
+    }
139
+
140
+    // N'accepter que les champs qui existent dans la table
141
+    $champs = array_intersect_key($c, $desc['field']);
142
+    // et dont la valeur n'est pas null
143
+    $champs = array_filter($champs, static function ($var) {
144
+        return $var !== null;
145
+    });
146
+    // TODO: ici aussi on peut valider les contenus
147
+    // en fonction du type
148
+
149
+    // Nettoyer les valeurs
150
+    $champs = array_map('corriger_caracteres', $champs);
151
+
152
+    // On récupère l'état avant toute modification
153
+    $row = sql_fetsel('*', $spip_table_objet, $id_table_objet . '=' . $id_objet);
154
+
155
+    // Envoyer aux plugins
156
+    $champs = pipeline(
157
+        'pre_edition',
158
+        [
159
+            'args' => [
160
+                'table' => $spip_table_objet, // compatibilite
161
+                'table_objet' => $table_objet,
162
+                'spip_table_objet' => $spip_table_objet,
163
+                'desc' => $desc,
164
+                'type' => $objet,
165
+                'id_objet' => $id_objet,
166
+                'data' => $options['data'] ?? null,
167
+                'champs' => $options['champs'] ?? [], // [doc] c'est quoi ?
168
+                'champs_anciens' => $row, // état du contenu avant modif
169
+                'serveur' => $serveur,
170
+                'action' => $options['action'] ?? 'modifier'
171
+            ],
172
+            'data' => $champs
173
+        ]
174
+    );
175
+
176
+    if (!$champs) {
177
+        return false;
178
+    }
179
+
180
+
181
+    // marquer le fait que l'objet est travaille par toto a telle date
182
+    include_spip('inc/config');
183
+    if (lire_config('articles_modif', 'non') !== 'non') {
184
+        include_spip('inc/drapeau_edition');
185
+        signale_edition($id_objet, $GLOBALS['visiteur_session'], $objet);
186
+    }
187
+
188
+    // Verifier si les mises a jour sont pertinentes, datees, en conflit etc
189
+    include_spip('inc/editer');
190
+    if (!isset($options['data']) or is_null($options['data'])) {
191
+        $options['data'] = &$_POST;
192
+    }
193
+    $conflits = controler_md5($champs, $options['data'], $objet, $id_objet, $serveur);
194
+    // cas hypothetique : normalement inc/editer verifie en amont le conflit edition
195
+    // et gere l'interface
196
+    // ici on ne renvoie donc qu'un messsage d'erreur, au cas ou on y arrive quand meme
197
+    if ($conflits) {
198
+        return _T('titre_conflit_edition');
199
+    }
200
+
201
+    if ($champs) {
202
+        // cas particulier de la langue : passer par instituer_langue_objet
203
+        if (isset($champs['lang'])) {
204
+            if ($changer_lang = $champs['lang']) {
205
+                $id_rubrique = 0;
206
+                if (isset($desc['field']['id_rubrique'])) {
207
+                    $parent = ($objet == 'rubrique') ? 'id_parent' : 'id_rubrique';
208
+                    $id_rubrique = sql_getfetsel($parent, $spip_table_objet, "$id_table_objet=" . intval($id_objet));
209
+                }
210
+                $instituer_langue_objet = charger_fonction('instituer_langue_objet', 'action');
211
+                $champs['lang'] = $instituer_langue_objet($objet, $id_objet, $id_rubrique, $changer_lang, $serveur);
212
+            }
213
+            // on laisse 'lang' dans $champs,
214
+            // ca permet de passer dans le pipeline post_edition et de journaliser
215
+            // et ca ne gene pas qu'on refasse un sql_updateq dessus apres l'avoir
216
+            // deja pris en compte
217
+        }
218
+
219
+        // la modif peut avoir lieu
220
+
221
+        // faut-il ajouter date_modif ?
222
+        if (
223
+            !empty($options['date_modif'])
224
+            and !isset($champs[$options['date_modif']])
225
+        ) {
226
+            $champs[$options['date_modif']] = date('Y-m-d H:i:s');
227
+        }
228
+
229
+        // allez on commit la modif
230
+        sql_updateq($spip_table_objet, $champs, "$id_table_objet=" . intval($id_objet), [], $serveur);
231
+
232
+        // on verifie si elle est bien passee
233
+        $moof = sql_fetsel(
234
+            array_keys($champs),
235
+            $spip_table_objet,
236
+            "$id_table_objet=" . intval($id_objet),
237
+            [],
238
+            [],
239
+            '',
240
+            [],
241
+            $serveur
242
+        );
243
+        // si difference entre les champs, reperer les champs mal enregistres
244
+        if ($moof != $champs) {
245
+            $liste = [];
246
+            foreach ($moof as $k => $v) {
247
+                if (
248
+                    $v !== $champs[$k]
249
+                    // ne pas alerter si le champ est numerique est que les valeurs sont equivalentes
250
+                    and (!is_numeric($v) or intval($v) !== intval($champs[$k]))
251
+                    // ne pas alerter si le champ est date, qu'on a envoye une valeur vide et qu'on recupere une date nulle
252
+                    and (strlen($champs[$k]) or !in_array($v, ['0000-00-00 00:00:00', '0000-00-00']))
253
+                ) {
254
+                    $liste[] = $k;
255
+                    $conflits[$k]['post'] = $champs[$k];
256
+                    $conflits[$k]['save'] = $v;
257
+
258
+                    // cas specifique MySQL+emoji : si l'un est la
259
+                    // conversion utf8_noplanes de l'autre alors c'est OK
260
+                    if (defined('_MYSQL_NOPLANES') && _MYSQL_NOPLANES) {
261
+                        include_spip('inc/charsets');
262
+                        if ($v == utf8_noplanes($champs[$k])) {
263
+                            array_pop($liste);
264
+                        }
265
+                    }
266
+                }
267
+            }
268
+            // si un champ n'a pas ete correctement enregistre, loger et retourner une erreur
269
+            // c'est un cas exceptionnel
270
+            if (count($liste)) {
271
+                spip_log(
272
+                    "Erreur enregistrement en base $objet/$id_objet champs :" . var_export($conflits, true),
273
+                    'modifier.' . _LOG_CRITIQUE
274
+                );
275
+
276
+                return _T(
277
+                    'erreur_technique_enregistrement_champs',
278
+                    ['champs' => "<i>'" . implode("'</i>,<i>'", $liste) . "'</i>"]
279
+                );
280
+            }
281
+        }
282
+
283
+        // Invalider les caches
284
+        if (isset($options['invalideur']) and $options['invalideur']) {
285
+            include_spip('inc/invalideur');
286
+            if (is_array($options['invalideur'])) {
287
+                array_map('suivre_invalideur', $options['invalideur']);
288
+            } else {
289
+                suivre_invalideur($options['invalideur']);
290
+            }
291
+        }
292
+
293
+        // Notifications, gestion des revisions...
294
+        // en standard, appelle |nouvelle_revision ci-dessous
295
+        pipeline(
296
+            'post_edition',
297
+            [
298
+                'args' => [
299
+                    'table' => $spip_table_objet,
300
+                    'table_objet' => $table_objet,
301
+                    'spip_table_objet' => $spip_table_objet,
302
+                    'desc' => $desc,
303
+                    'type' => $objet,
304
+                    'id_objet' => $id_objet,
305
+                    'champs' => $options['champs'] ?? [], // [doc] kesako ?
306
+                    'champs_anciens' => $row, // état du contenu avant modif
307
+                    'serveur' => $serveur,
308
+                    'action' => $options['action'] ?? 'modifier'
309
+                ],
310
+                'data' => $champs
311
+            ]
312
+        );
313
+    }
314
+
315
+    // journaliser l'affaire
316
+    // message a affiner :-)
317
+    include_spip('inc/filtres_mini');
318
+    $qui = '';
319
+    if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
320
+        $qui .= ' #id_auteur:' . $GLOBALS['visiteur_session']['id_auteur'] . '#';
321
+    }
322
+    if (!empty($GLOBALS['visiteur_session']['nom'])) {
323
+        $qui .= ' #nom:' . $GLOBALS['visiteur_session']['nom'] . '#';
324
+    }
325
+    if ($qui == '') {
326
+        $qui = '#ip:' . $GLOBALS['ip'] . '#';
327
+    }
328
+    journal(_L($qui . ' a édité ' . $objet . ' ' . $id_objet . ' (' . join(
329
+        '+',
330
+        array_diff(array_keys($champs), ['date_modif'])
331
+    ) . ')'), [
332
+        'faire' => 'modifier',
333
+        'quoi' => $objet,
334
+        'id' => $id_objet
335
+    ]);
336
+
337
+    return '';
338 338
 }
Please login to merge, or discard this patch.
ecrire/inc/filtres_images_lib_mini.php 1 patch
Indentation   +1323 added lines, -1323 removed lines patch added patch discarded remove patch
@@ -18,7 +18,7 @@  discard block
 block discarded – undo
18 18
  */
19 19
 
20 20
 if (!defined('_ECRIRE_INC_VERSION')) {
21
-	return;
21
+    return;
22 22
 }
23 23
 include_spip('inc/filtres'); // par precaution
24 24
 include_spip('inc/filtres_images_mini'); // par precaution
@@ -38,21 +38,21 @@  discard block
 block discarded – undo
38 38
  *     Le code de la couleur en hexadécimal.
39 39
  */
40 40
 function _couleur_dec_to_hex($red, $green, $blue) {
41
-	$red = dechex($red);
42
-	$green = dechex($green);
43
-	$blue = dechex($blue);
44
-
45
-	if (strlen($red) == 1) {
46
-		$red = '0' . $red;
47
-	}
48
-	if (strlen($green) == 1) {
49
-		$green = '0' . $green;
50
-	}
51
-	if (strlen($blue) == 1) {
52
-		$blue = '0' . $blue;
53
-	}
54
-
55
-	return "$red$green$blue";
41
+    $red = dechex($red);
42
+    $green = dechex($green);
43
+    $blue = dechex($blue);
44
+
45
+    if (strlen($red) == 1) {
46
+        $red = '0' . $red;
47
+    }
48
+    if (strlen($green) == 1) {
49
+        $green = '0' . $green;
50
+    }
51
+    if (strlen($blue) == 1) {
52
+        $blue = '0' . $blue;
53
+    }
54
+
55
+    return "$red$green$blue";
56 56
 }
57 57
 
58 58
 /**
@@ -64,17 +64,17 @@  discard block
 block discarded – undo
64 64
  *     Un tableau des 3 éléments : rouge, vert, bleu.
65 65
  */
66 66
 function _couleur_hex_to_dec($couleur) {
67
-	$couleur = couleur_html_to_hex($couleur);
68
-	$couleur = ltrim($couleur, '#');
69
-	if (strlen($couleur) === 3) {
70
-		$couleur = $couleur[0] . $couleur[0] . $couleur[1] . $couleur[1] . $couleur[2] . $couleur[2];
71
-	}
72
-	$retour = [];
73
-	$retour['red'] = hexdec(substr($couleur, 0, 2));
74
-	$retour['green'] = hexdec(substr($couleur, 2, 2));
75
-	$retour['blue'] = hexdec(substr($couleur, 4, 2));
76
-
77
-	return $retour;
67
+    $couleur = couleur_html_to_hex($couleur);
68
+    $couleur = ltrim($couleur, '#');
69
+    if (strlen($couleur) === 3) {
70
+        $couleur = $couleur[0] . $couleur[0] . $couleur[1] . $couleur[1] . $couleur[2] . $couleur[2];
71
+    }
72
+    $retour = [];
73
+    $retour['red'] = hexdec(substr($couleur, 0, 2));
74
+    $retour['green'] = hexdec(substr($couleur, 2, 2));
75
+    $retour['blue'] = hexdec(substr($couleur, 4, 2));
76
+
77
+    return $retour;
78 78
 }
79 79
 
80 80
 
@@ -91,8 +91,8 @@  discard block
 block discarded – undo
91 91
  *     Le code de la couleur en hexadécimal.
92 92
  */
93 93
 function _couleur_hsl_to_hex($hue, $saturation, $lightness) {
94
-	$rgb = _couleur_hsl_to_rgb($hue, $saturation, $lightness);
95
-	return _couleur_dec_to_hex($rgb['r'], $rgb['g'], $rgb['b']);
94
+    $rgb = _couleur_hsl_to_rgb($hue, $saturation, $lightness);
95
+    return _couleur_dec_to_hex($rgb['r'], $rgb['g'], $rgb['b']);
96 96
 }
97 97
 
98 98
 /**
@@ -104,8 +104,8 @@  discard block
 block discarded – undo
104 104
  *     Un tableau des 3 éléments : teinte, saturation, luminosité.
105 105
  */
106 106
 function _couleur_hex_to_hsl($couleur) {
107
-	$rgb = _couleur_hex_to_dec($couleur);
108
-	return _couleur_rgb_to_hsl($rgb['red'], $rgb['green'], $rgb['blue']);
107
+    $rgb = _couleur_hex_to_dec($couleur);
108
+    return _couleur_rgb_to_hsl($rgb['red'], $rgb['green'], $rgb['blue']);
109 109
 }
110 110
 
111 111
 /**
@@ -120,59 +120,59 @@  discard block
 block discarded – undo
120 120
  * @return array
121 121
  */
122 122
 function _couleur_rgb_to_hsl($R, $G, $B) {
123
-	$H = null;
124
-	$var_R = ($R / 255); // Where RGB values = 0 ÷ 255
125
-	$var_G = ($G / 255);
126
-	$var_B = ($B / 255);
127
-
128
-	$var_Min = min($var_R, $var_G, $var_B);   //Min. value of RGB
129
-	$var_Max = max($var_R, $var_G, $var_B);   //Max. value of RGB
130
-	$del_Max = $var_Max - $var_Min;           //Delta RGB value
131
-
132
-	$L = ($var_Max + $var_Min) / 2;
133
-
134
-	if ($del_Max == 0) {
135
-		//This is a gray, no chroma...
136
-		$H = 0; //HSL results = 0 ÷ 1
137
-		$S = 0;
138
-	} else {
139
-		// Chromatic data...
140
-		if ($L < 0.5) {
141
-			$S = $del_Max / ($var_Max + $var_Min);
142
-		} else {
143
-			$S = $del_Max / (2 - $var_Max - $var_Min);
144
-		}
145
-
146
-		$del_R = ((($var_Max - $var_R) / 6) + ($del_Max / 2)) / $del_Max;
147
-		$del_G = ((($var_Max - $var_G) / 6) + ($del_Max / 2)) / $del_Max;
148
-		$del_B = ((($var_Max - $var_B) / 6) + ($del_Max / 2)) / $del_Max;
149
-
150
-		if ($var_R == $var_Max) {
151
-			$H = $del_B - $del_G;
152
-		} else {
153
-			if ($var_G == $var_Max) {
154
-				$H = (1 / 3) + $del_R - $del_B;
155
-			} else {
156
-				if ($var_B == $var_Max) {
157
-					$H = (2 / 3) + $del_G - $del_R;
158
-				}
159
-			}
160
-		}
161
-
162
-		if ($H < 0) {
163
-			$H += 1;
164
-		}
165
-		if ($H > 1) {
166
-			$H -= 1;
167
-		}
168
-	}
169
-
170
-	$ret = [];
171
-	$ret['h'] = $H;
172
-	$ret['s'] = $S;
173
-	$ret['l'] = $L;
174
-
175
-	return $ret;
123
+    $H = null;
124
+    $var_R = ($R / 255); // Where RGB values = 0 ÷ 255
125
+    $var_G = ($G / 255);
126
+    $var_B = ($B / 255);
127
+
128
+    $var_Min = min($var_R, $var_G, $var_B);   //Min. value of RGB
129
+    $var_Max = max($var_R, $var_G, $var_B);   //Max. value of RGB
130
+    $del_Max = $var_Max - $var_Min;           //Delta RGB value
131
+
132
+    $L = ($var_Max + $var_Min) / 2;
133
+
134
+    if ($del_Max == 0) {
135
+        //This is a gray, no chroma...
136
+        $H = 0; //HSL results = 0 ÷ 1
137
+        $S = 0;
138
+    } else {
139
+        // Chromatic data...
140
+        if ($L < 0.5) {
141
+            $S = $del_Max / ($var_Max + $var_Min);
142
+        } else {
143
+            $S = $del_Max / (2 - $var_Max - $var_Min);
144
+        }
145
+
146
+        $del_R = ((($var_Max - $var_R) / 6) + ($del_Max / 2)) / $del_Max;
147
+        $del_G = ((($var_Max - $var_G) / 6) + ($del_Max / 2)) / $del_Max;
148
+        $del_B = ((($var_Max - $var_B) / 6) + ($del_Max / 2)) / $del_Max;
149
+
150
+        if ($var_R == $var_Max) {
151
+            $H = $del_B - $del_G;
152
+        } else {
153
+            if ($var_G == $var_Max) {
154
+                $H = (1 / 3) + $del_R - $del_B;
155
+            } else {
156
+                if ($var_B == $var_Max) {
157
+                    $H = (2 / 3) + $del_G - $del_R;
158
+                }
159
+            }
160
+        }
161
+
162
+        if ($H < 0) {
163
+            $H += 1;
164
+        }
165
+        if ($H > 1) {
166
+            $H -= 1;
167
+        }
168
+    }
169
+
170
+    $ret = [];
171
+    $ret['h'] = $H;
172
+    $ret['s'] = $S;
173
+    $ret['l'] = $L;
174
+
175
+    return $ret;
176 176
 }
177 177
 
178 178
 
@@ -188,52 +188,52 @@  discard block
 block discarded – undo
188 188
  * @return array
189 189
  */
190 190
 function _couleur_hsl_to_rgb($H, $S, $L) {
191
-	// helper
192
-	$hue_2_rgb = function ($v1, $v2, $vH) {
193
-		if ($vH < 0) {
194
-			$vH += 1;
195
-		}
196
-		if ($vH > 1) {
197
-			$vH -= 1;
198
-		}
199
-		if ((6 * $vH) < 1) {
200
-			return ($v1 + ($v2 - $v1) * 6 * $vH);
201
-		}
202
-		if ((2 * $vH) < 1) {
203
-			return ($v2);
204
-		}
205
-		if ((3 * $vH) < 2) {
206
-			return ($v1 + ($v2 - $v1) * ((2 / 3) - $vH) * 6);
207
-		}
208
-
209
-		return ($v1);
210
-	};
211
-
212
-	if ($S == 0) {
213
-		// HSV values = 0 -> 1
214
-		$R = $L * 255;
215
-		$G = $L * 255;
216
-		$B = $L * 255;
217
-	} else {
218
-		if ($L < 0.5) {
219
-			$var_2 = $L * (1 + $S);
220
-		} else {
221
-			$var_2 = ($L + $S) - ($S * $L);
222
-		}
223
-
224
-		$var_1 = 2 * $L - $var_2;
225
-
226
-		$R = 255 * $hue_2_rgb($var_1, $var_2, $H + (1 / 3));
227
-		$G = 255 * $hue_2_rgb($var_1, $var_2, $H);
228
-		$B = 255 * $hue_2_rgb($var_1, $var_2, $H - (1 / 3));
229
-	}
230
-
231
-	$ret = [];
232
-	$ret['r'] = floor($R);
233
-	$ret['g'] = floor($G);
234
-	$ret['b'] = floor($B);
235
-
236
-	return $ret;
191
+    // helper
192
+    $hue_2_rgb = function ($v1, $v2, $vH) {
193
+        if ($vH < 0) {
194
+            $vH += 1;
195
+        }
196
+        if ($vH > 1) {
197
+            $vH -= 1;
198
+        }
199
+        if ((6 * $vH) < 1) {
200
+            return ($v1 + ($v2 - $v1) * 6 * $vH);
201
+        }
202
+        if ((2 * $vH) < 1) {
203
+            return ($v2);
204
+        }
205
+        if ((3 * $vH) < 2) {
206
+            return ($v1 + ($v2 - $v1) * ((2 / 3) - $vH) * 6);
207
+        }
208
+
209
+        return ($v1);
210
+    };
211
+
212
+    if ($S == 0) {
213
+        // HSV values = 0 -> 1
214
+        $R = $L * 255;
215
+        $G = $L * 255;
216
+        $B = $L * 255;
217
+    } else {
218
+        if ($L < 0.5) {
219
+            $var_2 = $L * (1 + $S);
220
+        } else {
221
+            $var_2 = ($L + $S) - ($S * $L);
222
+        }
223
+
224
+        $var_1 = 2 * $L - $var_2;
225
+
226
+        $R = 255 * $hue_2_rgb($var_1, $var_2, $H + (1 / 3));
227
+        $G = 255 * $hue_2_rgb($var_1, $var_2, $H);
228
+        $B = 255 * $hue_2_rgb($var_1, $var_2, $H - (1 / 3));
229
+    }
230
+
231
+    $ret = [];
232
+    $ret['r'] = floor($R);
233
+    $ret['g'] = floor($G);
234
+    $ret['b'] = floor($B);
235
+
236
+    return $ret;
237 237
 }
238 238
 
239 239
 /**
@@ -251,11 +251,11 @@  discard block
 block discarded – undo
251 251
  *     true si il faut supprimer le fichier temporaire ; false sinon.
252 252
  */
253 253
 function statut_effacer_images_temporaires($stat) {
254
-	static $statut = false; // par defaut on grave toute les images
255
-	if ($stat === 'get') {
256
-		return $statut;
257
-	}
258
-	$statut = $stat ? true : false;
254
+    static $statut = false; // par defaut on grave toute les images
255
+    if ($stat === 'get') {
256
+        return $statut;
257
+    }
258
+    $statut = $stat ? true : false;
259 259
 }
260 260
 
261 261
 
@@ -308,243 +308,243 @@  discard block
 block discarded – undo
308 308
  *     - array : tableau décrivant de l'image
309 309
  */
310 310
 function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = null, $find_in_path = false, $support_svg = false) {
311
-	$ret = [];
312
-	$f = null;
313
-	static $images_recalcul = [];
314
-	if (strlen($img) == 0) {
315
-		return false;
316
-	}
317
-
318
-	$source = trim(extraire_attribut($img, 'src') ?? '');
319
-	if (strlen($source) < 1) {
320
-		$source = $img;
321
-		$img = "<img src='$source' />";
322
-	} elseif (
323
-		preg_match('@^data:image/([^;]*);base64,(.*)$@isS', $source, $regs)
324
-		and $extension = _image_trouver_extension_depuis_mime('image/' . $regs[1])
325
-		and in_array($extension, _image_extensions_acceptees_en_entree())
326
-	) {
327
-		# gerer img src="data:....base64"
328
-		$local = sous_repertoire(_DIR_VAR, 'image-data') . md5($regs[2]) . '.' . _image_extension_normalisee($extension);
329
-		if (!file_exists($local)) {
330
-			ecrire_fichier($local, base64_decode($regs[2]));
331
-		}
332
-		if ($sanitizer = charger_fonction($extension, 'sanitizer', true)) {
333
-			$sanitizer($local);
334
-		}
335
-		$source = $local;
336
-		$img = inserer_attribut($img, 'src', $source);
337
-		# eviter les mauvaises surprises lors de conversions de format
338
-		$img = inserer_attribut($img, 'width', '');
339
-		$img = inserer_attribut($img, 'height', '');
340
-	}
341
-
342
-	// les protocoles web prennent au moins 3 lettres
343
-	if (tester_url_absolue($source)) {
344
-		include_spip('inc/distant');
345
-		$fichier = _DIR_RACINE . copie_locale($source);
346
-		if (!$fichier) {
347
-			return '';
348
-		}
349
-		if (
350
-			$extension = _image_trouver_extension($fichier)
351
-			and $sanitizer = charger_fonction($extension, 'sanitizer', true)
352
-		) {
353
-			$sanitizer($fichier);
354
-		}
355
-	} else {
356
-		// enlever le timestamp eventuel
357
-		if (strpos($source, '?') !== false) {
358
-			$source = preg_replace(',[?][0-9]+$,', '', $source);
359
-		}
360
-		if (
361
-			strpos($source, '?') !== false
362
-			and strncmp($source, _DIR_IMG, strlen(_DIR_IMG)) == 0
363
-			and file_exists($f = preg_replace(',[?].*$,', '', $source))
364
-		) {
365
-			$source = $f;
366
-		}
367
-		$fichier = $source;
368
-	}
369
-
370
-	$terminaison_dest = '';
371
-	if ($terminaison = _image_trouver_extension($fichier)) {
372
-		$terminaison_dest = ($terminaison == 'gif') ? 'png' : $terminaison;
373
-	}
374
-
375
-	if (
376
-		$forcer_format !== false
377
-		// ignorer forcer_format si on a une image svg, que le filtre appelant ne supporte pas SVG, et que le forcage est un autre format image
378
-		and ($terminaison_dest !== 'svg' or $support_svg or !in_array($forcer_format, _image_extensions_acceptees_en_sortie()))
379
-	) {
380
-		$terminaison_dest = $forcer_format;
381
-	}
382
-
383
-	if (!$terminaison_dest) {
384
-		return false;
385
-	}
386
-
387
-	$nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
388
-	$fichier_dest = $nom_fichier;
389
-	if (
390
-		($find_in_path and $f = find_in_path($fichier) and $fichier = $f)
391
-		or @file_exists($f = $fichier)
392
-	) {
393
-		// on passe la balise img a taille image qui exraira les attributs si possible
394
-		// au lieu de faire un acces disque sur le fichier
395
-		[$ret['hauteur'], $ret['largeur']] = taille_image($find_in_path ? $f : $img);
396
-		$date_src = @filemtime($f);
397
-	} elseif (
398
-		@file_exists($f = "$fichier.src")
399
-		and lire_fichier($f, $valeurs)
400
-		and $valeurs = unserialize($valeurs)
401
-		and isset($valeurs['hauteur_dest'])
402
-		and isset($valeurs['largeur_dest'])
403
-	) {
404
-		$ret['hauteur'] = $valeurs['hauteur_dest'];
405
-		$ret['largeur'] = $valeurs['largeur_dest'];
406
-		$date_src = $valeurs['date'];
407
-	} // pas de fichier source par la
408
-	else {
409
-		return false;
410
-	}
411
-
412
-	// pas de taille mesurable
413
-	if (!($ret['hauteur'] or $ret['largeur'])) {
414
-		return false;
415
-	}
416
-
417
-	// les images calculees dependent du chemin du fichier source
418
-	// pour une meme image source et un meme filtre on aboutira a 2 fichiers selon si l'appel est dans le public ou dans le prive
419
-	// ce n'est pas totalement optimal en terme de stockage, mais chaque image est associee a un fichier .src
420
-	// qui contient la methode de reconstrucion (le filtre + les arguments d'appel) et les arguments different entre prive et public
421
-	// la mise en commun du fichier image cree donc un bug et des problemes qui necessiteraient beaucoup de complexite de code
422
-	// alors que ca concerne peu de site au final
423
-	// la release de r23632+r23633+r23634 a provoque peu de remontee de bug attestant du peu de sites impactes
424
-	$identifiant = $fichier;
425
-
426
-	// cas general :
427
-	// on a un dossier cache commun et un nom de fichier qui varie avec l'effet
428
-	// cas particulier de reduire :
429
-	// un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
430
-	$cache = 'cache-gd2';
431
-	if (substr($effet, 0, 7) == 'reduire') {
432
-		[, $maxWidth, $maxHeight] = explode('-', $effet);
433
-		[$destWidth, $destHeight] = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
434
-		$ret['largeur_dest'] = $destWidth;
435
-		$ret['hauteur_dest'] = $destHeight;
436
-		$effet = "L{$destWidth}xH$destHeight";
437
-		$cache = 'cache-vignettes';
438
-		$fichier_dest = basename($fichier_dest);
439
-		if (($ret['largeur'] <= $maxWidth) && ($ret['hauteur'] <= $maxHeight)) {
440
-			// on garde la terminaison initiale car image simplement copiee
441
-			// et on postfixe son nom avec un md5 du path
442
-			$terminaison_dest = $terminaison;
443
-			$fichier_dest .= '-' . substr(md5("$identifiant"), 0, 5);
444
-		} else {
445
-			$fichier_dest .= '-' . substr(md5("$identifiant-$effet"), 0, 5);
446
-		}
447
-		$cache = sous_repertoire(_DIR_VAR, $cache);
448
-		$cache = sous_repertoire($cache, $effet);
449
-	} else {
450
-		$fichier_dest = md5("$identifiant-$effet");
451
-		$cache = sous_repertoire(_DIR_VAR, $cache);
452
-		$cache = sous_repertoire($cache, substr($fichier_dest, 0, 2));
453
-		$fichier_dest = substr($fichier_dest, 2);
454
-	}
455
-
456
-	$fichier_dest = $cache . $fichier_dest . '.' . $terminaison_dest;
457
-
458
-	$GLOBALS['images_calculees'][] = $fichier_dest;
459
-
460
-	$creer = true;
461
-	// si recalcul des images demande, recalculer chaque image une fois
462
-	if (defined('_VAR_IMAGES') and _VAR_IMAGES and !isset($images_recalcul[$fichier_dest])) {
463
-		$images_recalcul[$fichier_dest] = true;
464
-	} else {
465
-		if (@file_exists($f = $fichier_dest)) {
466
-			if (filemtime($f) >= $date_src) {
467
-				$creer = false;
468
-			}
469
-		} else {
470
-			if (
471
-				@file_exists($f = "$fichier_dest.src")
472
-				and lire_fichier($f, $valeurs)
473
-				and $valeurs = unserialize($valeurs)
474
-				and $valeurs['date'] >= $date_src
475
-			) {
476
-				$creer = false;
477
-			}
478
-		}
479
-	}
480
-	if ($creer) {
481
-		if (!@file_exists($fichier)) {
482
-			if (!@file_exists("$fichier.src")) {
483
-				spip_log("Image absente : $fichier");
484
-
485
-				return false;
486
-			}
487
-			# on reconstruit l'image source absente a partir de la chaine des .src
488
-			reconstruire_image_intermediaire($fichier);
489
-		}
490
-	}
491
-
492
-	if ($creer) {
493
-		spip_log(
494
-			'filtre image ' . ($fonction_creation ? reset($fonction_creation) : '') . "[$effet] sur $fichier",
495
-			'images' . _LOG_DEBUG
496
-		);
497
-	}
498
-
499
-	$term_fonction = _image_trouver_extension_pertinente($fichier);
500
-	$ret['fonction_imagecreatefrom'] = '_imagecreatefrom' . $term_fonction;
501
-	$ret['fichier'] = $fichier;
502
-	$ret['fonction_image'] = '_image_image' . $terminaison_dest;
503
-	$ret['fichier_dest'] = $fichier_dest;
504
-	$ret['format_source'] = _image_extension_normalisee($terminaison);
505
-	$ret['format_dest'] = $terminaison_dest;
506
-	$ret['date_src'] = $date_src;
507
-	$ret['creer'] = $creer;
508
-	$ret['class'] = extraire_attribut($img, 'class');
509
-	$ret['alt'] = extraire_attribut($img, 'alt');
510
-	$ret['style'] = extraire_attribut($img, 'style');
511
-	$ret['tag'] = $img;
512
-	if ($fonction_creation) {
513
-		$ret['reconstruction'] = $fonction_creation;
514
-		# ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement
515
-		# cas de image_reduire qui finalement ne reduit pas l'image source
516
-		# ca evite d'essayer de le creer au prochain hit si il n'est pas la
517
-		#ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
518
-	}
519
-
520
-	$ret = pipeline('image_preparer_filtre', [
521
-			'args' => [
522
-				'img' => $img,
523
-				'effet' => $effet,
524
-				'forcer_format' => $forcer_format,
525
-				'fonction_creation' => $fonction_creation,
526
-				'find_in_path' => $find_in_path,
527
-			],
528
-			'data' => $ret
529
-		]);
530
-
531
-	// une globale pour le debug en cas de crash memoire
532
-	$GLOBALS['derniere_image_calculee'] = $ret;
533
-
534
-	// traiter le cas particulier des SVG : si le filtre n'a pas annonce explicitement qu'il savait faire, on delegue
535
-	if ($term_fonction === 'svg') {
536
-		if ($creer and !$support_svg) {
537
-			process_image_svg_identite($ret);
538
-			$ret['creer'] = false;
539
-		}
540
-	}
541
-	else {
542
-		if (!function_exists($ret['fonction_imagecreatefrom'])) {
543
-			return false;
544
-		}
545
-	}
546
-
547
-	return $ret;
311
+    $ret = [];
312
+    $f = null;
313
+    static $images_recalcul = [];
314
+    if (strlen($img) == 0) {
315
+        return false;
316
+    }
317
+
318
+    $source = trim(extraire_attribut($img, 'src') ?? '');
319
+    if (strlen($source) < 1) {
320
+        $source = $img;
321
+        $img = "<img src='$source' />";
322
+    } elseif (
323
+        preg_match('@^data:image/([^;]*);base64,(.*)$@isS', $source, $regs)
324
+        and $extension = _image_trouver_extension_depuis_mime('image/' . $regs[1])
325
+        and in_array($extension, _image_extensions_acceptees_en_entree())
326
+    ) {
327
+        # gerer img src="data:....base64"
328
+        $local = sous_repertoire(_DIR_VAR, 'image-data') . md5($regs[2]) . '.' . _image_extension_normalisee($extension);
329
+        if (!file_exists($local)) {
330
+            ecrire_fichier($local, base64_decode($regs[2]));
331
+        }
332
+        if ($sanitizer = charger_fonction($extension, 'sanitizer', true)) {
333
+            $sanitizer($local);
334
+        }
335
+        $source = $local;
336
+        $img = inserer_attribut($img, 'src', $source);
337
+        # eviter les mauvaises surprises lors de conversions de format
338
+        $img = inserer_attribut($img, 'width', '');
339
+        $img = inserer_attribut($img, 'height', '');
340
+    }
341
+
342
+    // les protocoles web prennent au moins 3 lettres
343
+    if (tester_url_absolue($source)) {
344
+        include_spip('inc/distant');
345
+        $fichier = _DIR_RACINE . copie_locale($source);
346
+        if (!$fichier) {
347
+            return '';
348
+        }
349
+        if (
350
+            $extension = _image_trouver_extension($fichier)
351
+            and $sanitizer = charger_fonction($extension, 'sanitizer', true)
352
+        ) {
353
+            $sanitizer($fichier);
354
+        }
355
+    } else {
356
+        // enlever le timestamp eventuel
357
+        if (strpos($source, '?') !== false) {
358
+            $source = preg_replace(',[?][0-9]+$,', '', $source);
359
+        }
360
+        if (
361
+            strpos($source, '?') !== false
362
+            and strncmp($source, _DIR_IMG, strlen(_DIR_IMG)) == 0
363
+            and file_exists($f = preg_replace(',[?].*$,', '', $source))
364
+        ) {
365
+            $source = $f;
366
+        }
367
+        $fichier = $source;
368
+    }
369
+
370
+    $terminaison_dest = '';
371
+    if ($terminaison = _image_trouver_extension($fichier)) {
372
+        $terminaison_dest = ($terminaison == 'gif') ? 'png' : $terminaison;
373
+    }
374
+
375
+    if (
376
+        $forcer_format !== false
377
+        // ignorer forcer_format si on a une image svg, que le filtre appelant ne supporte pas SVG, et que le forcage est un autre format image
378
+        and ($terminaison_dest !== 'svg' or $support_svg or !in_array($forcer_format, _image_extensions_acceptees_en_sortie()))
379
+    ) {
380
+        $terminaison_dest = $forcer_format;
381
+    }
382
+
383
+    if (!$terminaison_dest) {
384
+        return false;
385
+    }
386
+
387
+    $nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
388
+    $fichier_dest = $nom_fichier;
389
+    if (
390
+        ($find_in_path and $f = find_in_path($fichier) and $fichier = $f)
391
+        or @file_exists($f = $fichier)
392
+    ) {
393
+        // on passe la balise img a taille image qui exraira les attributs si possible
394
+        // au lieu de faire un acces disque sur le fichier
395
+        [$ret['hauteur'], $ret['largeur']] = taille_image($find_in_path ? $f : $img);
396
+        $date_src = @filemtime($f);
397
+    } elseif (
398
+        @file_exists($f = "$fichier.src")
399
+        and lire_fichier($f, $valeurs)
400
+        and $valeurs = unserialize($valeurs)
401
+        and isset($valeurs['hauteur_dest'])
402
+        and isset($valeurs['largeur_dest'])
403
+    ) {
404
+        $ret['hauteur'] = $valeurs['hauteur_dest'];
405
+        $ret['largeur'] = $valeurs['largeur_dest'];
406
+        $date_src = $valeurs['date'];
407
+    } // pas de fichier source par la
408
+    else {
409
+        return false;
410
+    }
411
+
412
+    // pas de taille mesurable
413
+    if (!($ret['hauteur'] or $ret['largeur'])) {
414
+        return false;
415
+    }
416
+
417
+    // les images calculees dependent du chemin du fichier source
418
+    // pour une meme image source et un meme filtre on aboutira a 2 fichiers selon si l'appel est dans le public ou dans le prive
419
+    // ce n'est pas totalement optimal en terme de stockage, mais chaque image est associee a un fichier .src
420
+    // qui contient la methode de reconstrucion (le filtre + les arguments d'appel) et les arguments different entre prive et public
421
+    // la mise en commun du fichier image cree donc un bug et des problemes qui necessiteraient beaucoup de complexite de code
422
+    // alors que ca concerne peu de site au final
423
+    // la release de r23632+r23633+r23634 a provoque peu de remontee de bug attestant du peu de sites impactes
424
+    $identifiant = $fichier;
425
+
426
+    // cas general :
427
+    // on a un dossier cache commun et un nom de fichier qui varie avec l'effet
428
+    // cas particulier de reduire :
429
+    // un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
430
+    $cache = 'cache-gd2';
431
+    if (substr($effet, 0, 7) == 'reduire') {
432
+        [, $maxWidth, $maxHeight] = explode('-', $effet);
433
+        [$destWidth, $destHeight] = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
434
+        $ret['largeur_dest'] = $destWidth;
435
+        $ret['hauteur_dest'] = $destHeight;
436
+        $effet = "L{$destWidth}xH$destHeight";
437
+        $cache = 'cache-vignettes';
438
+        $fichier_dest = basename($fichier_dest);
439
+        if (($ret['largeur'] <= $maxWidth) && ($ret['hauteur'] <= $maxHeight)) {
440
+            // on garde la terminaison initiale car image simplement copiee
441
+            // et on postfixe son nom avec un md5 du path
442
+            $terminaison_dest = $terminaison;
443
+            $fichier_dest .= '-' . substr(md5("$identifiant"), 0, 5);
444
+        } else {
445
+            $fichier_dest .= '-' . substr(md5("$identifiant-$effet"), 0, 5);
446
+        }
447
+        $cache = sous_repertoire(_DIR_VAR, $cache);
448
+        $cache = sous_repertoire($cache, $effet);
449
+    } else {
450
+        $fichier_dest = md5("$identifiant-$effet");
451
+        $cache = sous_repertoire(_DIR_VAR, $cache);
452
+        $cache = sous_repertoire($cache, substr($fichier_dest, 0, 2));
453
+        $fichier_dest = substr($fichier_dest, 2);
454
+    }
455
+
456
+    $fichier_dest = $cache . $fichier_dest . '.' . $terminaison_dest;
457
+
458
+    $GLOBALS['images_calculees'][] = $fichier_dest;
459
+
460
+    $creer = true;
461
+    // si recalcul des images demande, recalculer chaque image une fois
462
+    if (defined('_VAR_IMAGES') and _VAR_IMAGES and !isset($images_recalcul[$fichier_dest])) {
463
+        $images_recalcul[$fichier_dest] = true;
464
+    } else {
465
+        if (@file_exists($f = $fichier_dest)) {
466
+            if (filemtime($f) >= $date_src) {
467
+                $creer = false;
468
+            }
469
+        } else {
470
+            if (
471
+                @file_exists($f = "$fichier_dest.src")
472
+                and lire_fichier($f, $valeurs)
473
+                and $valeurs = unserialize($valeurs)
474
+                and $valeurs['date'] >= $date_src
475
+            ) {
476
+                $creer = false;
477
+            }
478
+        }
479
+    }
480
+    if ($creer) {
481
+        if (!@file_exists($fichier)) {
482
+            if (!@file_exists("$fichier.src")) {
483
+                spip_log("Image absente : $fichier");
484
+
485
+                return false;
486
+            }
487
+            # on reconstruit l'image source absente a partir de la chaine des .src
488
+            reconstruire_image_intermediaire($fichier);
489
+        }
490
+    }
491
+
492
+    if ($creer) {
493
+        spip_log(
494
+            'filtre image ' . ($fonction_creation ? reset($fonction_creation) : '') . "[$effet] sur $fichier",
495
+            'images' . _LOG_DEBUG
496
+        );
497
+    }
498
+
499
+    $term_fonction = _image_trouver_extension_pertinente($fichier);
500
+    $ret['fonction_imagecreatefrom'] = '_imagecreatefrom' . $term_fonction;
501
+    $ret['fichier'] = $fichier;
502
+    $ret['fonction_image'] = '_image_image' . $terminaison_dest;
503
+    $ret['fichier_dest'] = $fichier_dest;
504
+    $ret['format_source'] = _image_extension_normalisee($terminaison);
505
+    $ret['format_dest'] = $terminaison_dest;
506
+    $ret['date_src'] = $date_src;
507
+    $ret['creer'] = $creer;
508
+    $ret['class'] = extraire_attribut($img, 'class');
509
+    $ret['alt'] = extraire_attribut($img, 'alt');
510
+    $ret['style'] = extraire_attribut($img, 'style');
511
+    $ret['tag'] = $img;
512
+    if ($fonction_creation) {
513
+        $ret['reconstruction'] = $fonction_creation;
514
+        # ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement
515
+        # cas de image_reduire qui finalement ne reduit pas l'image source
516
+        # ca evite d'essayer de le creer au prochain hit si il n'est pas la
517
+        #ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
518
+    }
519
+
520
+    $ret = pipeline('image_preparer_filtre', [
521
+            'args' => [
522
+                'img' => $img,
523
+                'effet' => $effet,
524
+                'forcer_format' => $forcer_format,
525
+                'fonction_creation' => $fonction_creation,
526
+                'find_in_path' => $find_in_path,
527
+            ],
528
+            'data' => $ret
529
+        ]);
530
+
531
+    // une globale pour le debug en cas de crash memoire
532
+    $GLOBALS['derniere_image_calculee'] = $ret;
533
+
534
+    // traiter le cas particulier des SVG : si le filtre n'a pas annonce explicitement qu'il savait faire, on delegue
535
+    if ($term_fonction === 'svg') {
536
+        if ($creer and !$support_svg) {
537
+            process_image_svg_identite($ret);
538
+            $ret['creer'] = false;
539
+        }
540
+    }
541
+    else {
542
+        if (!function_exists($ret['fonction_imagecreatefrom'])) {
543
+            return false;
544
+        }
545
+    }
546
+
547
+    return $ret;
548 548
 }
549 549
 
550 550
 
@@ -553,54 +553,54 @@  discard block
 block discarded – undo
553 553
  * @return array
554 554
  */
555 555
 function _image_extensions_acceptees_en_entree() {
556
-	static $extensions = null;
557
-	if (empty($extensions)) {
558
-		$extensions = ['png', 'gif', 'jpg', 'jpeg'];
559
-		if (!empty($GLOBALS['meta']['gd_formats'])) {
560
-			// action=tester renseigne gd_formats et detecte le support de webp
561
-			$extensions = array_merge(explode(',', $GLOBALS['meta']['gd_formats']));
562
-			$extensions = array_map('trim', $extensions);
563
-			$extensions = array_filter($extensions);
564
-			if (in_array('jpg', $extensions)) {
565
-				$extensions[] = 'jpeg';
566
-			}
567
-			$extensions = array_unique($extensions);
568
-		}
569
-		$extensions[] = 'svg'; // on le supporte toujours avec des fonctions specifiques
570
-	}
571
-
572
-	return $extensions;
556
+    static $extensions = null;
557
+    if (empty($extensions)) {
558
+        $extensions = ['png', 'gif', 'jpg', 'jpeg'];
559
+        if (!empty($GLOBALS['meta']['gd_formats'])) {
560
+            // action=tester renseigne gd_formats et detecte le support de webp
561
+            $extensions = array_merge(explode(',', $GLOBALS['meta']['gd_formats']));
562
+            $extensions = array_map('trim', $extensions);
563
+            $extensions = array_filter($extensions);
564
+            if (in_array('jpg', $extensions)) {
565
+                $extensions[] = 'jpeg';
566
+            }
567
+            $extensions = array_unique($extensions);
568
+        }
569
+        $extensions[] = 'svg'; // on le supporte toujours avec des fonctions specifiques
570
+    }
571
+
572
+    return $extensions;
573 573
 }
574 574
 
575 575
 /**
576 576
  * @return array|string[]|null
577 577
  */
578 578
 function _image_extensions_acceptees_en_sortie() {
579
-	static $extensions = null;
580
-	if (empty($extensions)) {
581
-		$extensions = _image_extensions_acceptees_en_entree();
582
-		$extensions = array_diff($extensions, ['jpeg']);
583
-		if (in_array('gif', $extensions) and !function_exists('imagegif')) {
584
-			$extensions = array_diff($extensions, ['gif']);
585
-		}
586
-		if (in_array('webp', $extensions) and !function_exists('imagewebp')) {
587
-			$extensions = array_diff($extensions, ['webp']);
588
-		}
589
-	}
590
-
591
-	return $extensions;
579
+    static $extensions = null;
580
+    if (empty($extensions)) {
581
+        $extensions = _image_extensions_acceptees_en_entree();
582
+        $extensions = array_diff($extensions, ['jpeg']);
583
+        if (in_array('gif', $extensions) and !function_exists('imagegif')) {
584
+            $extensions = array_diff($extensions, ['gif']);
585
+        }
586
+        if (in_array('webp', $extensions) and !function_exists('imagewebp')) {
587
+            $extensions = array_diff($extensions, ['webp']);
588
+        }
589
+    }
590
+
591
+    return $extensions;
592 592
 }
593 593
 
594 594
 function _image_extension_normalisee($extension) {
595
-	$extension = strtolower($extension);
596
-	if ($extension === 'jpeg') {
597
-		$extension = 'jpg';
598
-	}
599
-	return $extension;
595
+    $extension = strtolower($extension);
596
+    if ($extension === 'jpeg') {
597
+        $extension = 'jpg';
598
+    }
599
+    return $extension;
600 600
 }
601 601
 
602 602
 function _image_extensions_conservent_transparence() {
603
-	return ['png', 'webp'];
603
+    return ['png', 'webp'];
604 604
 }
605 605
 
606 606
 
@@ -610,12 +610,12 @@  discard block
 block discarded – undo
610 610
  * @return string
611 611
  */
612 612
 function _image_trouver_extension($path) {
613
-	$preg_extensions = implode('|', _image_extensions_acceptees_en_entree());
614
-	if (preg_match(",\.($preg_extensions)($|[?]),i", $path, $regs)) {
615
-		$terminaison = strtolower($regs[1]);
616
-		return $terminaison;
617
-	}
618
-	return '';
613
+    $preg_extensions = implode('|', _image_extensions_acceptees_en_entree());
614
+    if (preg_match(",\.($preg_extensions)($|[?]),i", $path, $regs)) {
615
+        $terminaison = strtolower($regs[1]);
616
+        return $terminaison;
617
+    }
618
+    return '';
619 619
 }
620 620
 
621 621
 /**
@@ -626,33 +626,33 @@  discard block
 block discarded – undo
626 626
  * @return string Extension, dans le format attendu par les fonctions 'gd' ('jpeg' pour les .jpg par exemple)
627 627
  */
628 628
 function _image_trouver_extension_pertinente($path) {
629
-	$path = supprimer_timestamp($path);
630
-	$terminaison = _image_trouver_extension($path);
631
-	if ($terminaison == 'jpg') {
632
-		$terminaison = 'jpeg';
633
-	}
634
-
635
-	if (!file_exists($path)) {
636
-		return $terminaison;
637
-	}
638
-
639
-	if (!$info = @spip_getimagesize($path)) {
640
-		return $terminaison;
641
-	}
642
-
643
-	if (isset($info['mime'])) {
644
-		$mime = $info['mime'];
645
-	}
646
-	else {
647
-		$mime = image_type_to_mime_type($info[2]);
648
-	}
649
-
650
-	$_terminaison = _image_trouver_extension_depuis_mime($mime);
651
-	if ($_terminaison and $_terminaison !== $terminaison) {
652
-		spip_log("Mauvaise extension du fichier : $path . Son type mime est : $mime", 'images.' . _LOG_INFO_IMPORTANTE);
653
-		$terminaison = $_terminaison;
654
-	}
655
-	return $terminaison;
629
+    $path = supprimer_timestamp($path);
630
+    $terminaison = _image_trouver_extension($path);
631
+    if ($terminaison == 'jpg') {
632
+        $terminaison = 'jpeg';
633
+    }
634
+
635
+    if (!file_exists($path)) {
636
+        return $terminaison;
637
+    }
638
+
639
+    if (!$info = @spip_getimagesize($path)) {
640
+        return $terminaison;
641
+    }
642
+
643
+    if (isset($info['mime'])) {
644
+        $mime = $info['mime'];
645
+    }
646
+    else {
647
+        $mime = image_type_to_mime_type($info[2]);
648
+    }
649
+
650
+    $_terminaison = _image_trouver_extension_depuis_mime($mime);
651
+    if ($_terminaison and $_terminaison !== $terminaison) {
652
+        spip_log("Mauvaise extension du fichier : $path . Son type mime est : $mime", 'images.' . _LOG_INFO_IMPORTANTE);
653
+        $terminaison = $_terminaison;
654
+    }
655
+    return $terminaison;
656 656
 }
657 657
 
658 658
 /**
@@ -660,36 +660,36 @@  discard block
 block discarded – undo
660 660
  * @return string
661 661
  */
662 662
 function _image_trouver_extension_depuis_mime($mime) {
663
-	switch (strtolower($mime)) {
664
-		case 'image/png':
665
-		case 'image/x-png':
666
-			$terminaison = 'png';
667
-			break;
668
-
669
-		case 'image/jpg':
670
-		case 'image/jpeg':
671
-		case 'image/pjpeg':
672
-			$terminaison = 'jpeg';
673
-			break;
674
-
675
-		case 'image/gif':
676
-			$terminaison = 'gif';
677
-			break;
678
-
679
-		case 'image/webp':
680
-		case 'image/x-webp':
681
-			$terminaison = 'webp';
682
-			break;
683
-
684
-		case 'image/svg+xml':
685
-			$terminaison = 'svg';
686
-			break;
687
-
688
-		default:
689
-			$terminaison = '';
690
-	}
691
-
692
-	return $terminaison;
663
+    switch (strtolower($mime)) {
664
+        case 'image/png':
665
+        case 'image/x-png':
666
+            $terminaison = 'png';
667
+            break;
668
+
669
+        case 'image/jpg':
670
+        case 'image/jpeg':
671
+        case 'image/pjpeg':
672
+            $terminaison = 'jpeg';
673
+            break;
674
+
675
+        case 'image/gif':
676
+            $terminaison = 'gif';
677
+            break;
678
+
679
+        case 'image/webp':
680
+        case 'image/x-webp':
681
+            $terminaison = 'webp';
682
+            break;
683
+
684
+        case 'image/svg+xml':
685
+            $terminaison = 'svg';
686
+            break;
687
+
688
+        default:
689
+            $terminaison = '';
690
+    }
691
+
692
+    return $terminaison;
693 693
 }
694 694
 
695 695
 
@@ -709,18 +709,18 @@  discard block
 block discarded – undo
709 709
  *     Une ressource de type Image GD.
710 710
  */
711 711
 function _imagecreatefrom_func(string $func, string $filename) {
712
-	if (!function_exists($func)) {
713
-		spip_log("GD indisponible : $func inexistante. Traitement $filename impossible.", _LOG_CRITIQUE);
714
-		erreur_squelette("GD indisponible : $func inexistante. Traitement $filename impossible.");
715
-		return null;
716
-	}
717
-	$img = @$func($filename);
718
-	if (!$img) {
719
-		spip_log("Erreur lecture imagecreatefromjpeg $filename", _LOG_CRITIQUE);
720
-		erreur_squelette("Erreur lecture imagecreatefromjpeg $filename");
721
-		$img = imagecreate(10, 10);
722
-	}
723
-	return $img;
712
+    if (!function_exists($func)) {
713
+        spip_log("GD indisponible : $func inexistante. Traitement $filename impossible.", _LOG_CRITIQUE);
714
+        erreur_squelette("GD indisponible : $func inexistante. Traitement $filename impossible.");
715
+        return null;
716
+    }
717
+    $img = @$func($filename);
718
+    if (!$img) {
719
+        spip_log("Erreur lecture imagecreatefromjpeg $filename", _LOG_CRITIQUE);
720
+        erreur_squelette("Erreur lecture imagecreatefromjpeg $filename");
721
+        $img = imagecreate(10, 10);
722
+    }
723
+    return $img;
724 724
 }
725 725
 
726 726
 /**
@@ -736,7 +736,7 @@  discard block
 block discarded – undo
736 736
  *     Une ressource de type Image GD.
737 737
  */
738 738
 function _imagecreatefromjpeg($filename) {
739
-	return _imagecreatefrom_func('imagecreatefromjpeg', $filename);
739
+    return _imagecreatefrom_func('imagecreatefromjpeg', $filename);
740 740
 }
741 741
 
742 742
 /**
@@ -752,7 +752,7 @@  discard block
 block discarded – undo
752 752
  *     Une ressource de type Image GD.
753 753
  */
754 754
 function _imagecreatefrompng($filename) {
755
-	return _imagecreatefrom_func('imagecreatefrompng', $filename);
755
+    return _imagecreatefrom_func('imagecreatefrompng', $filename);
756 756
 }
757 757
 
758 758
 /**
@@ -768,7 +768,7 @@  discard block
 block discarded – undo
768 768
  *     Une ressource de type Image GD.
769 769
  */
770 770
 function _imagecreatefromgif($filename) {
771
-	return _imagecreatefrom_func('imagecreatefromgif', $filename);
771
+    return _imagecreatefrom_func('imagecreatefromgif', $filename);
772 772
 }
773 773
 
774 774
 
@@ -785,7 +785,7 @@  discard block
 block discarded – undo
785 785
  *     Une ressource de type Image GD.
786 786
  */
787 787
 function _imagecreatefromwebp($filename) {
788
-	return _imagecreatefrom_func('imagecreatefromwebp', $filename);
788
+    return _imagecreatefrom_func('imagecreatefromwebp', $filename);
789 789
 }
790 790
 
791 791
 /**
@@ -803,24 +803,24 @@  discard block
 block discarded – undo
803 803
  *     - true si une image est bien retournée.
804 804
  */
805 805
 function _image_imagepng($img, $fichier) {
806
-	if (!function_exists('imagepng')) {
807
-		return false;
808
-	}
809
-	$tmp = $fichier . '.tmp';
810
-	$ret = imagepng($img, $tmp);
811
-	if (file_exists($tmp)) {
812
-		$taille_test = getimagesize($tmp);
813
-		if ($taille_test[0] < 1) {
814
-			return false;
815
-		}
816
-
817
-		spip_unlink($fichier); // le fichier peut deja exister
818
-		@rename($tmp, $fichier);
819
-
820
-		return $ret;
821
-	}
822
-
823
-	return false;
806
+    if (!function_exists('imagepng')) {
807
+        return false;
808
+    }
809
+    $tmp = $fichier . '.tmp';
810
+    $ret = imagepng($img, $tmp);
811
+    if (file_exists($tmp)) {
812
+        $taille_test = getimagesize($tmp);
813
+        if ($taille_test[0] < 1) {
814
+            return false;
815
+        }
816
+
817
+        spip_unlink($fichier); // le fichier peut deja exister
818
+        @rename($tmp, $fichier);
819
+
820
+        return $ret;
821
+    }
822
+
823
+    return false;
824 824
 }
825 825
 
826 826
 /**
@@ -838,24 +838,24 @@  discard block
 block discarded – undo
838 838
  *     - true si une image est bien retournée.
839 839
  */
840 840
 function _image_imagegif($img, $fichier) {
841
-	if (!function_exists('imagegif')) {
842
-		return false;
843
-	}
844
-	$tmp = $fichier . '.tmp';
845
-	$ret = imagegif($img, $tmp);
846
-	if (file_exists($tmp)) {
847
-		$taille_test = getimagesize($tmp);
848
-		if ($taille_test[0] < 1) {
849
-			return false;
850
-		}
851
-
852
-		spip_unlink($fichier); // le fichier peut deja exister
853
-		@rename($tmp, $fichier);
854
-
855
-		return $ret;
856
-	}
857
-
858
-	return false;
841
+    if (!function_exists('imagegif')) {
842
+        return false;
843
+    }
844
+    $tmp = $fichier . '.tmp';
845
+    $ret = imagegif($img, $tmp);
846
+    if (file_exists($tmp)) {
847
+        $taille_test = getimagesize($tmp);
848
+        if ($taille_test[0] < 1) {
849
+            return false;
850
+        }
851
+
852
+        spip_unlink($fichier); // le fichier peut deja exister
853
+        @rename($tmp, $fichier);
854
+
855
+        return $ret;
856
+    }
857
+
858
+    return false;
859 859
 }
860 860
 
861 861
 /**
@@ -878,29 +878,29 @@  discard block
 block discarded – undo
878 878
  *     - true si une image est bien retournée.
879 879
  */
880 880
 function _image_imagejpg($img, $fichier, $qualite = _IMG_GD_QUALITE) {
881
-	if (!function_exists('imagejpeg')) {
882
-		return false;
883
-	}
884
-	$tmp = $fichier . '.tmp';
881
+    if (!function_exists('imagejpeg')) {
882
+        return false;
883
+    }
884
+    $tmp = $fichier . '.tmp';
885 885
 
886
-	// Enable interlancing
887
-	imageinterlace($img, true);
886
+    // Enable interlancing
887
+    imageinterlace($img, true);
888 888
 
889
-	$ret = imagejpeg($img, $tmp, $qualite);
889
+    $ret = imagejpeg($img, $tmp, $qualite);
890 890
 
891
-	if (file_exists($tmp)) {
892
-		$taille_test = getimagesize($tmp);
893
-		if ($taille_test[0] < 1) {
894
-			return false;
895
-		}
891
+    if (file_exists($tmp)) {
892
+        $taille_test = getimagesize($tmp);
893
+        if ($taille_test[0] < 1) {
894
+            return false;
895
+        }
896 896
 
897
-		spip_unlink($fichier); // le fichier peut deja exister
898
-		@rename($tmp, $fichier);
897
+        spip_unlink($fichier); // le fichier peut deja exister
898
+        @rename($tmp, $fichier);
899 899
 
900
-		return $ret;
901
-	}
900
+        return $ret;
901
+    }
902 902
 
903
-	return false;
903
+    return false;
904 904
 }
905 905
 
906 906
 /**
@@ -918,9 +918,9 @@  discard block
 block discarded – undo
918 918
  *     true si le fichier a bien été créé ; false sinon.
919 919
  */
920 920
 function _image_imageico($img, $fichier) {
921
-	$gd_image_array = [$img];
921
+    $gd_image_array = [$img];
922 922
 
923
-	return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
923
+    return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
924 924
 }
925 925
 
926 926
 
@@ -939,24 +939,24 @@  discard block
 block discarded – undo
939 939
  *     - true si une image est bien retournée.
940 940
  */
941 941
 function _image_imagewebp($img, $fichier, $qualite = _IMG_GD_QUALITE) {
942
-	if (!function_exists('imagewebp')) {
943
-		return false;
944
-	}
945
-	$tmp = $fichier . '.tmp';
946
-	$ret = imagewebp($img, $tmp, $qualite);
947
-	if (file_exists($tmp)) {
948
-		$taille_test = getimagesize($tmp);
949
-		if ($taille_test[0] < 1) {
950
-			return false;
951
-		}
952
-
953
-		spip_unlink($fichier); // le fichier peut deja exister
954
-		@rename($tmp, $fichier);
955
-
956
-		return $ret;
957
-	}
958
-
959
-	return false;
942
+    if (!function_exists('imagewebp')) {
943
+        return false;
944
+    }
945
+    $tmp = $fichier . '.tmp';
946
+    $ret = imagewebp($img, $tmp, $qualite);
947
+    if (file_exists($tmp)) {
948
+        $taille_test = getimagesize($tmp);
949
+        if ($taille_test[0] < 1) {
950
+            return false;
951
+        }
952
+
953
+        spip_unlink($fichier); // le fichier peut deja exister
954
+        @rename($tmp, $fichier);
955
+
956
+        return $ret;
957
+    }
958
+
959
+    return false;
960 960
 }
961 961
 
962 962
 /**
@@ -976,35 +976,35 @@  discard block
 block discarded – undo
976 976
  */
977 977
 function _image_imagesvg($img, $fichier) {
978 978
 
979
-	$tmp = $fichier . '.tmp';
980
-	if (strpos($img, '<') === false) {
981
-		$img = supprimer_timestamp($img);
982
-		if (!file_exists($img)) {
983
-			return false;
984
-		}
985
-		@copy($img, $tmp);
986
-		if (filesize($tmp) == filesize($img)) {
987
-			spip_unlink($fichier); // le fichier peut deja exister
988
-			@rename($tmp, $fichier);
989
-			return true;
990
-		}
991
-		return false;
992
-	}
993
-
994
-	file_put_contents($tmp, $img);
995
-	if (file_exists($tmp)) {
996
-		$taille_test = spip_getimagesize($tmp);
997
-		if ($taille_test[0] < 1) {
998
-			return false;
999
-		}
1000
-
1001
-		spip_unlink($fichier); // le fichier peut deja exister
1002
-		@rename($tmp, $fichier);
1003
-
1004
-		return true;
1005
-	}
1006
-
1007
-	return false;
979
+    $tmp = $fichier . '.tmp';
980
+    if (strpos($img, '<') === false) {
981
+        $img = supprimer_timestamp($img);
982
+        if (!file_exists($img)) {
983
+            return false;
984
+        }
985
+        @copy($img, $tmp);
986
+        if (filesize($tmp) == filesize($img)) {
987
+            spip_unlink($fichier); // le fichier peut deja exister
988
+            @rename($tmp, $fichier);
989
+            return true;
990
+        }
991
+        return false;
992
+    }
993
+
994
+    file_put_contents($tmp, $img);
995
+    if (file_exists($tmp)) {
996
+        $taille_test = spip_getimagesize($tmp);
997
+        if ($taille_test[0] < 1) {
998
+            return false;
999
+        }
1000
+
1001
+        spip_unlink($fichier); // le fichier peut deja exister
1002
+        @rename($tmp, $fichier);
1003
+
1004
+        return true;
1005
+    }
1006
+
1007
+    return false;
1008 1008
 }
1009 1009
 
1010 1010
 
@@ -1032,30 +1032,30 @@  discard block
 block discarded – undo
1032 1032
  *     - false sinon.
1033 1033
  */
1034 1034
 function _image_gd_output($img, $valeurs, $qualite = _IMG_GD_QUALITE, $fonction = null) {
1035
-	if (is_null($fonction)) {
1036
-		$fonction = '_image_image' . $valeurs['format_dest'];
1037
-	}
1038
-	$ret = false;
1039
-	#un flag pour reperer les images gravees
1040
-	$lock = (
1041
-		!statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
1042
-		or (@file_exists($valeurs['fichier_dest']) and !@file_exists($valeurs['fichier_dest'] . '.src'))
1043
-	);
1044
-	if (
1045
-		function_exists($fonction)
1046
-		&& ($ret = $fonction($img, $valeurs['fichier_dest'], $qualite)) # on a reussi a creer l'image
1047
-		&& isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
1048
-		&& !$lock
1049
-	) {
1050
-		if (@file_exists($valeurs['fichier_dest'])) {
1051
-			// dans tous les cas mettre a jour la taille de l'image finale
1052
-			[$valeurs['hauteur_dest'], $valeurs['largeur_dest']] = taille_image($valeurs['fichier_dest']);
1053
-			$valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
1054
-			ecrire_fichier($valeurs['fichier_dest'] . '.src', serialize($valeurs), true);
1055
-		}
1056
-	}
1057
-
1058
-	return $ret;
1035
+    if (is_null($fonction)) {
1036
+        $fonction = '_image_image' . $valeurs['format_dest'];
1037
+    }
1038
+    $ret = false;
1039
+    #un flag pour reperer les images gravees
1040
+    $lock = (
1041
+        !statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
1042
+        or (@file_exists($valeurs['fichier_dest']) and !@file_exists($valeurs['fichier_dest'] . '.src'))
1043
+    );
1044
+    if (
1045
+        function_exists($fonction)
1046
+        && ($ret = $fonction($img, $valeurs['fichier_dest'], $qualite)) # on a reussi a creer l'image
1047
+        && isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
1048
+        && !$lock
1049
+    ) {
1050
+        if (@file_exists($valeurs['fichier_dest'])) {
1051
+            // dans tous les cas mettre a jour la taille de l'image finale
1052
+            [$valeurs['hauteur_dest'], $valeurs['largeur_dest']] = taille_image($valeurs['fichier_dest']);
1053
+            $valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
1054
+            ecrire_fichier($valeurs['fichier_dest'] . '.src', serialize($valeurs), true);
1055
+        }
1056
+    }
1057
+
1058
+    return $ret;
1059 1059
 }
1060 1060
 
1061 1061
 /**
@@ -1068,27 +1068,27 @@  discard block
 block discarded – undo
1068 1068
  *     Chemin vers le fichier manquant
1069 1069
  **/
1070 1070
 function reconstruire_image_intermediaire($fichier_manquant) {
1071
-	$reconstruire = [];
1072
-	$fichier = $fichier_manquant;
1073
-	while (
1074
-		strpos($fichier, '://') === false
1075
-		and !@file_exists($fichier)
1076
-		and lire_fichier($src = "$fichier.src", $source)
1077
-		and $valeurs = unserialize($source)
1078
-		and ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
1079
-	) {
1080
-		spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
1081
-		$reconstruire[] = $valeurs['reconstruction'];
1082
-	}
1083
-	while (count($reconstruire)) {
1084
-		$r = array_pop($reconstruire);
1085
-		$fonction = $r[0];
1086
-		$args = $r[1];
1087
-		$fonction(...$args);
1088
-	}
1089
-	// cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
1090
-	// mais l'on peut nettoyer les miettes de sa creation
1091
-	ramasse_miettes($fichier_manquant);
1071
+    $reconstruire = [];
1072
+    $fichier = $fichier_manquant;
1073
+    while (
1074
+        strpos($fichier, '://') === false
1075
+        and !@file_exists($fichier)
1076
+        and lire_fichier($src = "$fichier.src", $source)
1077
+        and $valeurs = unserialize($source)
1078
+        and ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
1079
+    ) {
1080
+        spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
1081
+        $reconstruire[] = $valeurs['reconstruction'];
1082
+    }
1083
+    while (count($reconstruire)) {
1084
+        $r = array_pop($reconstruire);
1085
+        $fonction = $r[0];
1086
+        $args = $r[1];
1087
+        $fonction(...$args);
1088
+    }
1089
+    // cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
1090
+    // mais l'on peut nettoyer les miettes de sa creation
1091
+    ramasse_miettes($fichier_manquant);
1092 1092
 }
1093 1093
 
1094 1094
 /**
@@ -1108,28 +1108,28 @@  discard block
 block discarded – undo
1108 1108
  *     Chemin du fichier d'image calculé
1109 1109
  **/
1110 1110
 function ramasse_miettes($fichier) {
1111
-	if (
1112
-		strpos($fichier, '://') !== false
1113
-		or !lire_fichier($src = "$fichier.src", $source)
1114
-		or !$valeurs = unserialize($source)
1115
-	) {
1116
-		return;
1117
-	}
1118
-	spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
1119
-	while (
1120
-		($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
1121
-		and (substr($fichier, 0, strlen(_DIR_VAR)) == _DIR_VAR) # et est dans local
1122
-		and (lire_fichier(
1123
-			$src = "$fichier.src",
1124
-			$source
1125
-		)) # le fichier a une source connue (c'est donc une image calculee intermediaire)
1126
-		and ($valeurs = unserialize($source))  # et valide
1127
-	) {
1128
-		# on efface le fichier
1129
-		spip_unlink($fichier);
1130
-		# mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
1131
-		#spip_unlink($src);
1132
-	}
1111
+    if (
1112
+        strpos($fichier, '://') !== false
1113
+        or !lire_fichier($src = "$fichier.src", $source)
1114
+        or !$valeurs = unserialize($source)
1115
+    ) {
1116
+        return;
1117
+    }
1118
+    spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
1119
+    while (
1120
+        ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
1121
+        and (substr($fichier, 0, strlen(_DIR_VAR)) == _DIR_VAR) # et est dans local
1122
+        and (lire_fichier(
1123
+            $src = "$fichier.src",
1124
+            $source
1125
+        )) # le fichier a une source connue (c'est donc une image calculee intermediaire)
1126
+        and ($valeurs = unserialize($source))  # et valide
1127
+    ) {
1128
+        # on efface le fichier
1129
+        spip_unlink($fichier);
1130
+        # mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
1131
+        #spip_unlink($src);
1132
+    }
1133 1133
 }
1134 1134
 
1135 1135
 
@@ -1154,31 +1154,31 @@  discard block
 block discarded – undo
1154 1154
  *     Code HTML de l'image
1155 1155
  **/
1156 1156
 function image_graver($img) {
1157
-	// appeler le filtre post_image_filtrer qui permet de faire
1158
-	// des traitements auto a la fin d'une serie de filtres
1159
-	$img = pipeline('post_image_filtrer', $img);
1160
-
1161
-	$fichier_ori = $fichier = extraire_attribut($img, 'src');
1162
-	if (($p = strpos($fichier, '?')) !== false) {
1163
-		$fichier = substr($fichier, 0, $p);
1164
-	}
1165
-	if (strlen($fichier) < 1) {
1166
-		$fichier = $img;
1167
-	}
1168
-	# si jamais le fichier final n'a pas ete calcule car suppose temporaire
1169
-	# et qu'il ne s'agit pas d'une URL
1170
-	if (strpos($fichier, '://') === false and !@file_exists($fichier)) {
1171
-		reconstruire_image_intermediaire($fichier);
1172
-	}
1173
-	ramasse_miettes($fichier);
1174
-
1175
-	// ajouter le timestamp si besoin
1176
-	if (strpos($fichier_ori, '?') === false) {
1177
-		// on utilise str_replace pour attraper le onmouseover des logo si besoin
1178
-		$img = str_replace($fichier_ori, timestamp($fichier_ori), $img);
1179
-	}
1180
-
1181
-	return $img;
1157
+    // appeler le filtre post_image_filtrer qui permet de faire
1158
+    // des traitements auto a la fin d'une serie de filtres
1159
+    $img = pipeline('post_image_filtrer', $img);
1160
+
1161
+    $fichier_ori = $fichier = extraire_attribut($img, 'src');
1162
+    if (($p = strpos($fichier, '?')) !== false) {
1163
+        $fichier = substr($fichier, 0, $p);
1164
+    }
1165
+    if (strlen($fichier) < 1) {
1166
+        $fichier = $img;
1167
+    }
1168
+    # si jamais le fichier final n'a pas ete calcule car suppose temporaire
1169
+    # et qu'il ne s'agit pas d'une URL
1170
+    if (strpos($fichier, '://') === false and !@file_exists($fichier)) {
1171
+        reconstruire_image_intermediaire($fichier);
1172
+    }
1173
+    ramasse_miettes($fichier);
1174
+
1175
+    // ajouter le timestamp si besoin
1176
+    if (strpos($fichier_ori, '?') === false) {
1177
+        // on utilise str_replace pour attraper le onmouseover des logo si besoin
1178
+        $img = str_replace($fichier_ori, timestamp($fichier_ori), $img);
1179
+    }
1180
+
1181
+    return $img;
1182 1182
 }
1183 1183
 
1184 1184
 /**
@@ -1205,34 +1205,34 @@  discard block
 block discarded – undo
1205 1205
  *     Code html modifié de la balise.
1206 1206
  **/
1207 1207
 function _image_tag_changer_taille($tag, $width, $height, $style = false) {
1208
-	if ($style === false) {
1209
-		$style = extraire_attribut($tag, 'style');
1210
-	}
1211
-
1212
-	// enlever le width et height du style
1213
-	if ($style) {
1214
-		$style = preg_replace(',(^|;)\s*(width|height)\s*:\s*[^;]+,ims', '', $style);
1215
-	}
1216
-	if ($style and $style[0] === ';') {
1217
-		$style = substr($style, 1);
1218
-	}
1219
-
1220
-	// mettre des attributs de width et height sur les images,
1221
-	// ca accelere le rendu du navigateur
1222
-	// ca permet aux navigateurs de reserver la bonne taille
1223
-	// quand on a desactive l'affichage des images.
1224
-	$tag = inserer_attribut($tag, 'width', round($width));
1225
-	$tag = inserer_attribut($tag, 'height', round($height));
1226
-
1227
-	// attributs deprecies. Transformer en CSS
1228
-	if ($espace = extraire_attribut($tag, 'hspace')) {
1229
-		$style = "margin:${espace}px;" . $style;
1230
-		$tag = inserer_attribut($tag, 'hspace', '');
1231
-	}
1232
-
1233
-	$tag = inserer_attribut($tag, 'style', (string) $style, true, $style ? false : true);
1234
-
1235
-	return $tag;
1208
+    if ($style === false) {
1209
+        $style = extraire_attribut($tag, 'style');
1210
+    }
1211
+
1212
+    // enlever le width et height du style
1213
+    if ($style) {
1214
+        $style = preg_replace(',(^|;)\s*(width|height)\s*:\s*[^;]+,ims', '', $style);
1215
+    }
1216
+    if ($style and $style[0] === ';') {
1217
+        $style = substr($style, 1);
1218
+    }
1219
+
1220
+    // mettre des attributs de width et height sur les images,
1221
+    // ca accelere le rendu du navigateur
1222
+    // ca permet aux navigateurs de reserver la bonne taille
1223
+    // quand on a desactive l'affichage des images.
1224
+    $tag = inserer_attribut($tag, 'width', round($width));
1225
+    $tag = inserer_attribut($tag, 'height', round($height));
1226
+
1227
+    // attributs deprecies. Transformer en CSS
1228
+    if ($espace = extraire_attribut($tag, 'hspace')) {
1229
+        $style = "margin:${espace}px;" . $style;
1230
+        $tag = inserer_attribut($tag, 'hspace', '');
1231
+    }
1232
+
1233
+    $tag = inserer_attribut($tag, 'style', (string) $style, true, $style ? false : true);
1234
+
1235
+    return $tag;
1236 1236
 }
1237 1237
 
1238 1238
 
@@ -1258,72 +1258,72 @@  discard block
 block discarded – undo
1258 1258
  *     Retourne le code HTML de l'image
1259 1259
  **/
1260 1260
 function _image_ecrire_tag($valeurs, $surcharge = []) {
1261
-	$valeurs = pipeline('image_ecrire_tag_preparer', $valeurs);
1262
-
1263
-	// fermer les tags img pas bien fermes;
1264
-	$tag = str_replace('>', '/>', str_replace('/>', '>', $valeurs['tag']));
1265
-
1266
-	// le style
1267
-	$style = $valeurs['style'];
1268
-	if (isset($surcharge['style'])) {
1269
-		$style = $surcharge['style'];
1270
-		unset($surcharge['style']);
1271
-	}
1272
-
1273
-	// traiter specifiquement la largeur et la hauteur
1274
-	$width = $valeurs['largeur'];
1275
-	if (isset($surcharge['width'])) {
1276
-		$width = $surcharge['width'];
1277
-		unset($surcharge['width']);
1278
-	}
1279
-	$height = $valeurs['hauteur'];
1280
-	if (isset($surcharge['height'])) {
1281
-		$height = $surcharge['height'];
1282
-		unset($surcharge['height']);
1283
-	}
1284
-
1285
-	$tag = _image_tag_changer_taille($tag, $width, $height, $style);
1286
-	// traiter specifiquement le src qui peut etre repris dans un onmouseout
1287
-	// on remplace toute les ref a src dans le tag
1288
-	$src = extraire_attribut($tag, 'src');
1289
-	if (isset($surcharge['src'])) {
1290
-		$tag = str_replace($src, $surcharge['src'], $tag);
1291
-		// si il y a des & dans src, alors ils peuvent provenir d'un &amp
1292
-		// pas garanti comme methode, mais mieux que rien
1293
-		if (strpos($src, '&') !== false) {
1294
-			$tag = str_replace(str_replace('&', '&amp;', $src), $surcharge['src'], $tag);
1295
-		}
1296
-		$src = $surcharge['src'];
1297
-		unset($surcharge['src']);
1298
-	}
1299
-
1300
-	$class = $valeurs['class'];
1301
-	if (isset($surcharge['class'])) {
1302
-		$class = $surcharge['class'];
1303
-		unset($surcharge['class']);
1304
-	}
1305
-	if (is_scalar($class) && strlen($class)) {
1306
-		$tag = inserer_attribut($tag, 'class', $class);
1307
-	}
1308
-
1309
-	if (count($surcharge)) {
1310
-		foreach ($surcharge as $attribut => $valeur) {
1311
-			$tag = inserer_attribut($tag, $attribut, $valeur);
1312
-		}
1313
-	}
1314
-
1315
-	$tag = pipeline(
1316
-		'image_ecrire_tag_finir',
1317
-		[
1318
-			'args' => [
1319
-				'valeurs' => $valeurs,
1320
-				'surcharge' => $surcharge,
1321
-			],
1322
-			'data' => $tag
1323
-		]
1324
-	);
1325
-
1326
-	return $tag;
1261
+    $valeurs = pipeline('image_ecrire_tag_preparer', $valeurs);
1262
+
1263
+    // fermer les tags img pas bien fermes;
1264
+    $tag = str_replace('>', '/>', str_replace('/>', '>', $valeurs['tag']));
1265
+
1266
+    // le style
1267
+    $style = $valeurs['style'];
1268
+    if (isset($surcharge['style'])) {
1269
+        $style = $surcharge['style'];
1270
+        unset($surcharge['style']);
1271
+    }
1272
+
1273
+    // traiter specifiquement la largeur et la hauteur
1274
+    $width = $valeurs['largeur'];
1275
+    if (isset($surcharge['width'])) {
1276
+        $width = $surcharge['width'];
1277
+        unset($surcharge['width']);
1278
+    }
1279
+    $height = $valeurs['hauteur'];
1280
+    if (isset($surcharge['height'])) {
1281
+        $height = $surcharge['height'];
1282
+        unset($surcharge['height']);
1283
+    }
1284
+
1285
+    $tag = _image_tag_changer_taille($tag, $width, $height, $style);
1286
+    // traiter specifiquement le src qui peut etre repris dans un onmouseout
1287
+    // on remplace toute les ref a src dans le tag
1288
+    $src = extraire_attribut($tag, 'src');
1289
+    if (isset($surcharge['src'])) {
1290
+        $tag = str_replace($src, $surcharge['src'], $tag);
1291
+        // si il y a des & dans src, alors ils peuvent provenir d'un &amp
1292
+        // pas garanti comme methode, mais mieux que rien
1293
+        if (strpos($src, '&') !== false) {
1294
+            $tag = str_replace(str_replace('&', '&amp;', $src), $surcharge['src'], $tag);
1295
+        }
1296
+        $src = $surcharge['src'];
1297
+        unset($surcharge['src']);
1298
+    }
1299
+
1300
+    $class = $valeurs['class'];
1301
+    if (isset($surcharge['class'])) {
1302
+        $class = $surcharge['class'];
1303
+        unset($surcharge['class']);
1304
+    }
1305
+    if (is_scalar($class) && strlen($class)) {
1306
+        $tag = inserer_attribut($tag, 'class', $class);
1307
+    }
1308
+
1309
+    if (count($surcharge)) {
1310
+        foreach ($surcharge as $attribut => $valeur) {
1311
+            $tag = inserer_attribut($tag, $attribut, $valeur);
1312
+        }
1313
+    }
1314
+
1315
+    $tag = pipeline(
1316
+        'image_ecrire_tag_finir',
1317
+        [
1318
+            'args' => [
1319
+                'valeurs' => $valeurs,
1320
+                'surcharge' => $surcharge,
1321
+            ],
1322
+            'data' => $tag
1323
+        ]
1324
+    );
1325
+
1326
+    return $tag;
1327 1327
 }
1328 1328
 
1329 1329
 /**
@@ -1346,267 +1346,267 @@  discard block
 block discarded – undo
1346 1346
  *     Description de l'image, sinon null.
1347 1347
  **/
1348 1348
 function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process = 'AUTO', $force = false) {
1349
-	$srcHeight = null;
1350
-	$retour = [];
1351
-	// ordre de preference des formats graphiques pour creer les vignettes
1352
-	// le premier format disponible, selon la methode demandee, est utilise
1353
-	$image = $valeurs['fichier'];
1354
-	$format = $valeurs['format_source'];
1355
-	$destdir = dirname($valeurs['fichier_dest']);
1356
-	$destfile = basename($valeurs['fichier_dest'], '.' . $valeurs['format_dest']);
1357
-
1358
-	$format_sortie = $valeurs['format_dest'];
1359
-
1360
-	if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) {
1361
-		$process = $GLOBALS['meta']['image_process'];
1362
-	}
1363
-
1364
-	// si le doc n'est pas une image dans un format accetpable, refuser
1365
-	if (!$force and !in_array($format, formats_image_acceptables(in_array($process, ['gd1', 'gd2'])))) {
1366
-		return;
1367
-	}
1368
-	$destination = "$destdir/$destfile";
1369
-
1370
-	// calculer la taille
1371
-	if (($srcWidth = $valeurs['largeur']) && ($srcHeight = $valeurs['hauteur'])) {
1372
-		if (!($destWidth = $valeurs['largeur_dest']) || !($destHeight = $valeurs['hauteur_dest'])) {
1373
-			[$destWidth, $destHeight] = _image_ratio($srcWidth, $srcHeight, $maxWidth, $maxHeight);
1374
-		}
1375
-	} elseif ($process == 'convert' or $process == 'imagick') {
1376
-		$destWidth = $maxWidth;
1377
-		$destHeight = $maxHeight;
1378
-	} else {
1379
-		spip_log("echec $process sur $image");
1380
-
1381
-		return;
1382
-	}
1383
-
1384
-	$vignette = '';
1385
-
1386
-	// Si l'image est de la taille demandee (ou plus petite), simplement la retourner
1387
-	if ($srcWidth and $srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1388
-		$vignette = $destination . '.' . $format;
1389
-		@copy($image, $vignette);
1390
-	}
1391
-
1392
-	elseif ($valeurs['format_source'] === 'svg') {
1393
-		if ($svg = svg_redimensionner($valeurs['fichier'], $destWidth, $destHeight)) {
1394
-			$format_sortie = 'svg';
1395
-			$vignette = $destination . '.' . $format_sortie;
1396
-			$valeurs['fichier_dest'] = $vignette;
1397
-			_image_gd_output($svg, $valeurs);
1398
-		}
1399
-	}
1400
-
1401
-	// imagemagick en ligne de commande
1402
-	elseif ($process == 'convert') {
1403
-		if (!defined('_CONVERT_COMMAND')) {
1404
-			define('_CONVERT_COMMAND', 'convert');
1405
-		} // Securite : mes_options.php peut preciser le chemin absolu
1406
-		if (!defined('_RESIZE_COMMAND')) {
1407
-			define('_RESIZE_COMMAND', _CONVERT_COMMAND . ' -quality ' . _IMG_CONVERT_QUALITE . ' -resize %xx%y! %src %dest');
1408
-		}
1409
-		$vignette = $destination . '.' . $format_sortie;
1410
-		$commande = str_replace(
1411
-			['%x', '%y', '%src', '%dest'],
1412
-			[
1413
-				$destWidth,
1414
-				$destHeight,
1415
-				escapeshellcmd($image),
1416
-				escapeshellcmd($vignette)
1417
-			],
1418
-			_RESIZE_COMMAND
1419
-		);
1420
-		spip_log($commande);
1421
-		exec($commande);
1422
-		if (!@file_exists($vignette)) {
1423
-			spip_log("echec convert sur $vignette");
1424
-
1425
-			return;  // echec commande
1426
-		}
1427
-	}
1428
-
1429
-	// php5 imagemagick
1430
-	elseif ($process == 'imagick') {
1431
-		if (!class_exists(\Imagick::class)) {
1432
-			spip_log('Classe Imagick absente !', _LOG_ERREUR);
1433
-
1434
-			return;
1435
-		}
1436
-
1437
-		// chemin compatible Windows
1438
-		$output = realpath(dirname($destination));
1439
-		if (!$output) {
1440
-			return;
1441
-		}
1442
-		$vignette = $output . DIRECTORY_SEPARATOR . basename($destination) . '.' . $format_sortie;
1443
-
1444
-		$imagick = new Imagick();
1445
-		$imagick->readImage(realpath($image));
1446
-		$imagick->resizeImage(
1447
-			$destWidth,
1448
-			$destHeight,
1449
-			Imagick::FILTER_LANCZOS,
1450
-			1
1451
-		);//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100);
1452
-		$imagick->writeImage($vignette);
1453
-
1454
-		if (!@file_exists($vignette)) {
1455
-			spip_log("echec imagick sur $vignette");
1456
-
1457
-			return;
1458
-		}
1459
-		// remettre le chemin relatif car c'est ce qu'attend SPIP pour la suite (en particlier action/tester)
1460
-		$vignette = $destination . '.' . $format_sortie;
1461
-	}
1462
-
1463
-	// netpbm
1464
-	elseif ($process == 'netpbm') {
1465
-		if (!defined('_PNMSCALE_COMMAND')) {
1466
-			define('_PNMSCALE_COMMAND', 'pnmscale');
1467
-		} // Securite : mes_options.php peut preciser le chemin absolu
1468
-		if (_PNMSCALE_COMMAND == '') {
1469
-			return;
1470
-		}
1471
-		$vignette = $destination . '.' . $format_sortie;
1472
-		$pnmtojpeg_command = str_replace('pnmscale', 'pnmtojpeg', _PNMSCALE_COMMAND);
1473
-		if ($format == 'jpg') {
1474
-			$jpegtopnm_command = str_replace('pnmscale', 'jpegtopnm', _PNMSCALE_COMMAND);
1475
-			exec("$jpegtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1476
-			if (!($s = @filesize($vignette))) {
1477
-				spip_unlink($vignette);
1478
-			}
1479
-			if (!@file_exists($vignette)) {
1480
-				spip_log("echec netpbm-jpg sur $vignette");
1481
-
1482
-				return;
1483
-			}
1484
-		} else {
1485
-			if ($format == 'gif') {
1486
-				$giftopnm_command = str_replace('pnmscale', 'giftopnm', _PNMSCALE_COMMAND);
1487
-				exec("$giftopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1488
-				if (!($s = @filesize($vignette))) {
1489
-					spip_unlink($vignette);
1490
-				}
1491
-				if (!@file_exists($vignette)) {
1492
-					spip_log("echec netpbm-gif sur $vignette");
1493
-
1494
-					return;
1495
-				}
1496
-			} else {
1497
-				if ($format == 'png') {
1498
-					$pngtopnm_command = str_replace('pnmscale', 'pngtopnm', _PNMSCALE_COMMAND);
1499
-					exec("$pngtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1500
-					if (!($s = @filesize($vignette))) {
1501
-						spip_unlink($vignette);
1502
-					}
1503
-					if (!@file_exists($vignette)) {
1504
-						spip_log("echec netpbm-png sur $vignette");
1505
-
1506
-						return;
1507
-					}
1508
-				}
1509
-			}
1510
-		}
1511
-	}
1512
-
1513
-	// gd ou gd2
1514
-	elseif ($process == 'gd1' or $process == 'gd2') {
1515
-		if (!function_exists('gd_info')) {
1516
-			spip_log('Librairie GD absente !', _LOG_ERREUR);
1517
-
1518
-			return;
1519
-		}
1520
-		if (_IMG_GD_MAX_PIXELS && $srcWidth * $srcHeight > _IMG_GD_MAX_PIXELS) {
1521
-			spip_log('vignette gd1/gd2 impossible : ' . $srcWidth * $srcHeight . 'pixels');
1522
-
1523
-			return;
1524
-		}
1525
-		$destFormat = $format_sortie;
1526
-		if (!$destFormat) {
1527
-			spip_log("pas de format pour $image");
1528
-
1529
-			return;
1530
-		}
1531
-
1532
-		$fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
1533
-		if (!function_exists($fonction_imagecreatefrom)) {
1534
-			return;
1535
-		}
1536
-		$srcImage = @$fonction_imagecreatefrom($image);
1537
-		if (!$srcImage) {
1538
-			spip_log('echec gd1/gd2');
1539
-
1540
-			return;
1541
-		}
1542
-
1543
-		// Initialisation de l'image destination
1544
-		$destImage = null;
1545
-		if ($process == 'gd2' and $destFormat != 'gif') {
1546
-			$destImage = ImageCreateTrueColor($destWidth, $destHeight);
1547
-		}
1548
-		if (!$destImage) {
1549
-			$destImage = ImageCreate($destWidth, $destHeight);
1550
-		}
1551
-
1552
-		// Recopie de l'image d'origine avec adaptation de la taille
1553
-		$ok = false;
1554
-		if (($process == 'gd2') and function_exists('ImageCopyResampled')) {
1555
-			if ($format == 'gif') {
1556
-				// Si un GIF est transparent,
1557
-				// fabriquer un PNG transparent
1558
-				$transp = imagecolortransparent($srcImage);
1559
-				if ($transp > 0) {
1560
-					$destFormat = 'png';
1561
-				}
1562
-			}
1563
-			if (in_array($destFormat, _image_extensions_conservent_transparence())) {
1564
-				// Conserver la transparence
1565
-				if (function_exists('imageAntiAlias')) {
1566
-					imageAntiAlias($destImage, true);
1567
-				}
1568
-				@imagealphablending($destImage, false);
1569
-				@imagesavealpha($destImage, true);
1570
-			}
1571
-			$ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1572
-		}
1573
-		if (!$ok) {
1574
-			$ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1575
-		}
1576
-
1577
-		// Sauvegarde de l'image destination
1578
-		$valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
1579
-		$valeurs['format_dest'] = $format = $destFormat;
1580
-		_image_gd_output($destImage, $valeurs);
1581
-
1582
-		if ($srcImage) {
1583
-			ImageDestroy($srcImage);
1584
-		}
1585
-		ImageDestroy($destImage);
1586
-	}
1587
-
1588
-	if (!$vignette or !$size = @spip_getimagesize($vignette)) {
1589
-		$size = [$destWidth, $destHeight];
1590
-	}
1591
-
1592
-	// Gaffe: en safe mode, pas d'acces a la vignette,
1593
-	// donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
1594
-	if ($size[0] < 1) {
1595
-		$size[0] = $destWidth;
1596
-	}
1597
-	if ($size[1] < 1) {
1598
-		$size[1] = $destHeight;
1599
-	}
1600
-
1601
-	$retour['width'] = $largeur = $size[0];
1602
-	$retour['height'] = $hauteur = $size[1];
1603
-
1604
-	$retour['fichier'] = $vignette;
1605
-	$retour['format'] = $format;
1606
-	$retour['date'] = @filemtime($vignette);
1607
-
1608
-	// renvoyer l'image
1609
-	return $retour;
1349
+    $srcHeight = null;
1350
+    $retour = [];
1351
+    // ordre de preference des formats graphiques pour creer les vignettes
1352
+    // le premier format disponible, selon la methode demandee, est utilise
1353
+    $image = $valeurs['fichier'];
1354
+    $format = $valeurs['format_source'];
1355
+    $destdir = dirname($valeurs['fichier_dest']);
1356
+    $destfile = basename($valeurs['fichier_dest'], '.' . $valeurs['format_dest']);
1357
+
1358
+    $format_sortie = $valeurs['format_dest'];
1359
+
1360
+    if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) {
1361
+        $process = $GLOBALS['meta']['image_process'];
1362
+    }
1363
+
1364
+    // si le doc n'est pas une image dans un format accetpable, refuser
1365
+    if (!$force and !in_array($format, formats_image_acceptables(in_array($process, ['gd1', 'gd2'])))) {
1366
+        return;
1367
+    }
1368
+    $destination = "$destdir/$destfile";
1369
+
1370
+    // calculer la taille
1371
+    if (($srcWidth = $valeurs['largeur']) && ($srcHeight = $valeurs['hauteur'])) {
1372
+        if (!($destWidth = $valeurs['largeur_dest']) || !($destHeight = $valeurs['hauteur_dest'])) {
1373
+            [$destWidth, $destHeight] = _image_ratio($srcWidth, $srcHeight, $maxWidth, $maxHeight);
1374
+        }
1375
+    } elseif ($process == 'convert' or $process == 'imagick') {
1376
+        $destWidth = $maxWidth;
1377
+        $destHeight = $maxHeight;
1378
+    } else {
1379
+        spip_log("echec $process sur $image");
1380
+
1381
+        return;
1382
+    }
1383
+
1384
+    $vignette = '';
1385
+
1386
+    // Si l'image est de la taille demandee (ou plus petite), simplement la retourner
1387
+    if ($srcWidth and $srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1388
+        $vignette = $destination . '.' . $format;
1389
+        @copy($image, $vignette);
1390
+    }
1391
+
1392
+    elseif ($valeurs['format_source'] === 'svg') {
1393
+        if ($svg = svg_redimensionner($valeurs['fichier'], $destWidth, $destHeight)) {
1394
+            $format_sortie = 'svg';
1395
+            $vignette = $destination . '.' . $format_sortie;
1396
+            $valeurs['fichier_dest'] = $vignette;
1397
+            _image_gd_output($svg, $valeurs);
1398
+        }
1399
+    }
1400
+
1401
+    // imagemagick en ligne de commande
1402
+    elseif ($process == 'convert') {
1403
+        if (!defined('_CONVERT_COMMAND')) {
1404
+            define('_CONVERT_COMMAND', 'convert');
1405
+        } // Securite : mes_options.php peut preciser le chemin absolu
1406
+        if (!defined('_RESIZE_COMMAND')) {
1407
+            define('_RESIZE_COMMAND', _CONVERT_COMMAND . ' -quality ' . _IMG_CONVERT_QUALITE . ' -resize %xx%y! %src %dest');
1408
+        }
1409
+        $vignette = $destination . '.' . $format_sortie;
1410
+        $commande = str_replace(
1411
+            ['%x', '%y', '%src', '%dest'],
1412
+            [
1413
+                $destWidth,
1414
+                $destHeight,
1415
+                escapeshellcmd($image),
1416
+                escapeshellcmd($vignette)
1417
+            ],
1418
+            _RESIZE_COMMAND
1419
+        );
1420
+        spip_log($commande);
1421
+        exec($commande);
1422
+        if (!@file_exists($vignette)) {
1423
+            spip_log("echec convert sur $vignette");
1424
+
1425
+            return;  // echec commande
1426
+        }
1427
+    }
1428
+
1429
+    // php5 imagemagick
1430
+    elseif ($process == 'imagick') {
1431
+        if (!class_exists(\Imagick::class)) {
1432
+            spip_log('Classe Imagick absente !', _LOG_ERREUR);
1433
+
1434
+            return;
1435
+        }
1436
+
1437
+        // chemin compatible Windows
1438
+        $output = realpath(dirname($destination));
1439
+        if (!$output) {
1440
+            return;
1441
+        }
1442
+        $vignette = $output . DIRECTORY_SEPARATOR . basename($destination) . '.' . $format_sortie;
1443
+
1444
+        $imagick = new Imagick();
1445
+        $imagick->readImage(realpath($image));
1446
+        $imagick->resizeImage(
1447
+            $destWidth,
1448
+            $destHeight,
1449
+            Imagick::FILTER_LANCZOS,
1450
+            1
1451
+        );//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100);
1452
+        $imagick->writeImage($vignette);
1453
+
1454
+        if (!@file_exists($vignette)) {
1455
+            spip_log("echec imagick sur $vignette");
1456
+
1457
+            return;
1458
+        }
1459
+        // remettre le chemin relatif car c'est ce qu'attend SPIP pour la suite (en particlier action/tester)
1460
+        $vignette = $destination . '.' . $format_sortie;
1461
+    }
1462
+
1463
+    // netpbm
1464
+    elseif ($process == 'netpbm') {
1465
+        if (!defined('_PNMSCALE_COMMAND')) {
1466
+            define('_PNMSCALE_COMMAND', 'pnmscale');
1467
+        } // Securite : mes_options.php peut preciser le chemin absolu
1468
+        if (_PNMSCALE_COMMAND == '') {
1469
+            return;
1470
+        }
1471
+        $vignette = $destination . '.' . $format_sortie;
1472
+        $pnmtojpeg_command = str_replace('pnmscale', 'pnmtojpeg', _PNMSCALE_COMMAND);
1473
+        if ($format == 'jpg') {
1474
+            $jpegtopnm_command = str_replace('pnmscale', 'jpegtopnm', _PNMSCALE_COMMAND);
1475
+            exec("$jpegtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1476
+            if (!($s = @filesize($vignette))) {
1477
+                spip_unlink($vignette);
1478
+            }
1479
+            if (!@file_exists($vignette)) {
1480
+                spip_log("echec netpbm-jpg sur $vignette");
1481
+
1482
+                return;
1483
+            }
1484
+        } else {
1485
+            if ($format == 'gif') {
1486
+                $giftopnm_command = str_replace('pnmscale', 'giftopnm', _PNMSCALE_COMMAND);
1487
+                exec("$giftopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1488
+                if (!($s = @filesize($vignette))) {
1489
+                    spip_unlink($vignette);
1490
+                }
1491
+                if (!@file_exists($vignette)) {
1492
+                    spip_log("echec netpbm-gif sur $vignette");
1493
+
1494
+                    return;
1495
+                }
1496
+            } else {
1497
+                if ($format == 'png') {
1498
+                    $pngtopnm_command = str_replace('pnmscale', 'pngtopnm', _PNMSCALE_COMMAND);
1499
+                    exec("$pngtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1500
+                    if (!($s = @filesize($vignette))) {
1501
+                        spip_unlink($vignette);
1502
+                    }
1503
+                    if (!@file_exists($vignette)) {
1504
+                        spip_log("echec netpbm-png sur $vignette");
1505
+
1506
+                        return;
1507
+                    }
1508
+                }
1509
+            }
1510
+        }
1511
+    }
1512
+
1513
+    // gd ou gd2
1514
+    elseif ($process == 'gd1' or $process == 'gd2') {
1515
+        if (!function_exists('gd_info')) {
1516
+            spip_log('Librairie GD absente !', _LOG_ERREUR);
1517
+
1518
+            return;
1519
+        }
1520
+        if (_IMG_GD_MAX_PIXELS && $srcWidth * $srcHeight > _IMG_GD_MAX_PIXELS) {
1521
+            spip_log('vignette gd1/gd2 impossible : ' . $srcWidth * $srcHeight . 'pixels');
1522
+
1523
+            return;
1524
+        }
1525
+        $destFormat = $format_sortie;
1526
+        if (!$destFormat) {
1527
+            spip_log("pas de format pour $image");
1528
+
1529
+            return;
1530
+        }
1531
+
1532
+        $fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
1533
+        if (!function_exists($fonction_imagecreatefrom)) {
1534
+            return;
1535
+        }
1536
+        $srcImage = @$fonction_imagecreatefrom($image);
1537
+        if (!$srcImage) {
1538
+            spip_log('echec gd1/gd2');
1539
+
1540
+            return;
1541
+        }
1542
+
1543
+        // Initialisation de l'image destination
1544
+        $destImage = null;
1545
+        if ($process == 'gd2' and $destFormat != 'gif') {
1546
+            $destImage = ImageCreateTrueColor($destWidth, $destHeight);
1547
+        }
1548
+        if (!$destImage) {
1549
+            $destImage = ImageCreate($destWidth, $destHeight);
1550
+        }
1551
+
1552
+        // Recopie de l'image d'origine avec adaptation de la taille
1553
+        $ok = false;
1554
+        if (($process == 'gd2') and function_exists('ImageCopyResampled')) {
1555
+            if ($format == 'gif') {
1556
+                // Si un GIF est transparent,
1557
+                // fabriquer un PNG transparent
1558
+                $transp = imagecolortransparent($srcImage);
1559
+                if ($transp > 0) {
1560
+                    $destFormat = 'png';
1561
+                }
1562
+            }
1563
+            if (in_array($destFormat, _image_extensions_conservent_transparence())) {
1564
+                // Conserver la transparence
1565
+                if (function_exists('imageAntiAlias')) {
1566
+                    imageAntiAlias($destImage, true);
1567
+                }
1568
+                @imagealphablending($destImage, false);
1569
+                @imagesavealpha($destImage, true);
1570
+            }
1571
+            $ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1572
+        }
1573
+        if (!$ok) {
1574
+            $ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1575
+        }
1576
+
1577
+        // Sauvegarde de l'image destination
1578
+        $valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
1579
+        $valeurs['format_dest'] = $format = $destFormat;
1580
+        _image_gd_output($destImage, $valeurs);
1581
+
1582
+        if ($srcImage) {
1583
+            ImageDestroy($srcImage);
1584
+        }
1585
+        ImageDestroy($destImage);
1586
+    }
1587
+
1588
+    if (!$vignette or !$size = @spip_getimagesize($vignette)) {
1589
+        $size = [$destWidth, $destHeight];
1590
+    }
1591
+
1592
+    // Gaffe: en safe mode, pas d'acces a la vignette,
1593
+    // donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
1594
+    if ($size[0] < 1) {
1595
+        $size[0] = $destWidth;
1596
+    }
1597
+    if ($size[1] < 1) {
1598
+        $size[1] = $destHeight;
1599
+    }
1600
+
1601
+    $retour['width'] = $largeur = $size[0];
1602
+    $retour['height'] = $hauteur = $size[1];
1603
+
1604
+    $retour['fichier'] = $vignette;
1605
+    $retour['format'] = $format;
1606
+    $retour['date'] = @filemtime($vignette);
1607
+
1608
+    // renvoyer l'image
1609
+    return $retour;
1610 1610
 }
1611 1611
 
1612 1612
 /**
@@ -1626,25 +1626,25 @@  discard block
 block discarded – undo
1626 1626
  * @return array Liste [ largeur, hauteur, ratio de réduction ]
1627 1627
  **/
1628 1628
 function _image_ratio(int $srcWidth, int $srcHeight, int $maxWidth, int $maxHeight): array {
1629
-	$ratioWidth = $srcWidth / $maxWidth;
1630
-	$ratioHeight = $srcHeight / $maxHeight;
1631
-
1632
-	if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1633
-		$destWidth = $srcWidth;
1634
-		$destHeight = $srcHeight;
1635
-	} elseif ($ratioWidth < $ratioHeight) {
1636
-		$destWidth = $srcWidth / $ratioHeight;
1637
-		$destHeight = $maxHeight;
1638
-	} else {
1639
-		$destWidth = $maxWidth;
1640
-		$destHeight = $srcHeight / $ratioWidth;
1641
-	}
1642
-
1643
-	return [
1644
-		intval(round($destWidth)),
1645
-		intval(round($destHeight)),
1646
-		max($ratioWidth, $ratioHeight)
1647
-	];
1629
+    $ratioWidth = $srcWidth / $maxWidth;
1630
+    $ratioHeight = $srcHeight / $maxHeight;
1631
+
1632
+    if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1633
+        $destWidth = $srcWidth;
1634
+        $destHeight = $srcHeight;
1635
+    } elseif ($ratioWidth < $ratioHeight) {
1636
+        $destWidth = $srcWidth / $ratioHeight;
1637
+        $destHeight = $maxHeight;
1638
+    } else {
1639
+        $destWidth = $maxWidth;
1640
+        $destHeight = $srcHeight / $ratioWidth;
1641
+    }
1642
+
1643
+    return [
1644
+        intval(round($destWidth)),
1645
+        intval(round($destHeight)),
1646
+        max($ratioWidth, $ratioHeight)
1647
+    ];
1648 1648
 }
1649 1649
 
1650 1650
 /**
@@ -1664,25 +1664,25 @@  discard block
 block discarded – undo
1664 1664
  * @return array Liste [ largeur, hauteur, ratio de réduction ]
1665 1665
  **/
1666 1666
 function ratio_passe_partout(int $srcWidth, int $srcHeight, int $maxWidth, int $maxHeight): array {
1667
-	$ratioWidth = $srcWidth / $maxWidth;
1668
-	$ratioHeight = $srcHeight / $maxHeight;
1669
-
1670
-	if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1671
-		$destWidth = $srcWidth;
1672
-		$destHeight = $srcHeight;
1673
-	} elseif ($ratioWidth > $ratioHeight) {
1674
-		$destWidth = $srcWidth / $ratioHeight;
1675
-		$destHeight = $maxHeight;
1676
-	} else {
1677
-		$destWidth = $maxWidth;
1678
-		$destHeight = $srcHeight / $ratioWidth;
1679
-	}
1680
-
1681
-	return [
1682
-		intval(round($destWidth)),
1683
-		intval(round($destHeight)),
1684
-		min($ratioWidth, $ratioHeight)
1685
-	];
1667
+    $ratioWidth = $srcWidth / $maxWidth;
1668
+    $ratioHeight = $srcHeight / $maxHeight;
1669
+
1670
+    if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1671
+        $destWidth = $srcWidth;
1672
+        $destHeight = $srcHeight;
1673
+    } elseif ($ratioWidth > $ratioHeight) {
1674
+        $destWidth = $srcWidth / $ratioHeight;
1675
+        $destHeight = $maxHeight;
1676
+    } else {
1677
+        $destWidth = $maxWidth;
1678
+        $destHeight = $srcHeight / $ratioWidth;
1679
+    }
1680
+
1681
+    return [
1682
+        intval(round($destWidth)),
1683
+        intval(round($destHeight)),
1684
+        min($ratioWidth, $ratioHeight)
1685
+    ];
1686 1686
 }
1687 1687
 
1688 1688
 
@@ -1695,12 +1695,12 @@  discard block
 block discarded – undo
1695 1695
  * @return string
1696 1696
  */
1697 1697
 function process_image_svg_identite($image) {
1698
-	if ($image['creer']) {
1699
-		$source = $image['fichier'];
1700
-		_image_gd_output($source, $image);
1701
-	}
1698
+    if ($image['creer']) {
1699
+        $source = $image['fichier'];
1700
+        _image_gd_output($source, $image);
1701
+    }
1702 1702
 
1703
-	return _image_ecrire_tag($image, ['src' => $image['fichier_dest']]);
1703
+    return _image_ecrire_tag($image, ['src' => $image['fichier_dest']]);
1704 1704
 }
1705 1705
 
1706 1706
 
@@ -1733,109 +1733,109 @@  discard block
 block discarded – undo
1733 1733
  *     Code HTML de la balise img produite
1734 1734
  **/
1735 1735
 function process_image_reduire($fonction, $img, $taille, $taille_y, $force, $process = 'AUTO') {
1736
-	$image = false;
1737
-	if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) {
1738
-		$process = $GLOBALS['meta']['image_process'];
1739
-	}
1740
-	# determiner le format de sortie
1741
-	$format_sortie = false; // le choix par defaut sera bon
1742
-	if ($process == 'netpbm') {
1743
-		$format_sortie = 'jpg';
1744
-	} elseif ($process == 'gd1' or $process == 'gd2') {
1745
-		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1746
-		// on verifie que l'extension choisie est bonne (en principe oui)
1747
-		$gd_formats = formats_image_acceptables(true);
1748
-		if (
1749
-			is_array($image)
1750
-			and (!in_array($image['format_dest'], $gd_formats)
1751
-				or (!in_array($image['format_dest'], _image_extensions_acceptees_en_sortie()))
1752
-			)
1753
-		) {
1754
-			if ($image['format_source'] == 'jpg') {
1755
-				$formats_sortie = ['jpg', 'png', 'gif'];
1756
-			} else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
1757
-			{
1758
-				$formats_sortie = ['png', 'jpg', 'gif'];
1759
-			}
1760
-			// Choisir le format destination
1761
-			// - on sauve de preference en JPEG (meilleure compression)
1762
-			// - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
1763
-			# bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
1764
-			# pas *ecrire*
1765
-			$format_sortie = '';
1766
-			foreach ($formats_sortie as $fmt) {
1767
-				if (in_array($fmt, $gd_formats) and in_array($fmt, _image_extensions_acceptees_en_sortie())) {
1768
-					$format_sortie = $fmt;
1769
-					break;
1770
-				}
1771
-			}
1772
-			$image = false;
1773
-		}
1774
-	}
1775
-
1776
-	if (!is_array($image)) {
1777
-		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1778
-	}
1779
-
1780
-	if (!is_array($image) or !$image['largeur'] or !$image['hauteur']) {
1781
-		spip_log("image_reduire_src:pas de version locale de $img ou extension non prise en charge");
1782
-		// on peut resizer en mode html si on dispose des elements
1783
-		[$srcw, $srch] = taille_image($img);
1784
-		if ($srcw and $srch) {
1785
-			[$w, $h] = _image_ratio($srcw, $srch, $taille, $taille_y);
1786
-
1787
-			return _image_tag_changer_taille($img, $w, $h);
1788
-		}
1789
-		// la on n'a pas d'infos sur l'image source... on refile le truc a css
1790
-		// sous la forme style='max-width: NNpx;'
1791
-		return inserer_attribut(
1792
-			$img,
1793
-			'style',
1794
-			"max-width: ${taille}px;max-width: min(100%,${taille}px); max-height: ${taille_y}px"
1795
-		);
1796
-	}
1797
-
1798
-	// si l'image est plus petite que la cible retourner une copie cachee de l'image
1799
-	if (($image['largeur'] <= $taille) && ($image['hauteur'] <= $taille_y)) {
1800
-		if ($image['creer']) {
1801
-			@copy($image['fichier'], $image['fichier_dest']);
1802
-		}
1803
-
1804
-		return _image_ecrire_tag($image, ['src' => $image['fichier_dest']]);
1805
-	}
1806
-
1807
-	if ($image['creer'] == false && !$force) {
1808
-		return _image_ecrire_tag(
1809
-			$image,
1810
-			['src' => $image['fichier_dest'], 'width' => $image['largeur_dest'], 'height' => $image['hauteur_dest']]
1811
-		);
1812
-	}
1813
-
1814
-	if (in_array($image['format_source'], _image_extensions_acceptees_en_entree())) {
1815
-		$destWidth = $image['largeur_dest'];
1816
-		$destHeight = $image['hauteur_dest'];
1817
-		$logo = $image['fichier'];
1818
-		$date = $image['date_src'];
1819
-		$preview = _image_creer_vignette($image, $taille, $taille_y, $process, $force);
1820
-
1821
-		if ($preview && $preview['fichier']) {
1822
-			$logo = $preview['fichier'];
1823
-			$destWidth = $preview['width'];
1824
-			$destHeight = $preview['height'];
1825
-			$date = $preview['date'];
1826
-		}
1827
-		// dans l'espace prive mettre un timestamp sur l'adresse
1828
-		// de l'image, de facon a tromper le cache du navigateur
1829
-		// quand on fait supprimer/reuploader un logo
1830
-		// (pas de filemtime si SAFE MODE)
1831
-		$date = test_espace_prive() ? ('?' . $date) : '';
1832
-
1833
-		return _image_ecrire_tag($image, ['src' => "$logo$date", 'width' => $destWidth, 'height' => $destHeight]);
1834
-	}
1835
-	else {
1836
-		# BMP, tiff ... les redacteurs osent tout!
1837
-		return $img;
1838
-	}
1736
+    $image = false;
1737
+    if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) {
1738
+        $process = $GLOBALS['meta']['image_process'];
1739
+    }
1740
+    # determiner le format de sortie
1741
+    $format_sortie = false; // le choix par defaut sera bon
1742
+    if ($process == 'netpbm') {
1743
+        $format_sortie = 'jpg';
1744
+    } elseif ($process == 'gd1' or $process == 'gd2') {
1745
+        $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1746
+        // on verifie que l'extension choisie est bonne (en principe oui)
1747
+        $gd_formats = formats_image_acceptables(true);
1748
+        if (
1749
+            is_array($image)
1750
+            and (!in_array($image['format_dest'], $gd_formats)
1751
+                or (!in_array($image['format_dest'], _image_extensions_acceptees_en_sortie()))
1752
+            )
1753
+        ) {
1754
+            if ($image['format_source'] == 'jpg') {
1755
+                $formats_sortie = ['jpg', 'png', 'gif'];
1756
+            } else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
1757
+            {
1758
+                $formats_sortie = ['png', 'jpg', 'gif'];
1759
+            }
1760
+            // Choisir le format destination
1761
+            // - on sauve de preference en JPEG (meilleure compression)
1762
+            // - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
1763
+            # bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
1764
+            # pas *ecrire*
1765
+            $format_sortie = '';
1766
+            foreach ($formats_sortie as $fmt) {
1767
+                if (in_array($fmt, $gd_formats) and in_array($fmt, _image_extensions_acceptees_en_sortie())) {
1768
+                    $format_sortie = $fmt;
1769
+                    break;
1770
+                }
1771
+            }
1772
+            $image = false;
1773
+        }
1774
+    }
1775
+
1776
+    if (!is_array($image)) {
1777
+        $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1778
+    }
1779
+
1780
+    if (!is_array($image) or !$image['largeur'] or !$image['hauteur']) {
1781
+        spip_log("image_reduire_src:pas de version locale de $img ou extension non prise en charge");
1782
+        // on peut resizer en mode html si on dispose des elements
1783
+        [$srcw, $srch] = taille_image($img);
1784
+        if ($srcw and $srch) {
1785
+            [$w, $h] = _image_ratio($srcw, $srch, $taille, $taille_y);
1786
+
1787
+            return _image_tag_changer_taille($img, $w, $h);
1788
+        }
1789
+        // la on n'a pas d'infos sur l'image source... on refile le truc a css
1790
+        // sous la forme style='max-width: NNpx;'
1791
+        return inserer_attribut(
1792
+            $img,
1793
+            'style',
1794
+            "max-width: ${taille}px;max-width: min(100%,${taille}px); max-height: ${taille_y}px"
1795
+        );
1796
+    }
1797
+
1798
+    // si l'image est plus petite que la cible retourner une copie cachee de l'image
1799
+    if (($image['largeur'] <= $taille) && ($image['hauteur'] <= $taille_y)) {
1800
+        if ($image['creer']) {
1801
+            @copy($image['fichier'], $image['fichier_dest']);
1802
+        }
1803
+
1804
+        return _image_ecrire_tag($image, ['src' => $image['fichier_dest']]);
1805
+    }
1806
+
1807
+    if ($image['creer'] == false && !$force) {
1808
+        return _image_ecrire_tag(
1809
+            $image,
1810
+            ['src' => $image['fichier_dest'], 'width' => $image['largeur_dest'], 'height' => $image['hauteur_dest']]
1811
+        );
1812
+    }
1813
+
1814
+    if (in_array($image['format_source'], _image_extensions_acceptees_en_entree())) {
1815
+        $destWidth = $image['largeur_dest'];
1816
+        $destHeight = $image['hauteur_dest'];
1817
+        $logo = $image['fichier'];
1818
+        $date = $image['date_src'];
1819
+        $preview = _image_creer_vignette($image, $taille, $taille_y, $process, $force);
1820
+
1821
+        if ($preview && $preview['fichier']) {
1822
+            $logo = $preview['fichier'];
1823
+            $destWidth = $preview['width'];
1824
+            $destHeight = $preview['height'];
1825
+            $date = $preview['date'];
1826
+        }
1827
+        // dans l'espace prive mettre un timestamp sur l'adresse
1828
+        // de l'image, de facon a tromper le cache du navigateur
1829
+        // quand on fait supprimer/reuploader un logo
1830
+        // (pas de filemtime si SAFE MODE)
1831
+        $date = test_espace_prive() ? ('?' . $date) : '';
1832
+
1833
+        return _image_ecrire_tag($image, ['src' => "$logo$date", 'width' => $destWidth, 'height' => $destHeight]);
1834
+    }
1835
+    else {
1836
+        # BMP, tiff ... les redacteurs osent tout!
1837
+        return $img;
1838
+    }
1839 1839
 }
1840 1840
 
1841 1841
 /**
@@ -1849,145 +1849,145 @@  discard block
 block discarded – undo
1849 1849
  * Class phpthumb_functions
1850 1850
  */
1851 1851
 class phpthumb_functions {
1852
-	/**
1853
-	 * Retourne la couleur d'un pixel dans une image
1854
-	 *
1855
-	 * @param resource|GdImage $img
1856
-	 * @param int $x
1857
-	 * @param int $y
1858
-	 * @return array|bool
1859
-	 */
1860
-	public static function GetPixelColor(&$img, $x, $y) {
1861
-		if (is_resource($img) || (is_object($img) && $img instanceof \GdImage)) {
1862
-			return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
1863
-		}
1864
-		return false;
1865
-	}
1866
-
1867
-	/**
1868
-	 * Retourne un nombre dans une représentation en Little Endian
1869
-	 *
1870
-	 * @param int $number
1871
-	 * @param int $minbytes
1872
-	 * @return string
1873
-	 */
1874
-	public static function LittleEndian2String($number, $minbytes = 1) {
1875
-		$intstring = '';
1876
-		while ($number > 0) {
1877
-			$intstring = $intstring . chr($number & 255);
1878
-			$number >>= 8;
1879
-		}
1880
-
1881
-		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
1882
-	}
1883
-
1884
-	/**
1885
-	 * Transforme une ressource GD en image au format ICO
1886
-	 *
1887
-	 * @param array $gd_image_array
1888
-	 *     Tableau de ressources d'images GD
1889
-	 * @return string
1890
-	 *     Image au format ICO
1891
-	 */
1892
-	public static function GD2ICOstring(&$gd_image_array) {
1893
-		foreach ($gd_image_array as $key => $gd_image) {
1894
-			$ImageWidths[$key] = ImageSX($gd_image);
1895
-			$ImageHeights[$key] = ImageSY($gd_image);
1896
-			$bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24;
1897
-			$totalcolors[$key] = ImageColorsTotal($gd_image);
1898
-
1899
-			$icXOR[$key] = '';
1900
-			for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
1901
-				for ($x = 0; $x < $ImageWidths[$key]; $x++) {
1902
-					$argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
1903
-					$a = round(255 * ((127 - $argb['alpha']) / 127));
1904
-					$r = $argb['red'];
1905
-					$g = $argb['green'];
1906
-					$b = $argb['blue'];
1907
-
1908
-					if ($bpp[$key] == 32) {
1909
-						$icXOR[$key] .= chr($b) . chr($g) . chr($r) . chr($a);
1910
-					} elseif ($bpp[$key] == 24) {
1911
-						$icXOR[$key] .= chr($b) . chr($g) . chr($r);
1912
-					}
1913
-
1914
-					if ($a < 128) {
1915
-						@$icANDmask[$key][$y] .= '1';
1916
-					} else {
1917
-						@$icANDmask[$key][$y] .= '0';
1918
-					}
1919
-				}
1920
-				// mask bits are 32-bit aligned per scanline
1921
-				while (strlen($icANDmask[$key][$y]) % 32) {
1922
-					$icANDmask[$key][$y] .= '0';
1923
-				}
1924
-			}
1925
-			$icAND[$key] = '';
1926
-			foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
1927
-				for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
1928
-					$icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
1929
-				}
1930
-			}
1931
-		}
1932
-
1933
-		foreach ($gd_image_array as $key => $gd_image) {
1934
-			$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
1935
-
1936
-			// BITMAPINFOHEADER - 40 bytes
1937
-			$BitmapInfoHeader[$key] = '';
1938
-			$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";                // DWORD  biSize;
1939
-			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);    // LONG   biWidth;
1940
-			// The biHeight member specifies the combined
1941
-			// height of the XOR and AND masks.
1942
-			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
1943
-			$BitmapInfoHeader[$key] .= "\x01\x00";                    // WORD   biPlanes;
1944
-			$BitmapInfoHeader[$key] .= chr($bpp[$key]) . "\x00";              // wBitCount;
1945
-			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biCompression;
1946
-			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);      // DWORD  biSizeImage;
1947
-			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biXPelsPerMeter;
1948
-			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biYPelsPerMeter;
1949
-			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrUsed;
1950
-			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrImportant;
1951
-		}
1952
-
1953
-
1954
-		$icondata = "\x00\x00";                    // idReserved;   // Reserved (must be 0)
1955
-		$icondata .= "\x01\x00";                    // idType;	   // Resource Type (1 for icons)
1956
-		$icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2);  // idCount;	  // How many images?
1957
-
1958
-		$dwImageOffset = 6 + (count($gd_image_array) * 16);
1959
-		foreach ($gd_image_array as $key => $gd_image) {
1960
-			// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
1961
-
1962
-			$icondata .= chr($ImageWidths[$key]);           // bWidth;		  // Width, in pixels, of the image
1963
-			$icondata .= chr($ImageHeights[$key]);          // bHeight;		 // Height, in pixels, of the image
1964
-			$icondata .= chr($totalcolors[$key]);           // bColorCount;	 // Number of colors in image (0 if >=8bpp)
1965
-			$icondata .= "\x00";                    // bReserved;	   // Reserved ( must be 0)
1966
-
1967
-			$icondata .= "\x01\x00";                  // wPlanes;		 // Color Planes
1968
-			$icondata .= chr($bpp[$key]) . "\x00";            // wBitCount;	   // Bits per pixel
1969
-
1970
-			$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
1971
-			$icondata .= phpthumb_functions::LittleEndian2String(
1972
-				$dwBytesInRes,
1973
-				4
1974
-			);     // dwBytesInRes;	// How many bytes in this resource?
1975
-
1976
-			$icondata .= phpthumb_functions::LittleEndian2String(
1977
-				$dwImageOffset,
1978
-				4
1979
-			);    // dwImageOffset;   // Where in the file is this image?
1980
-			$dwImageOffset += strlen($BitmapInfoHeader[$key]);
1981
-			$dwImageOffset += strlen($icXOR[$key]);
1982
-			$dwImageOffset += strlen($icAND[$key]);
1983
-		}
1984
-
1985
-		foreach ($gd_image_array as $key => $gd_image) {
1986
-			$icondata .= $BitmapInfoHeader[$key];
1987
-			$icondata .= $icXOR[$key];
1988
-			$icondata .= $icAND[$key];
1989
-		}
1990
-
1991
-		return $icondata;
1992
-	}
1852
+    /**
1853
+     * Retourne la couleur d'un pixel dans une image
1854
+     *
1855
+     * @param resource|GdImage $img
1856
+     * @param int $x
1857
+     * @param int $y
1858
+     * @return array|bool
1859
+     */
1860
+    public static function GetPixelColor(&$img, $x, $y) {
1861
+        if (is_resource($img) || (is_object($img) && $img instanceof \GdImage)) {
1862
+            return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
1863
+        }
1864
+        return false;
1865
+    }
1866
+
1867
+    /**
1868
+     * Retourne un nombre dans une représentation en Little Endian
1869
+     *
1870
+     * @param int $number
1871
+     * @param int $minbytes
1872
+     * @return string
1873
+     */
1874
+    public static function LittleEndian2String($number, $minbytes = 1) {
1875
+        $intstring = '';
1876
+        while ($number > 0) {
1877
+            $intstring = $intstring . chr($number & 255);
1878
+            $number >>= 8;
1879
+        }
1880
+
1881
+        return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
1882
+    }
1883
+
1884
+    /**
1885
+     * Transforme une ressource GD en image au format ICO
1886
+     *
1887
+     * @param array $gd_image_array
1888
+     *     Tableau de ressources d'images GD
1889
+     * @return string
1890
+     *     Image au format ICO
1891
+     */
1892
+    public static function GD2ICOstring(&$gd_image_array) {
1893
+        foreach ($gd_image_array as $key => $gd_image) {
1894
+            $ImageWidths[$key] = ImageSX($gd_image);
1895
+            $ImageHeights[$key] = ImageSY($gd_image);
1896
+            $bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24;
1897
+            $totalcolors[$key] = ImageColorsTotal($gd_image);
1898
+
1899
+            $icXOR[$key] = '';
1900
+            for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
1901
+                for ($x = 0; $x < $ImageWidths[$key]; $x++) {
1902
+                    $argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
1903
+                    $a = round(255 * ((127 - $argb['alpha']) / 127));
1904
+                    $r = $argb['red'];
1905
+                    $g = $argb['green'];
1906
+                    $b = $argb['blue'];
1907
+
1908
+                    if ($bpp[$key] == 32) {
1909
+                        $icXOR[$key] .= chr($b) . chr($g) . chr($r) . chr($a);
1910
+                    } elseif ($bpp[$key] == 24) {
1911
+                        $icXOR[$key] .= chr($b) . chr($g) . chr($r);
1912
+                    }
1913
+
1914
+                    if ($a < 128) {
1915
+                        @$icANDmask[$key][$y] .= '1';
1916
+                    } else {
1917
+                        @$icANDmask[$key][$y] .= '0';
1918
+                    }
1919
+                }
1920
+                // mask bits are 32-bit aligned per scanline
1921
+                while (strlen($icANDmask[$key][$y]) % 32) {
1922
+                    $icANDmask[$key][$y] .= '0';
1923
+                }
1924
+            }
1925
+            $icAND[$key] = '';
1926
+            foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
1927
+                for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
1928
+                    $icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
1929
+                }
1930
+            }
1931
+        }
1932
+
1933
+        foreach ($gd_image_array as $key => $gd_image) {
1934
+            $biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
1935
+
1936
+            // BITMAPINFOHEADER - 40 bytes
1937
+            $BitmapInfoHeader[$key] = '';
1938
+            $BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";                // DWORD  biSize;
1939
+            $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);    // LONG   biWidth;
1940
+            // The biHeight member specifies the combined
1941
+            // height of the XOR and AND masks.
1942
+            $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
1943
+            $BitmapInfoHeader[$key] .= "\x01\x00";                    // WORD   biPlanes;
1944
+            $BitmapInfoHeader[$key] .= chr($bpp[$key]) . "\x00";              // wBitCount;
1945
+            $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biCompression;
1946
+            $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);      // DWORD  biSizeImage;
1947
+            $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biXPelsPerMeter;
1948
+            $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biYPelsPerMeter;
1949
+            $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrUsed;
1950
+            $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrImportant;
1951
+        }
1952
+
1953
+
1954
+        $icondata = "\x00\x00";                    // idReserved;   // Reserved (must be 0)
1955
+        $icondata .= "\x01\x00";                    // idType;	   // Resource Type (1 for icons)
1956
+        $icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2);  // idCount;	  // How many images?
1957
+
1958
+        $dwImageOffset = 6 + (count($gd_image_array) * 16);
1959
+        foreach ($gd_image_array as $key => $gd_image) {
1960
+            // ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
1961
+
1962
+            $icondata .= chr($ImageWidths[$key]);           // bWidth;		  // Width, in pixels, of the image
1963
+            $icondata .= chr($ImageHeights[$key]);          // bHeight;		 // Height, in pixels, of the image
1964
+            $icondata .= chr($totalcolors[$key]);           // bColorCount;	 // Number of colors in image (0 if >=8bpp)
1965
+            $icondata .= "\x00";                    // bReserved;	   // Reserved ( must be 0)
1966
+
1967
+            $icondata .= "\x01\x00";                  // wPlanes;		 // Color Planes
1968
+            $icondata .= chr($bpp[$key]) . "\x00";            // wBitCount;	   // Bits per pixel
1969
+
1970
+            $dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
1971
+            $icondata .= phpthumb_functions::LittleEndian2String(
1972
+                $dwBytesInRes,
1973
+                4
1974
+            );     // dwBytesInRes;	// How many bytes in this resource?
1975
+
1976
+            $icondata .= phpthumb_functions::LittleEndian2String(
1977
+                $dwImageOffset,
1978
+                4
1979
+            );    // dwImageOffset;   // Where in the file is this image?
1980
+            $dwImageOffset += strlen($BitmapInfoHeader[$key]);
1981
+            $dwImageOffset += strlen($icXOR[$key]);
1982
+            $dwImageOffset += strlen($icAND[$key]);
1983
+        }
1984
+
1985
+        foreach ($gd_image_array as $key => $gd_image) {
1986
+            $icondata .= $BitmapInfoHeader[$key];
1987
+            $icondata .= $icXOR[$key];
1988
+            $icondata .= $icAND[$key];
1989
+        }
1990
+
1991
+        return $icondata;
1992
+    }
1993 1993
 }
Please login to merge, or discard this patch.
ecrire/public/composer.php 1 patch
Indentation   +761 added lines, -761 removed lines patch added patch discarded remove patch
@@ -18,7 +18,7 @@  discard block
 block discarded – undo
18 18
  **/
19 19
 
20 20
 if (!defined('_ECRIRE_INC_VERSION')) {
21
-	return;
21
+    return;
22 22
 }
23 23
 
24 24
 include_spip('inc/texte');
@@ -42,234 +42,234 @@  discard block
 block discarded – undo
42 42
 
43 43
 function public_composer_dist($squelette, $mime_type, $gram, $source, string $connect = '') {
44 44
 
45
-	$skel = null;
46
-	$boucle = null;
47
-	$nom = calculer_nom_fonction_squel($squelette, $mime_type, $connect);
48
-
49
-	//  si deja en memoire (INCLURE  a repetition) c'est bon.
50
-	if (function_exists($nom)) {
51
-		return $nom;
52
-	}
53
-
54
-	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
55
-		$GLOBALS['debug_objets']['courant'] = $nom;
56
-	}
57
-
58
-	$phpfile = sous_repertoire(_DIR_SKELS, '', false, true) . $nom . '.php';
59
-
60
-	// si squelette est deja compile et perenne, le charger
61
-	if (!squelette_obsolete($phpfile, $source)) {
62
-		include_once $phpfile;
63
-		#if (!squelette_obsolete($phpfile, $source)
64
-		#  AND lire_fichier ($phpfile, $skel_code,
65
-		#  array('critique' => 'oui', 'phpcheck' => 'oui'))){
66
-		## eval('?'.'>'.$skel_code);
67
-		#	 spip_log($skel_code, 'comp')
68
-		#}
69
-	}
70
-
71
-	if (file_exists($lib = $squelette . '_fonctions' . '.php')) {
72
-		include_once $lib;
73
-	}
74
-
75
-	// tester si le eval ci-dessus a mis le squelette en memoire
76
-
77
-	if (function_exists($nom)) {
78
-		return $nom;
79
-	}
80
-
81
-	// charger le source, si possible, et compiler
82
-	$skel_code = '';
83
-	if (lire_fichier($source, $skel)) {
84
-		$compiler = charger_fonction('compiler', 'public');
85
-		$skel_code = $compiler($skel, $nom, $gram, $source, $connect);
86
-	}
87
-
88
-	// Ne plus rien faire si le compilateur n'a pas pu operer.
89
-	if (!$skel_code) {
90
-		return false;
91
-	}
92
-
93
-	foreach ($skel_code as $id => $boucle) {
94
-		$f = $boucle->return;
95
-		try {
96
-			eval("return true; $f ;");
97
-		} catch (\ParseError $e) {
98
-			// Code syntaxiquement faux (critere etc mal programme')
99
-			$msg = _T('zbug_erreur_compilation') . ' | Line ' . $e->getLine() . ' : ' . $e->getMessage();
100
-			erreur_squelette($msg, $boucle);
101
-			// continuer pour trouver d'autres fautes eventuelles
102
-			// mais prevenir que c'est mort
103
-			$nom = '';
104
-		}
105
-
106
-		// Contexte de compil inutile a present
107
-		// (mais la derniere valeur de $boucle est utilisee ci-dessous)
108
-		$skel_code[$id] = $f;
109
-	}
110
-
111
-	$code = '';
112
-	if ($nom) {
113
-		// Si le code est bon, concatener et mettre en cache
114
-		if (function_exists($nom)) {
115
-			$code = squelette_traduit($skel, $source, $phpfile, $skel_code);
116
-		} else {
117
-			// code semantiquement faux: bug du compilateur
118
-			// $boucle est en fait ici la fct principale du squelette
119
-			$msg = _T('zbug_erreur_compilation');
120
-			erreur_squelette($msg, $boucle);
121
-			$nom = '';
122
-		}
123
-	}
124
-
125
-	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
126
-		// Tracer ce qui vient d'etre compile
127
-		$GLOBALS['debug_objets']['code'][$nom . 'tout'] = $code;
128
-
129
-		// si c'est ce que demande le debusqueur, lui passer la main
130
-		if (
131
-			$GLOBALS['debug_objets']['sourcefile']
132
-			and (_request('var_mode_objet') == $nom)
133
-			and (_request('var_mode_affiche') == 'code')
134
-		) {
135
-			erreur_squelette();
136
-		}
137
-	}
138
-
139
-	return $nom ?: false;
45
+    $skel = null;
46
+    $boucle = null;
47
+    $nom = calculer_nom_fonction_squel($squelette, $mime_type, $connect);
48
+
49
+    //  si deja en memoire (INCLURE  a repetition) c'est bon.
50
+    if (function_exists($nom)) {
51
+        return $nom;
52
+    }
53
+
54
+    if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
55
+        $GLOBALS['debug_objets']['courant'] = $nom;
56
+    }
57
+
58
+    $phpfile = sous_repertoire(_DIR_SKELS, '', false, true) . $nom . '.php';
59
+
60
+    // si squelette est deja compile et perenne, le charger
61
+    if (!squelette_obsolete($phpfile, $source)) {
62
+        include_once $phpfile;
63
+        #if (!squelette_obsolete($phpfile, $source)
64
+        #  AND lire_fichier ($phpfile, $skel_code,
65
+        #  array('critique' => 'oui', 'phpcheck' => 'oui'))){
66
+        ## eval('?'.'>'.$skel_code);
67
+        #	 spip_log($skel_code, 'comp')
68
+        #}
69
+    }
70
+
71
+    if (file_exists($lib = $squelette . '_fonctions' . '.php')) {
72
+        include_once $lib;
73
+    }
74
+
75
+    // tester si le eval ci-dessus a mis le squelette en memoire
76
+
77
+    if (function_exists($nom)) {
78
+        return $nom;
79
+    }
80
+
81
+    // charger le source, si possible, et compiler
82
+    $skel_code = '';
83
+    if (lire_fichier($source, $skel)) {
84
+        $compiler = charger_fonction('compiler', 'public');
85
+        $skel_code = $compiler($skel, $nom, $gram, $source, $connect);
86
+    }
87
+
88
+    // Ne plus rien faire si le compilateur n'a pas pu operer.
89
+    if (!$skel_code) {
90
+        return false;
91
+    }
92
+
93
+    foreach ($skel_code as $id => $boucle) {
94
+        $f = $boucle->return;
95
+        try {
96
+            eval("return true; $f ;");
97
+        } catch (\ParseError $e) {
98
+            // Code syntaxiquement faux (critere etc mal programme')
99
+            $msg = _T('zbug_erreur_compilation') . ' | Line ' . $e->getLine() . ' : ' . $e->getMessage();
100
+            erreur_squelette($msg, $boucle);
101
+            // continuer pour trouver d'autres fautes eventuelles
102
+            // mais prevenir que c'est mort
103
+            $nom = '';
104
+        }
105
+
106
+        // Contexte de compil inutile a present
107
+        // (mais la derniere valeur de $boucle est utilisee ci-dessous)
108
+        $skel_code[$id] = $f;
109
+    }
110
+
111
+    $code = '';
112
+    if ($nom) {
113
+        // Si le code est bon, concatener et mettre en cache
114
+        if (function_exists($nom)) {
115
+            $code = squelette_traduit($skel, $source, $phpfile, $skel_code);
116
+        } else {
117
+            // code semantiquement faux: bug du compilateur
118
+            // $boucle est en fait ici la fct principale du squelette
119
+            $msg = _T('zbug_erreur_compilation');
120
+            erreur_squelette($msg, $boucle);
121
+            $nom = '';
122
+        }
123
+    }
124
+
125
+    if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
126
+        // Tracer ce qui vient d'etre compile
127
+        $GLOBALS['debug_objets']['code'][$nom . 'tout'] = $code;
128
+
129
+        // si c'est ce que demande le debusqueur, lui passer la main
130
+        if (
131
+            $GLOBALS['debug_objets']['sourcefile']
132
+            and (_request('var_mode_objet') == $nom)
133
+            and (_request('var_mode_affiche') == 'code')
134
+        ) {
135
+            erreur_squelette();
136
+        }
137
+    }
138
+
139
+    return $nom ?: false;
140 140
 }
141 141
 
142 142
 function squelette_traduit($squelette, $sourcefile, $phpfile, $boucles) {
143 143
 
144
-	$code = null;
145
-	// Le dernier index est '' (fonction principale)
146
-	$noms = substr(join(', ', array_keys($boucles)), 0, -2);
147
-	if (CODE_COMMENTE) {
148
-		$code = "
144
+    $code = null;
145
+    // Le dernier index est '' (fonction principale)
146
+    $noms = substr(join(', ', array_keys($boucles)), 0, -2);
147
+    if (CODE_COMMENTE) {
148
+        $code = "
149 149
 /*
150 150
  * Squelette : $sourcefile
151 151
  * Date :      " . gmdate('D, d M Y H:i:s', @filemtime($sourcefile)) . ' GMT
152 152
  * Compile :   ' . gmdate('D, d M Y H:i:s', time()) . ' GMT
153 153
  * ' . (!$boucles ? 'Pas de boucle' : ('Boucles :   ' . $noms)) . '
154 154
  */ ';
155
-	}
155
+    }
156 156
 
157
-	$code = '<' . "?php\n" . $code . join('', $boucles) . "\n";
158
-	if (!defined('_VAR_NOCACHE') or !_VAR_NOCACHE) {
159
-		ecrire_fichier($phpfile, $code);
160
-	}
157
+    $code = '<' . "?php\n" . $code . join('', $boucles) . "\n";
158
+    if (!defined('_VAR_NOCACHE') or !_VAR_NOCACHE) {
159
+        ecrire_fichier($phpfile, $code);
160
+    }
161 161
 
162
-	return $code;
162
+    return $code;
163 163
 }
164 164
 
165 165
 // Le squelette compile est-il trop vieux ?
166 166
 function squelette_obsolete($skel, $squelette) {
167
-	static $date_change = null;
168
-	// ne verifier la date de mes_fonctions et mes_options qu'une seule fois
169
-	// par hit
170
-	if (is_null($date_change)) {
171
-		if (@file_exists($fonc = 'mes_fonctions.php')) {
172
-			$date_change = @filemtime($fonc);
173
-		} # compatibilite
174
-		if (defined('_FILE_OPTIONS')) {
175
-			$date_change = max($date_change, @filemtime(_FILE_OPTIONS));
176
-		}
177
-	}
178
-
179
-	return (
180
-		(defined('_VAR_MODE') and in_array(_VAR_MODE, ['recalcul', 'preview', 'debug']))
181
-		or !@file_exists($skel)
182
-		or ((@file_exists($squelette) ? @filemtime($squelette) : 0)
183
-			> ($date = @filemtime($skel)))
184
-		or ($date_change > $date)
185
-	);
167
+    static $date_change = null;
168
+    // ne verifier la date de mes_fonctions et mes_options qu'une seule fois
169
+    // par hit
170
+    if (is_null($date_change)) {
171
+        if (@file_exists($fonc = 'mes_fonctions.php')) {
172
+            $date_change = @filemtime($fonc);
173
+        } # compatibilite
174
+        if (defined('_FILE_OPTIONS')) {
175
+            $date_change = max($date_change, @filemtime(_FILE_OPTIONS));
176
+        }
177
+    }
178
+
179
+    return (
180
+        (defined('_VAR_MODE') and in_array(_VAR_MODE, ['recalcul', 'preview', 'debug']))
181
+        or !@file_exists($skel)
182
+        or ((@file_exists($squelette) ? @filemtime($squelette) : 0)
183
+            > ($date = @filemtime($skel)))
184
+        or ($date_change > $date)
185
+    );
186 186
 }
187 187
 
188 188
 // Activer l'invalideur de session
189 189
 function invalideur_session(&$Cache, $code = null) {
190
-	$Cache['session'] = spip_session();
190
+    $Cache['session'] = spip_session();
191 191
 
192
-	return $code;
192
+    return $code;
193 193
 }
194 194
 
195 195
 
196 196
 function analyse_resultat_skel($nom, $cache, $corps, $source = '') {
197
-	static $filtres = [];
198
-	$headers = [];
199
-	$corps ??= '';
200
-
201
-	// Recupere les < ?php header('Xx: y'); ? > pour $page['headers']
202
-	// note: on essaie d'attrapper aussi certains de ces entetes codes
203
-	// "a la main" dans les squelettes, mais evidemment sans exhaustivite
204
-	if (
205
-		stripos($corps, 'header') !== false
206
-		and preg_match_all(
207
-			'/(<[?]php\s+)@?header\s*\(\s*.([^:\'"]*):?\s*([^)]*)[^)]\s*\)\s*[;]?\s*[?]>/ims',
208
-			$corps,
209
-			$regs,
210
-			PREG_SET_ORDER
211
-		)
212
-	) {
213
-		foreach ($regs as $r) {
214
-			$corps = str_replace($r[0], '', $corps);
215
-			# $j = Content-Type, et pas content-TYPE.
216
-			$j = join('-', array_map('ucwords', explode('-', strtolower($r[2]))));
217
-
218
-			if ($j == 'X-Spip-Filtre' and isset($headers[$j])) {
219
-				$headers[$j] .= '|' . $r[3];
220
-			} else {
221
-				$headers[$j] = str_replace(['\\\\',"\\'",'\\"'], ['\\',"'",'"'], $r[3]);
222
-			}
223
-		}
224
-	}
225
-	// S'agit-il d'un resultat constant ou contenant du code php
226
-	$process_ins = (
227
-		strpos($corps, '<' . '?') === false
228
-		or
229
-		(strpos($corps, '<' . '?xml') !== false and
230
-			strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
231
-	)
232
-		? 'html'
233
-		: 'php';
234
-
235
-	$skel = [
236
-		'squelette' => $nom,
237
-		'source' => $source,
238
-		'process_ins' => $process_ins,
239
-		'invalideurs' => $cache,
240
-		'entetes' => $headers,
241
-		'duree' => isset($headers['X-Spip-Cache']) ? intval($headers['X-Spip-Cache']) : 0
242
-	];
243
-
244
-	// traiter #FILTRE{} et filtres
245
-	if (!isset($filtres[$nom])) {
246
-		$filtres[$nom] = pipeline('declarer_filtres_squelettes', ['args' => $skel, 'data' => []]);
247
-	}
248
-	$filtres_headers = [];
249
-	if (isset($headers['X-Spip-Filtre']) and strlen($headers['X-Spip-Filtre'])) {
250
-		$filtres_headers = array_filter(explode('|', $headers['X-Spip-Filtre']));
251
-		unset($headers['X-Spip-Filtre']);
252
-	}
253
-	if (is_array($filtres[$nom]) || $filtres[$nom] instanceof \Countable ? count($filtres[$nom]) : 0 or count($filtres_headers)) {
254
-		include_spip('public/sandbox');
255
-		$corps = sandbox_filtrer_squelette($skel, $corps, $filtres_headers, $filtres[$nom]);
256
-
257
-		if ($process_ins == 'html') {
258
-			$skel['process_ins'] = (
259
-				strpos($corps, '<' . '?') === false
260
-				or
261
-				(strpos($corps, '<' . '?xml') !== false and
262
-					strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
263
-			)
264
-				? 'html'
265
-				: 'php';
266
-		}
267
-	}
268
-
269
-	$skel['entetes'] = $headers;
270
-	$skel['texte'] = $corps;
271
-
272
-	return $skel;
197
+    static $filtres = [];
198
+    $headers = [];
199
+    $corps ??= '';
200
+
201
+    // Recupere les < ?php header('Xx: y'); ? > pour $page['headers']
202
+    // note: on essaie d'attrapper aussi certains de ces entetes codes
203
+    // "a la main" dans les squelettes, mais evidemment sans exhaustivite
204
+    if (
205
+        stripos($corps, 'header') !== false
206
+        and preg_match_all(
207
+            '/(<[?]php\s+)@?header\s*\(\s*.([^:\'"]*):?\s*([^)]*)[^)]\s*\)\s*[;]?\s*[?]>/ims',
208
+            $corps,
209
+            $regs,
210
+            PREG_SET_ORDER
211
+        )
212
+    ) {
213
+        foreach ($regs as $r) {
214
+            $corps = str_replace($r[0], '', $corps);
215
+            # $j = Content-Type, et pas content-TYPE.
216
+            $j = join('-', array_map('ucwords', explode('-', strtolower($r[2]))));
217
+
218
+            if ($j == 'X-Spip-Filtre' and isset($headers[$j])) {
219
+                $headers[$j] .= '|' . $r[3];
220
+            } else {
221
+                $headers[$j] = str_replace(['\\\\',"\\'",'\\"'], ['\\',"'",'"'], $r[3]);
222
+            }
223
+        }
224
+    }
225
+    // S'agit-il d'un resultat constant ou contenant du code php
226
+    $process_ins = (
227
+        strpos($corps, '<' . '?') === false
228
+        or
229
+        (strpos($corps, '<' . '?xml') !== false and
230
+            strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
231
+    )
232
+        ? 'html'
233
+        : 'php';
234
+
235
+    $skel = [
236
+        'squelette' => $nom,
237
+        'source' => $source,
238
+        'process_ins' => $process_ins,
239
+        'invalideurs' => $cache,
240
+        'entetes' => $headers,
241
+        'duree' => isset($headers['X-Spip-Cache']) ? intval($headers['X-Spip-Cache']) : 0
242
+    ];
243
+
244
+    // traiter #FILTRE{} et filtres
245
+    if (!isset($filtres[$nom])) {
246
+        $filtres[$nom] = pipeline('declarer_filtres_squelettes', ['args' => $skel, 'data' => []]);
247
+    }
248
+    $filtres_headers = [];
249
+    if (isset($headers['X-Spip-Filtre']) and strlen($headers['X-Spip-Filtre'])) {
250
+        $filtres_headers = array_filter(explode('|', $headers['X-Spip-Filtre']));
251
+        unset($headers['X-Spip-Filtre']);
252
+    }
253
+    if (is_array($filtres[$nom]) || $filtres[$nom] instanceof \Countable ? count($filtres[$nom]) : 0 or count($filtres_headers)) {
254
+        include_spip('public/sandbox');
255
+        $corps = sandbox_filtrer_squelette($skel, $corps, $filtres_headers, $filtres[$nom]);
256
+
257
+        if ($process_ins == 'html') {
258
+            $skel['process_ins'] = (
259
+                strpos($corps, '<' . '?') === false
260
+                or
261
+                (strpos($corps, '<' . '?xml') !== false and
262
+                    strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
263
+            )
264
+                ? 'html'
265
+                : 'php';
266
+        }
267
+    }
268
+
269
+    $skel['entetes'] = $headers;
270
+    $skel['texte'] = $corps;
271
+
272
+    return $skel;
273 273
 }
274 274
 
275 275
 //
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
 inserer_balise_dynamique(balise_%s_dyn(%s), array(%s));
284 284
 if ($lang_select) lang_select();
285 285
 ?'
286
-	. '>');
286
+    . '>');
287 287
 
288 288
 /**
289 289
  * Synthétise une balise dynamique : crée l'appel à l'inclusion
@@ -303,35 +303,35 @@  discard block
 block discarded – undo
303 303
  *     Code PHP pour inclure le squelette de la balise dynamique
304 304
  **/
305 305
 function synthetiser_balise_dynamique($nom, $args, $file, $context_compil) {
306
-	if (
307
-		strncmp($file, '/', 1) !== 0
308
-		// pas de lien symbolique sous Windows
309
-		and !(stristr(PHP_OS, 'WIN') and strpos($file, ':') !== false)
310
-	) {
311
-		$file = './" . _DIR_RACINE . "' . $file;
312
-	}
313
-
314
-	$lang = $context_compil[4];
315
-	if (preg_match(',\W,', $lang)) {
316
-		$lang = '';
317
-	}
318
-
319
-	$args = array_map('argumenter_squelette', $args);
320
-	if (!empty($context_compil['appel_php_depuis_modele'])) {
321
-		$args[0] = 'arguments_balise_dyn_depuis_modele(' . $args[0] . ')';
322
-	}
323
-	$args = join(', ', $args);
324
-
325
-	$r = sprintf(
326
-		CODE_INCLURE_BALISE,
327
-		$file,
328
-		$lang,
329
-		$nom,
330
-		$args,
331
-		join(', ', array_map('_q', $context_compil))
332
-	);
333
-
334
-	return $r;
306
+    if (
307
+        strncmp($file, '/', 1) !== 0
308
+        // pas de lien symbolique sous Windows
309
+        and !(stristr(PHP_OS, 'WIN') and strpos($file, ':') !== false)
310
+    ) {
311
+        $file = './" . _DIR_RACINE . "' . $file;
312
+    }
313
+
314
+    $lang = $context_compil[4];
315
+    if (preg_match(',\W,', $lang)) {
316
+        $lang = '';
317
+    }
318
+
319
+    $args = array_map('argumenter_squelette', $args);
320
+    if (!empty($context_compil['appel_php_depuis_modele'])) {
321
+        $args[0] = 'arguments_balise_dyn_depuis_modele(' . $args[0] . ')';
322
+    }
323
+    $args = join(', ', $args);
324
+
325
+    $r = sprintf(
326
+        CODE_INCLURE_BALISE,
327
+        $file,
328
+        $lang,
329
+        $nom,
330
+        $args,
331
+        join(', ', array_map('_q', $context_compil))
332
+    );
333
+
334
+    return $r;
335 335
 }
336 336
 
337 337
 /**
@@ -349,18 +349,18 @@  discard block
 block discarded – undo
349 349
  **/
350 350
 function argumenter_squelette($v) {
351 351
 
352
-	if (is_object($v)) {
353
-		return var_export($v, true);
354
-	} elseif (!is_array($v)) {
355
-		return "'" . texte_script((string) $v) . "'";
356
-	} else {
357
-		$out = [];
358
-		foreach ($v as $k => $val) {
359
-			$out [] = argumenter_squelette($k) . '=>' . argumenter_squelette($val);
360
-		}
361
-
362
-		return 'array(' . join(', ', $out) . ')';
363
-	}
352
+    if (is_object($v)) {
353
+        return var_export($v, true);
354
+    } elseif (!is_array($v)) {
355
+        return "'" . texte_script((string) $v) . "'";
356
+    } else {
357
+        $out = [];
358
+        foreach ($v as $k => $val) {
359
+            $out [] = argumenter_squelette($k) . '=>' . argumenter_squelette($val);
360
+        }
361
+
362
+        return 'array(' . join(', ', $out) . ')';
363
+    }
364 364
 }
365 365
 
366 366
 
@@ -391,87 +391,87 @@  discard block
 block discarded – undo
391 391
  *     Code PHP d'exécutant l'inclusion du squelette (ou texte) de la balise dynamique
392 392
  **/
393 393
 function executer_balise_dynamique($nom, $args, $context_compil) {
394
-	/** @var string Nom de la balise à charger (balise demandée ou balise générique) */
395
-	$nom_balise = $nom;
396
-	/** @var string Nom de la balise générique (si utilisée) */
397
-	$nom_balise_generique = '';
398
-
399
-	$appel_php_depuis_modele = false;
400
-	if (
401
-		is_array($context_compil)
402
-		and !is_numeric($context_compil[3])
403
-		and empty($context_compil[0])
404
-		and empty($context_compil[1])
405
-		and empty($context_compil[2])
406
-		and empty($context_compil[3])
407
-	) {
408
-		$appel_php_depuis_modele = true;
409
-	}
410
-
411
-	if (!$fonction_balise = charger_fonction($nom_balise, 'balise', true)) {
412
-		// Calculer un nom générique (ie. 'formulaire_' dans 'formulaire_editer_article')
413
-		if ($balise_generique = chercher_balise_generique($nom)) {
414
-			// injecter en premier arg le nom de la balise
415
-			array_unshift($args, $nom);
416
-			$nom_balise_generique = $balise_generique['nom_generique'];
417
-			$fonction_balise = $balise_generique['fonction_generique'];
418
-			$nom_balise = $nom_balise_generique;
419
-		}
420
-		unset($balise_generique);
421
-	}
422
-
423
-	if (!$fonction_balise) {
424
-		$msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
425
-		erreur_squelette($msg, $context_compil);
426
-
427
-		return '';
428
-	}
429
-
430
-	// retrouver le fichier qui a déclaré la fonction
431
-	// même si la fonction dynamique est déclarée dans un fichier de fonctions.
432
-	// Attention sous windows, getFileName() retourne un antislash.
433
-	$reflector = new ReflectionFunction($fonction_balise);
434
-	$file = str_replace('\\', '/', $reflector->getFileName());
435
-	if (strncmp($file, str_replace('\\', '/', _ROOT_RACINE), strlen(_ROOT_RACINE)) === 0) {
436
-		$file = substr($file, strlen(_ROOT_RACINE));
437
-	}
438
-
439
-	// Y a-t-il une fonction de traitement des arguments ?
440
-	$f = 'balise_' . $nom_balise . '_stat';
441
-
442
-	$r = !function_exists($f) ? $args : $f($args, $context_compil);
443
-
444
-	if (!is_array($r)) {
445
-		return $r;
446
-	}
447
-
448
-	// verifier que la fonction dyn est la,
449
-	// sinon se replier sur la generique si elle existe
450
-	if (!function_exists('balise_' . $nom_balise . '_dyn')) {
451
-		if (
452
-			$balise_generique = chercher_balise_generique($nom)
453
-			and $nom_balise_generique = $balise_generique['nom_generique']
454
-			and $file = include_spip('balise/' . strtolower($nom_balise_generique))
455
-			and function_exists('balise_' . $nom_balise_generique . '_dyn')
456
-		) {
457
-			// et lui injecter en premier arg le nom de la balise
458
-			array_unshift($r, $nom);
459
-			$nom_balise = $nom_balise_generique;
460
-			if (!_DIR_RESTREINT) {
461
-				$file = _DIR_RESTREINT_ABS . $file;
462
-			}
463
-		} else {
464
-			$msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
465
-			erreur_squelette($msg, $context_compil);
466
-
467
-			return '';
468
-		}
469
-	}
470
-
471
-	if ($appel_php_depuis_modele) {
472
-		$context_compil['appel_php_depuis_modele'] = true;
473
-	}
474
-	return synthetiser_balise_dynamique($nom_balise, $r, $file, $context_compil);
394
+    /** @var string Nom de la balise à charger (balise demandée ou balise générique) */
395
+    $nom_balise = $nom;
396
+    /** @var string Nom de la balise générique (si utilisée) */
397
+    $nom_balise_generique = '';
398
+
399
+    $appel_php_depuis_modele = false;
400
+    if (
401
+        is_array($context_compil)
402
+        and !is_numeric($context_compil[3])
403
+        and empty($context_compil[0])
404
+        and empty($context_compil[1])
405
+        and empty($context_compil[2])
406
+        and empty($context_compil[3])
407
+    ) {
408
+        $appel_php_depuis_modele = true;
409
+    }
410
+
411
+    if (!$fonction_balise = charger_fonction($nom_balise, 'balise', true)) {
412
+        // Calculer un nom générique (ie. 'formulaire_' dans 'formulaire_editer_article')
413
+        if ($balise_generique = chercher_balise_generique($nom)) {
414
+            // injecter en premier arg le nom de la balise
415
+            array_unshift($args, $nom);
416
+            $nom_balise_generique = $balise_generique['nom_generique'];
417
+            $fonction_balise = $balise_generique['fonction_generique'];
418
+            $nom_balise = $nom_balise_generique;
419
+        }
420
+        unset($balise_generique);
421
+    }
422
+
423
+    if (!$fonction_balise) {
424
+        $msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
425
+        erreur_squelette($msg, $context_compil);
426
+
427
+        return '';
428
+    }
429
+
430
+    // retrouver le fichier qui a déclaré la fonction
431
+    // même si la fonction dynamique est déclarée dans un fichier de fonctions.
432
+    // Attention sous windows, getFileName() retourne un antislash.
433
+    $reflector = new ReflectionFunction($fonction_balise);
434
+    $file = str_replace('\\', '/', $reflector->getFileName());
435
+    if (strncmp($file, str_replace('\\', '/', _ROOT_RACINE), strlen(_ROOT_RACINE)) === 0) {
436
+        $file = substr($file, strlen(_ROOT_RACINE));
437
+    }
438
+
439
+    // Y a-t-il une fonction de traitement des arguments ?
440
+    $f = 'balise_' . $nom_balise . '_stat';
441
+
442
+    $r = !function_exists($f) ? $args : $f($args, $context_compil);
443
+
444
+    if (!is_array($r)) {
445
+        return $r;
446
+    }
447
+
448
+    // verifier que la fonction dyn est la,
449
+    // sinon se replier sur la generique si elle existe
450
+    if (!function_exists('balise_' . $nom_balise . '_dyn')) {
451
+        if (
452
+            $balise_generique = chercher_balise_generique($nom)
453
+            and $nom_balise_generique = $balise_generique['nom_generique']
454
+            and $file = include_spip('balise/' . strtolower($nom_balise_generique))
455
+            and function_exists('balise_' . $nom_balise_generique . '_dyn')
456
+        ) {
457
+            // et lui injecter en premier arg le nom de la balise
458
+            array_unshift($r, $nom);
459
+            $nom_balise = $nom_balise_generique;
460
+            if (!_DIR_RESTREINT) {
461
+                $file = _DIR_RESTREINT_ABS . $file;
462
+            }
463
+        } else {
464
+            $msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
465
+            erreur_squelette($msg, $context_compil);
466
+
467
+            return '';
468
+        }
469
+    }
470
+
471
+    if ($appel_php_depuis_modele) {
472
+        $context_compil['appel_php_depuis_modele'] = true;
473
+    }
474
+    return synthetiser_balise_dynamique($nom_balise, $r, $file, $context_compil);
475 475
 }
476 476
 
477 477
 /**
@@ -486,23 +486,23 @@  discard block
 block discarded – undo
486 486
  * @return array|null
487 487
  */
488 488
 function chercher_balise_generique($nom) {
489
-	if (false === strpos($nom, '_')) {
490
-		return null;
491
-	}
492
-	$nom_generique = $nom;
493
-	while (false !== ($p = strrpos($nom_generique, '_'))) {
494
-		$nom_generique = substr($nom_generique, 0, $p + 1);
495
-		$fonction_generique = charger_fonction($nom_generique, 'balise', true);
496
-		if ($fonction_generique) {
497
-			return [
498
-				'nom' => $nom,
499
-				'nom_generique' => $nom_generique,
500
-				'fonction_generique' => $fonction_generique,
501
-			];
502
-		}
503
-		$nom_generique = substr($nom_generique, 0, -1);
504
-	}
505
-	return null;
489
+    if (false === strpos($nom, '_')) {
490
+        return null;
491
+    }
492
+    $nom_generique = $nom;
493
+    while (false !== ($p = strrpos($nom_generique, '_'))) {
494
+        $nom_generique = substr($nom_generique, 0, $p + 1);
495
+        $fonction_generique = charger_fonction($nom_generique, 'balise', true);
496
+        if ($fonction_generique) {
497
+            return [
498
+                'nom' => $nom,
499
+                'nom_generique' => $nom_generique,
500
+                'fonction_generique' => $fonction_generique,
501
+            ];
502
+        }
503
+        $nom_generique = substr($nom_generique, 0, -1);
504
+    }
505
+    return null;
506 506
 }
507 507
 
508 508
 
@@ -526,50 +526,50 @@  discard block
 block discarded – undo
526 526
  * @return null;
527 527
  **/
528 528
 function lang_select_public($lang, $lang_select, $titre = null) {
529
-	// Cas 1. forcer_lang = true et pas de critere {lang_select}
530
-	if (
531
-		isset($GLOBALS['forcer_lang']) and $GLOBALS['forcer_lang']
532
-		and $lang_select !== 'oui'
533
-	) {
534
-		$lang = $GLOBALS['spip_lang'];
535
-	} // Cas 2. l'objet n'a pas de langue definie (ou definie a '')
536
-	elseif (!strlen($lang)) {
537
-		$lang = $GLOBALS['spip_lang'];
538
-	} // Cas 3. l'objet est multilingue !
539
-	elseif (
540
-		$lang_select !== 'oui'
541
-		and strlen($titre) > 10
542
-		and strpos($titre, '<multi>') !== false
543
-		and strpos(echappe_html($titre), '<multi>') !== false
544
-	) {
545
-		$lang = $GLOBALS['spip_lang'];
546
-	}
547
-
548
-	// faire un lang_select() eventuellement sur la langue inchangee
549
-	lang_select($lang);
550
-
551
-	return;
529
+    // Cas 1. forcer_lang = true et pas de critere {lang_select}
530
+    if (
531
+        isset($GLOBALS['forcer_lang']) and $GLOBALS['forcer_lang']
532
+        and $lang_select !== 'oui'
533
+    ) {
534
+        $lang = $GLOBALS['spip_lang'];
535
+    } // Cas 2. l'objet n'a pas de langue definie (ou definie a '')
536
+    elseif (!strlen($lang)) {
537
+        $lang = $GLOBALS['spip_lang'];
538
+    } // Cas 3. l'objet est multilingue !
539
+    elseif (
540
+        $lang_select !== 'oui'
541
+        and strlen($titre) > 10
542
+        and strpos($titre, '<multi>') !== false
543
+        and strpos(echappe_html($titre), '<multi>') !== false
544
+    ) {
545
+        $lang = $GLOBALS['spip_lang'];
546
+    }
547
+
548
+    // faire un lang_select() eventuellement sur la langue inchangee
549
+    lang_select($lang);
550
+
551
+    return;
552 552
 }
553 553
 
554 554
 
555 555
 // Si un tableau &doublons[articles] est passe en parametre,
556 556
 // il faut le nettoyer car il pourrait etre injecte en SQL
557 557
 function nettoyer_env_doublons($envd) {
558
-	foreach ($envd as $table => $liste) {
559
-		$n = '';
560
-		foreach (explode(',', $liste) as $val) {
561
-			if ($a = intval($val) and $val === strval($a)) {
562
-				$n .= ',' . $val;
563
-			}
564
-		}
565
-		if (strlen($n)) {
566
-			$envd[$table] = $n;
567
-		} else {
568
-			unset($envd[$table]);
569
-		}
570
-	}
571
-
572
-	return $envd;
558
+    foreach ($envd as $table => $liste) {
559
+        $n = '';
560
+        foreach (explode(',', $liste) as $val) {
561
+            if ($a = intval($val) and $val === strval($a)) {
562
+                $n .= ',' . $val;
563
+            }
564
+        }
565
+        if (strlen($n)) {
566
+            $envd[$table] = $n;
567
+        } else {
568
+            unset($envd[$table]);
569
+        }
570
+    }
571
+
572
+    return $envd;
573 573
 }
574 574
 
575 575
 /**
@@ -588,21 +588,21 @@  discard block
 block discarded – undo
588 588
  *     Opérateur trouvé (SELF ou SUBSELECT) sinon false.
589 589
  **/
590 590
 function match_self($w) {
591
-	if (is_string($w)) {
592
-		return false;
593
-	}
594
-	if (is_array($w)) {
595
-		if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
596
-			return $w;
597
-		}
598
-		foreach (array_filter($w, 'is_array') as $sw) {
599
-			if ($m = match_self($sw)) {
600
-				return $m;
601
-			}
602
-		}
603
-	}
604
-
605
-	return false;
591
+    if (is_string($w)) {
592
+        return false;
593
+    }
594
+    if (is_array($w)) {
595
+        if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
596
+            return $w;
597
+        }
598
+        foreach (array_filter($w, 'is_array') as $sw) {
599
+            if ($m = match_self($sw)) {
600
+                return $m;
601
+            }
602
+        }
603
+    }
604
+
605
+    return false;
606 606
 }
607 607
 
608 608
 /**
@@ -618,16 +618,16 @@  discard block
 block discarded – undo
618 618
  *     est remplacée par son code.
619 619
  **/
620 620
 function remplace_sous_requete($w, $sousrequete) {
621
-	if (is_array($w)) {
622
-		if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
623
-			return $sousrequete;
624
-		}
625
-		foreach ($w as $k => $sw) {
626
-			$w[$k] = remplace_sous_requete($sw, $sousrequete);
627
-		}
628
-	}
629
-
630
-	return $w;
621
+    if (is_array($w)) {
622
+        if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
623
+            return $sousrequete;
624
+        }
625
+        foreach ($w as $k => $sw) {
626
+            $w[$k] = remplace_sous_requete($sw, $sousrequete);
627
+        }
628
+    }
629
+
630
+    return $w;
631 631
 }
632 632
 
633 633
 /**
@@ -641,17 +641,17 @@  discard block
 block discarded – undo
641 641
  *     - Conditions avec des sous requêtes
642 642
  **/
643 643
 function trouver_sous_requetes($where) {
644
-	$where_simples = [];
645
-	$where_sous = [];
646
-	foreach ($where as $k => $w) {
647
-		if (match_self($w)) {
648
-			$where_sous[$k] = $w;
649
-		} else {
650
-			$where_simples[$k] = $w;
651
-		}
652
-	}
653
-
654
-	return [$where_simples, $where_sous];
644
+    $where_simples = [];
645
+    $where_sous = [];
646
+    foreach ($where as $k => $w) {
647
+        if (match_self($w)) {
648
+            $where_sous[$k] = $w;
649
+        } else {
650
+            $where_simples[$k] = $w;
651
+        }
652
+    }
653
+
654
+    return [$where_simples, $where_sous];
655 655
 }
656 656
 
657 657
 
@@ -677,292 +677,292 @@  discard block
 block discarded – undo
677 677
  * @return resource
678 678
  */
679 679
 function calculer_select(
680
-	$select = [],
681
-	$from = [],
682
-	$from_type = [],
683
-	$where = [],
684
-	$join = [],
685
-	$groupby = [],
686
-	$orderby = [],
687
-	$limit = '',
688
-	$having = [],
689
-	$table = '',
690
-	$id = '',
691
-	$serveur = '',
692
-	$requeter = true
680
+    $select = [],
681
+    $from = [],
682
+    $from_type = [],
683
+    $where = [],
684
+    $join = [],
685
+    $groupby = [],
686
+    $orderby = [],
687
+    $limit = '',
688
+    $having = [],
689
+    $table = '',
690
+    $id = '',
691
+    $serveur = '',
692
+    $requeter = true
693 693
 ) {
694 694
 
695
-	// retirer les criteres vides:
696
-	// {X ?} avec X absent de l'URL
697
-	// {par #ENV{X}} avec X absent de l'URL
698
-	// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
699
-	$menage = false;
700
-	foreach ($where as $k => $v) {
701
-		if (is_array($v) and count($v)) {
702
-			if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
703
-				$op = false;
704
-			} elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
705
-				$op = false;
706
-			} else {
707
-				$op = $v[0] ?: $v;
708
-			}
709
-		} else {
710
-			$op = $v;
711
-		}
712
-		if ((!$op) or ($op == 1) or ($op == '0=0')) {
713
-			unset($where[$k]);
714
-			$menage = true;
715
-		}
716
-	}
717
-
718
-	// evacuer les eventuels groupby vide issus d'un calcul dynamique
719
-	$groupby = array_diff($groupby, ['']);
720
-
721
-	// remplacer les sous requetes recursives au calcul
722
-	[$where_simples, $where_sous] = trouver_sous_requetes($where);
723
-	foreach ($where_sous as $k => $w) {
724
-		$menage = true;
725
-		// on recupere la sous requete
726
-		$sous = match_self($w);
727
-		if ($sous[0] == 'SELF') {
728
-			// c'est une sous requete identique a elle meme sous la forme (SELF,$select,$where)
729
-			array_push($where_simples, $sous[2]);
730
-			$wheresub = [
731
-				$sous[2],
732
-				'0=0'
733
-			]; // pour accepter une string et forcer a faire le menage car on a surement simplifie select et where
734
-			$jsub = $join;
735
-			// trouver les jointures utiles a
736
-			// reinjecter dans le where de la sous requete les conditions supplementaires des jointures qui y sont mentionnees
737
-			// ie L1.objet='article'
738
-			// on construit le where une fois, puis on ajoute les where complentaires si besoin, et on reconstruit le where en fonction
739
-			$i = 0;
740
-			do {
741
-				$where[$k] = remplace_sous_requete($w, '(' . calculer_select(
742
-					[$sous[1] . ' AS id'],
743
-					$from,
744
-					$from_type,
745
-					$wheresub,
746
-					$jsub,
747
-					[],
748
-					[],
749
-					'',
750
-					$having,
751
-					$table,
752
-					$id,
753
-					$serveur,
754
-					false
755
-				) . ')');
756
-				if (!$i) {
757
-					$i = 1;
758
-					$wherestring = calculer_where_to_string($where[$k]);
759
-					foreach ($join as $cle => $wj) {
760
-						if (
761
-							(is_countable($wj) ? count($wj) : 0) == 4
762
-							and strpos($wherestring, (string) "{$cle}.") !== false
763
-						) {
764
-							$i = 0;
765
-							$wheresub[] = $wj[3];
766
-							unset($jsub[$cle][3]);
767
-						}
768
-					}
769
-				}
770
-			} while ($i++ < 1);
771
-		}
772
-		if ($sous[0] == 'SUBSELECT') {
773
-			// c'est une sous requete explicite sous la forme identique a sql_select : (SUBSELECT,$select,$from,$where,$groupby,$orderby,$limit,$having)
774
-			array_push($where_simples, $sous[3]); // est-ce utile dans ce cas ?
775
-			$where[$k] = remplace_sous_requete($w, '(' . calculer_select(
776
-				$sous[1], # select
777
-				$sous[2], #from
778
-				[], #from_type
779
-				$sous[3] ? (is_array($sous[3]) ? $sous[3] : [$sous[3]]) : [],
780
-				#where, qui peut etre de la forme string comme dans sql_select
781
-					[], #join
782
-				$sous[4] ?: [], #groupby
783
-				$sous[5] ?: [], #orderby
784
-				$sous[6], #limit
785
-				$sous[7] ?: [], #having
786
-				$table,
787
-				$id,
788
-				$serveur,
789
-				false
790
-			) . ')');
791
-		}
792
-		array_pop($where_simples);
793
-	}
794
-
795
-	foreach ($having as $k => $v) {
796
-		if ((!$v) or ($v == 1) or ($v == '0=0')) {
797
-			unset($having[$k]);
798
-		}
799
-	}
800
-
801
-	// Installer les jointures.
802
-	// Retirer celles seulement utiles aux criteres finalement absents mais
803
-	// parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
804
-	// si elle est seulement utile a Ln+1 elle meme inutile
805
-
806
-	$afrom = [];
807
-	$equiv = [];
808
-	$k = count($join);
809
-	foreach (array_reverse($join, true) as $cledef => $j) {
810
-		$cle = $cledef;
811
-		// le format de join est :
812
-		// array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
813
-		$join[$cle] = array_values($join[$cle]); // recalculer les cles car des unset ont pu perturber
814
-		if (count($join[$cle]) == 2) {
815
-			$join[$cle][] = $join[$cle][1];
816
-		}
817
-		if ((is_array($join[$cle]) || $join[$cle] instanceof \Countable ? count($join[$cle]) : 0) == 3) {
818
-			$join[$cle][] = '';
819
-		}
820
-		[$t, $c, $carr, $and] = $join[$cle];
821
-		// si le nom de la jointure n'a pas ete specifiee, on prend Lx avec x sont rang dans la liste
822
-		// pour compat avec ancienne convention
823
-		if (is_numeric($cle)) {
824
-			$cle = "L$k";
825
-		}
826
-		$cle_where_lie = "JOIN-$cle";
827
-		if (
828
-			!$menage
829
-			or isset($afrom[$cle])
830
-			or calculer_jointnul($cle, $select)
831
-			or calculer_jointnul($cle, array_diff_key($join, [$cle => $join[$cle]]))
832
-			or calculer_jointnul($cle, $having)
833
-			or calculer_jointnul($cle, array_diff_key($where_simples, [$cle_where_lie => '']))
834
-		) {
835
-			// corriger les references non explicites dans select
836
-			// ou groupby
837
-			foreach ($select as $i => $s) {
838
-				if ($s == $c) {
839
-					$select[$i] = "$cle.$c AS $c";
840
-					break;
841
-				}
842
-			}
843
-			foreach ($groupby as $i => $g) {
844
-				if ($g == $c) {
845
-					$groupby[$i] = "$cle.$c";
846
-					break;
847
-				}
848
-			}
849
-			// on garde une ecriture decomposee pour permettre une simplification ulterieure si besoin
850
-			// sans recours a preg_match
851
-			// un implode(' ',..) est fait dans reinjecte_joint un peu plus bas
852
-			$afrom[$t][$cle] = [
853
-				"\n" .
854
-				($from_type[$cle] ?? 'INNER') . ' JOIN',
855
-				$from[$cle],
856
-				"AS $cle",
857
-				'ON (',
858
-				"$cle.$c",
859
-				'=',
860
-				"$t.$carr",
861
-				($and ? 'AND ' . $and : '') .
862
-				')'
863
-			];
864
-			if (isset($afrom[$cle])) {
865
-				$afrom[$t] = $afrom[$t] + $afrom[$cle];
866
-				unset($afrom[$cle]);
867
-			}
868
-			$equiv[] = $carr;
869
-		} else {
870
-			unset($join[$cledef]);
871
-			if (isset($where_simples[$cle_where_lie])) {
872
-				unset($where_simples[$cle_where_lie]);
873
-				unset($where[$cle_where_lie]);
874
-			}
875
-		}
876
-		unset($from[$cle]);
877
-		$k--;
878
-	}
879
-
880
-	if (count($afrom)) {
881
-		// Regarder si la table principale ne sert finalement a rien comme dans
882
-		//<BOUCLE3(MOTS){id_article}{id_mot}> class='on'</BOUCLE3>
883
-		//<BOUCLE2(MOTS){id_article} />#TOTAL_BOUCLE<//B2>
884
-		//<BOUCLE5(RUBRIQUES){id_mot}{tout} />#TOTAL_BOUCLE<//B5>
885
-		// ou dans
886
-		//<BOUCLE8(HIERARCHIE){id_rubrique}{tout}{type='Squelette'}{inverse}{0,1}{lang_select=non} />#TOTAL_BOUCLE<//B8>
887
-		// qui comporte plusieurs jointures
888
-		// ou dans
889
-		// <BOUCLE6(ARTICLES){id_mot=2}{statut==.*} />#TOTAL_BOUCLE<//B6>
890
-		// <BOUCLE7(ARTICLES){id_mot>0}{statut?} />#TOTAL_BOUCLE<//B7>
891
-		// penser a regarder aussi la clause orderby pour ne pas simplifier abusivement
892
-		// <BOUCLE9(ARTICLES){recherche truc}{par titre}>#ID_ARTICLE</BOUCLE9>
893
-		// penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
894
-		// <BOUCLE10(EVENEMENTS){id_rubrique} />#TOTAL_BOUCLE<//B10>
895
-
896
-		$t = key($from);
897
-		$c = current($from);
898
-		reset($from);
899
-		$e = '/\b(' . "$t\\." . join('|' . $t . '\.', $equiv) . ')\b/';
900
-		if (
901
-			!(strpos($t, ' ') or // jointure des le depart cf boucle_doc
902
-				calculer_jointnul($t, $select, $e) or
903
-				calculer_jointnul($t, $join, $e) or
904
-				calculer_jointnul($t, $where, $e) or
905
-				calculer_jointnul($t, $orderby, $e) or
906
-				calculer_jointnul($t, $groupby, $e) or
907
-				calculer_jointnul($t, $having, $e))
908
-			&& count($afrom[$t])
909
-		) {
910
-			$nfrom = reset($afrom[$t]);
911
-			$nt = array_key_first($afrom[$t]);
912
-			unset($from[$t]);
913
-			$from[$nt] = $nfrom[1];
914
-			unset($afrom[$t][$nt]);
915
-			$afrom[$nt] = $afrom[$t];
916
-			unset($afrom[$t]);
917
-			$e = '/\b' . preg_quote($nfrom[6]) . '\b/';
918
-			$t = $nfrom[4];
919
-			$alias = '';
920
-			// verifier que les deux cles sont homonymes, sinon installer un alias dans le select
921
-			$oldcle = explode('.', $nfrom[6]);
922
-			$oldcle = end($oldcle);
923
-			$newcle = explode('.', $nfrom[4]);
924
-			$newcle = end($newcle);
925
-			if ($newcle != $oldcle) {
926
-				// si l'ancienne cle etait deja dans le select avec un AS
927
-				// reprendre simplement ce AS
928
-				$as = '/\b' . preg_quote($nfrom[6]) . '\s+(AS\s+\w+)\b/';
929
-				if (preg_match($as, implode(',', $select), $m)) {
930
-					$alias = '';
931
-				} else {
932
-					$alias = ', ' . $nfrom[4] . " AS $oldcle";
933
-				}
934
-			}
935
-			$select = remplacer_jointnul($t . $alias, $select, $e);
936
-			$join = remplacer_jointnul($t, $join, $e);
937
-			$where = remplacer_jointnul($t, $where, $e);
938
-			$having = remplacer_jointnul($t, $having, $e);
939
-			$groupby = remplacer_jointnul($t, $groupby, $e);
940
-			$orderby = remplacer_jointnul($t, $orderby, $e);
941
-		}
942
-		$from = reinjecte_joint($afrom, $from);
943
-	}
944
-	if (empty($GLOBALS['debug']) or !is_array($GLOBALS['debug'])) {
945
-		$wasdebug = empty($GLOBALS['debug']) ? false : $GLOBALS['debug'];
946
-		$GLOBALS['debug'] = [];
947
-		if ($wasdebug) {
948
-			$GLOBALS['debug']['debug'] = true;
949
-		}
950
-	}
951
-	$GLOBALS['debug']['aucasou'] = [$table, $id, $serveur, $requeter];
952
-	$r = sql_select(
953
-		$select,
954
-		$from,
955
-		$where,
956
-		$groupby,
957
-		array_filter($orderby),
958
-		$limit,
959
-		$having,
960
-		$serveur,
961
-		$requeter
962
-	);
963
-	unset($GLOBALS['debug']['aucasou']);
964
-
965
-	return $r;
695
+    // retirer les criteres vides:
696
+    // {X ?} avec X absent de l'URL
697
+    // {par #ENV{X}} avec X absent de l'URL
698
+    // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
699
+    $menage = false;
700
+    foreach ($where as $k => $v) {
701
+        if (is_array($v) and count($v)) {
702
+            if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
703
+                $op = false;
704
+            } elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
705
+                $op = false;
706
+            } else {
707
+                $op = $v[0] ?: $v;
708
+            }
709
+        } else {
710
+            $op = $v;
711
+        }
712
+        if ((!$op) or ($op == 1) or ($op == '0=0')) {
713
+            unset($where[$k]);
714
+            $menage = true;
715
+        }
716
+    }
717
+
718
+    // evacuer les eventuels groupby vide issus d'un calcul dynamique
719
+    $groupby = array_diff($groupby, ['']);
720
+
721
+    // remplacer les sous requetes recursives au calcul
722
+    [$where_simples, $where_sous] = trouver_sous_requetes($where);
723
+    foreach ($where_sous as $k => $w) {
724
+        $menage = true;
725
+        // on recupere la sous requete
726
+        $sous = match_self($w);
727
+        if ($sous[0] == 'SELF') {
728
+            // c'est une sous requete identique a elle meme sous la forme (SELF,$select,$where)
729
+            array_push($where_simples, $sous[2]);
730
+            $wheresub = [
731
+                $sous[2],
732
+                '0=0'
733
+            ]; // pour accepter une string et forcer a faire le menage car on a surement simplifie select et where
734
+            $jsub = $join;
735
+            // trouver les jointures utiles a
736
+            // reinjecter dans le where de la sous requete les conditions supplementaires des jointures qui y sont mentionnees
737
+            // ie L1.objet='article'
738
+            // on construit le where une fois, puis on ajoute les where complentaires si besoin, et on reconstruit le where en fonction
739
+            $i = 0;
740
+            do {
741
+                $where[$k] = remplace_sous_requete($w, '(' . calculer_select(
742
+                    [$sous[1] . ' AS id'],
743
+                    $from,
744
+                    $from_type,
745
+                    $wheresub,
746
+                    $jsub,
747
+                    [],
748
+                    [],
749
+                    '',
750
+                    $having,
751
+                    $table,
752
+                    $id,
753
+                    $serveur,
754
+                    false
755
+                ) . ')');
756
+                if (!$i) {
757
+                    $i = 1;
758
+                    $wherestring = calculer_where_to_string($where[$k]);
759
+                    foreach ($join as $cle => $wj) {
760
+                        if (
761
+                            (is_countable($wj) ? count($wj) : 0) == 4
762
+                            and strpos($wherestring, (string) "{$cle}.") !== false
763
+                        ) {
764
+                            $i = 0;
765
+                            $wheresub[] = $wj[3];
766
+                            unset($jsub[$cle][3]);
767
+                        }
768
+                    }
769
+                }
770
+            } while ($i++ < 1);
771
+        }
772
+        if ($sous[0] == 'SUBSELECT') {
773
+            // c'est une sous requete explicite sous la forme identique a sql_select : (SUBSELECT,$select,$from,$where,$groupby,$orderby,$limit,$having)
774
+            array_push($where_simples, $sous[3]); // est-ce utile dans ce cas ?
775
+            $where[$k] = remplace_sous_requete($w, '(' . calculer_select(
776
+                $sous[1], # select
777
+                $sous[2], #from
778
+                [], #from_type
779
+                $sous[3] ? (is_array($sous[3]) ? $sous[3] : [$sous[3]]) : [],
780
+                #where, qui peut etre de la forme string comme dans sql_select
781
+                    [], #join
782
+                $sous[4] ?: [], #groupby
783
+                $sous[5] ?: [], #orderby
784
+                $sous[6], #limit
785
+                $sous[7] ?: [], #having
786
+                $table,
787
+                $id,
788
+                $serveur,
789
+                false
790
+            ) . ')');
791
+        }
792
+        array_pop($where_simples);
793
+    }
794
+
795
+    foreach ($having as $k => $v) {
796
+        if ((!$v) or ($v == 1) or ($v == '0=0')) {
797
+            unset($having[$k]);
798
+        }
799
+    }
800
+
801
+    // Installer les jointures.
802
+    // Retirer celles seulement utiles aux criteres finalement absents mais
803
+    // parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
804
+    // si elle est seulement utile a Ln+1 elle meme inutile
805
+
806
+    $afrom = [];
807
+    $equiv = [];
808
+    $k = count($join);
809
+    foreach (array_reverse($join, true) as $cledef => $j) {
810
+        $cle = $cledef;
811
+        // le format de join est :
812
+        // array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
813
+        $join[$cle] = array_values($join[$cle]); // recalculer les cles car des unset ont pu perturber
814
+        if (count($join[$cle]) == 2) {
815
+            $join[$cle][] = $join[$cle][1];
816
+        }
817
+        if ((is_array($join[$cle]) || $join[$cle] instanceof \Countable ? count($join[$cle]) : 0) == 3) {
818
+            $join[$cle][] = '';
819
+        }
820
+        [$t, $c, $carr, $and] = $join[$cle];
821
+        // si le nom de la jointure n'a pas ete specifiee, on prend Lx avec x sont rang dans la liste
822
+        // pour compat avec ancienne convention
823
+        if (is_numeric($cle)) {
824
+            $cle = "L$k";
825
+        }
826
+        $cle_where_lie = "JOIN-$cle";
827
+        if (
828
+            !$menage
829
+            or isset($afrom[$cle])
830
+            or calculer_jointnul($cle, $select)
831
+            or calculer_jointnul($cle, array_diff_key($join, [$cle => $join[$cle]]))
832
+            or calculer_jointnul($cle, $having)
833
+            or calculer_jointnul($cle, array_diff_key($where_simples, [$cle_where_lie => '']))
834
+        ) {
835
+            // corriger les references non explicites dans select
836
+            // ou groupby
837
+            foreach ($select as $i => $s) {
838
+                if ($s == $c) {
839
+                    $select[$i] = "$cle.$c AS $c";
840
+                    break;
841
+                }
842
+            }
843
+            foreach ($groupby as $i => $g) {
844
+                if ($g == $c) {
845
+                    $groupby[$i] = "$cle.$c";
846
+                    break;
847
+                }
848
+            }
849
+            // on garde une ecriture decomposee pour permettre une simplification ulterieure si besoin
850
+            // sans recours a preg_match
851
+            // un implode(' ',..) est fait dans reinjecte_joint un peu plus bas
852
+            $afrom[$t][$cle] = [
853
+                "\n" .
854
+                ($from_type[$cle] ?? 'INNER') . ' JOIN',
855
+                $from[$cle],
856
+                "AS $cle",
857
+                'ON (',
858
+                "$cle.$c",
859
+                '=',
860
+                "$t.$carr",
861
+                ($and ? 'AND ' . $and : '') .
862
+                ')'
863
+            ];
864
+            if (isset($afrom[$cle])) {
865
+                $afrom[$t] = $afrom[$t] + $afrom[$cle];
866
+                unset($afrom[$cle]);
867
+            }
868
+            $equiv[] = $carr;
869
+        } else {
870
+            unset($join[$cledef]);
871
+            if (isset($where_simples[$cle_where_lie])) {
872
+                unset($where_simples[$cle_where_lie]);
873
+                unset($where[$cle_where_lie]);
874
+            }
875
+        }
876
+        unset($from[$cle]);
877
+        $k--;
878
+    }
879
+
880
+    if (count($afrom)) {
881
+        // Regarder si la table principale ne sert finalement a rien comme dans
882
+        //<BOUCLE3(MOTS){id_article}{id_mot}> class='on'</BOUCLE3>
883
+        //<BOUCLE2(MOTS){id_article} />#TOTAL_BOUCLE<//B2>
884
+        //<BOUCLE5(RUBRIQUES){id_mot}{tout} />#TOTAL_BOUCLE<//B5>
885
+        // ou dans
886
+        //<BOUCLE8(HIERARCHIE){id_rubrique}{tout}{type='Squelette'}{inverse}{0,1}{lang_select=non} />#TOTAL_BOUCLE<//B8>
887
+        // qui comporte plusieurs jointures
888
+        // ou dans
889
+        // <BOUCLE6(ARTICLES){id_mot=2}{statut==.*} />#TOTAL_BOUCLE<//B6>
890
+        // <BOUCLE7(ARTICLES){id_mot>0}{statut?} />#TOTAL_BOUCLE<//B7>
891
+        // penser a regarder aussi la clause orderby pour ne pas simplifier abusivement
892
+        // <BOUCLE9(ARTICLES){recherche truc}{par titre}>#ID_ARTICLE</BOUCLE9>
893
+        // penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
894
+        // <BOUCLE10(EVENEMENTS){id_rubrique} />#TOTAL_BOUCLE<//B10>
895
+
896
+        $t = key($from);
897
+        $c = current($from);
898
+        reset($from);
899
+        $e = '/\b(' . "$t\\." . join('|' . $t . '\.', $equiv) . ')\b/';
900
+        if (
901
+            !(strpos($t, ' ') or // jointure des le depart cf boucle_doc
902
+                calculer_jointnul($t, $select, $e) or
903
+                calculer_jointnul($t, $join, $e) or
904
+                calculer_jointnul($t, $where, $e) or
905
+                calculer_jointnul($t, $orderby, $e) or
906
+                calculer_jointnul($t, $groupby, $e) or
907
+                calculer_jointnul($t, $having, $e))
908
+            && count($afrom[$t])
909
+        ) {
910
+            $nfrom = reset($afrom[$t]);
911
+            $nt = array_key_first($afrom[$t]);
912
+            unset($from[$t]);
913
+            $from[$nt] = $nfrom[1];
914
+            unset($afrom[$t][$nt]);
915
+            $afrom[$nt] = $afrom[$t];
916
+            unset($afrom[$t]);
917
+            $e = '/\b' . preg_quote($nfrom[6]) . '\b/';
918
+            $t = $nfrom[4];
919
+            $alias = '';
920
+            // verifier que les deux cles sont homonymes, sinon installer un alias dans le select
921
+            $oldcle = explode('.', $nfrom[6]);
922
+            $oldcle = end($oldcle);
923
+            $newcle = explode('.', $nfrom[4]);
924
+            $newcle = end($newcle);
925
+            if ($newcle != $oldcle) {
926
+                // si l'ancienne cle etait deja dans le select avec un AS
927
+                // reprendre simplement ce AS
928
+                $as = '/\b' . preg_quote($nfrom[6]) . '\s+(AS\s+\w+)\b/';
929
+                if (preg_match($as, implode(',', $select), $m)) {
930
+                    $alias = '';
931
+                } else {
932
+                    $alias = ', ' . $nfrom[4] . " AS $oldcle";
933
+                }
934
+            }
935
+            $select = remplacer_jointnul($t . $alias, $select, $e);
936
+            $join = remplacer_jointnul($t, $join, $e);
937
+            $where = remplacer_jointnul($t, $where, $e);
938
+            $having = remplacer_jointnul($t, $having, $e);
939
+            $groupby = remplacer_jointnul($t, $groupby, $e);
940
+            $orderby = remplacer_jointnul($t, $orderby, $e);
941
+        }
942
+        $from = reinjecte_joint($afrom, $from);
943
+    }
944
+    if (empty($GLOBALS['debug']) or !is_array($GLOBALS['debug'])) {
945
+        $wasdebug = empty($GLOBALS['debug']) ? false : $GLOBALS['debug'];
946
+        $GLOBALS['debug'] = [];
947
+        if ($wasdebug) {
948
+            $GLOBALS['debug']['debug'] = true;
949
+        }
950
+    }
951
+    $GLOBALS['debug']['aucasou'] = [$table, $id, $serveur, $requeter];
952
+    $r = sql_select(
953
+        $select,
954
+        $from,
955
+        $where,
956
+        $groupby,
957
+        array_filter($orderby),
958
+        $limit,
959
+        $having,
960
+        $serveur,
961
+        $requeter
962
+    );
963
+    unset($GLOBALS['debug']['aucasou']);
964
+
965
+    return $r;
966 966
 }
967 967
 
968 968
 /**
@@ -973,79 +973,79 @@  discard block
 block discarded – undo
973 973
  * @return string
974 974
  */
975 975
 function calculer_where_to_string($v, $join = 'AND') {
976
-	if (empty($v)) {
977
-		return '';
978
-	}
979
-
980
-	if (!is_array($v)) {
981
-		return $v;
982
-	} else {
983
-		$exp = '';
984
-		if (strtoupper($join) === 'AND') {
985
-			return $exp . join(" $join ", array_map('calculer_where_to_string', $v));
986
-		} else {
987
-			return $exp . join($join, $v);
988
-		}
989
-	}
976
+    if (empty($v)) {
977
+        return '';
978
+    }
979
+
980
+    if (!is_array($v)) {
981
+        return $v;
982
+    } else {
983
+        $exp = '';
984
+        if (strtoupper($join) === 'AND') {
985
+            return $exp . join(" $join ", array_map('calculer_where_to_string', $v));
986
+        } else {
987
+            return $exp . join($join, $v);
988
+        }
989
+    }
990 990
 }
991 991
 
992 992
 
993 993
 //condition suffisante (mais non necessaire) pour qu'une table soit utile
994 994
 
995 995
 function calculer_jointnul($cle, $exp, $equiv = '') {
996
-	if (!is_array($exp)) {
997
-		if ($equiv) {
998
-			$exp = preg_replace($equiv, '', $exp);
999
-		}
1000
-
1001
-		return preg_match("/\\b$cle\\./", $exp);
1002
-	} else {
1003
-		foreach ($exp as $v) {
1004
-			if (calculer_jointnul($cle, $v, $equiv)) {
1005
-				return true;
1006
-			}
1007
-		}
1008
-
1009
-		return false;
1010
-	}
996
+    if (!is_array($exp)) {
997
+        if ($equiv) {
998
+            $exp = preg_replace($equiv, '', $exp);
999
+        }
1000
+
1001
+        return preg_match("/\\b$cle\\./", $exp);
1002
+    } else {
1003
+        foreach ($exp as $v) {
1004
+            if (calculer_jointnul($cle, $v, $equiv)) {
1005
+                return true;
1006
+            }
1007
+        }
1008
+
1009
+        return false;
1010
+    }
1011 1011
 }
1012 1012
 
1013 1013
 function reinjecte_joint($afrom, $from) {
1014
-	$from_synth = [];
1015
-	foreach ($from as $k => $v) {
1016
-		$from_synth[$k] = $from[$k];
1017
-		if (isset($afrom[$k])) {
1018
-			foreach ($afrom[$k] as $kk => $vv) {
1019
-				$afrom[$k][$kk] = implode(' ', $afrom[$k][$kk]);
1020
-			}
1021
-			$from_synth["$k@"] = implode(' ', $afrom[$k]);
1022
-			unset($afrom[$k]);
1023
-		}
1024
-	}
1025
-
1026
-	return $from_synth;
1014
+    $from_synth = [];
1015
+    foreach ($from as $k => $v) {
1016
+        $from_synth[$k] = $from[$k];
1017
+        if (isset($afrom[$k])) {
1018
+            foreach ($afrom[$k] as $kk => $vv) {
1019
+                $afrom[$k][$kk] = implode(' ', $afrom[$k][$kk]);
1020
+            }
1021
+            $from_synth["$k@"] = implode(' ', $afrom[$k]);
1022
+            unset($afrom[$k]);
1023
+        }
1024
+    }
1025
+
1026
+    return $from_synth;
1027 1027
 }
1028 1028
 
1029 1029
 function remplacer_jointnul($cle, $exp, $equiv = '') {
1030
-	if (!is_array($exp)) {
1031
-		return preg_replace($equiv, $cle, $exp);
1032
-	} else {
1033
-		foreach ($exp as $k => $v) {
1034
-			$exp[$k] = remplacer_jointnul($cle, $v, $equiv);
1035
-		}
1036
-
1037
-		return $exp;
1038
-	}
1030
+    if (!is_array($exp)) {
1031
+        return preg_replace($equiv, $cle, $exp);
1032
+    } else {
1033
+        foreach ($exp as $k => $v) {
1034
+            $exp[$k] = remplacer_jointnul($cle, $v, $equiv);
1035
+        }
1036
+
1037
+        return $exp;
1038
+    }
1039 1039
 }
1040 1040
 
1041 1041
 // calcul du nom du squelette
1042 1042
 function calculer_nom_fonction_squel($skel, $mime_type = 'html', string $connect = '') {
1043
-	// ne pas doublonner les squelette selon qu'ils sont calcules depuis ecrire/ ou depuis la racine
1044
-	if ($l = strlen(_DIR_RACINE) and strncmp($skel, _DIR_RACINE, $l) == 0) {
1045
-		$skel = substr($skel, strlen(_DIR_RACINE));
1046
-	}
1047
-
1048
-	return $mime_type
1049
-	. (!$connect ? '' : preg_replace('/\W/', '_', $connect)) . '_'
1050
-	. md5($GLOBALS['spip_version_code'] . ' * ' . $skel . (isset($GLOBALS['marqueur_skel']) ? '*' . $GLOBALS['marqueur_skel'] : ''));
1043
+    // ne pas doublonner les squelette selon qu'ils sont calcules depuis ecrire/ ou depuis la racine
1044
+    if ($l = strlen(_DIR_RACINE) and strncmp($skel, _DIR_RACINE, $l) == 0) {
1045
+        $skel = substr($skel, strlen(_DIR_RACINE));
1046
+    }
1047
+
1048
+    return $mime_type
1049
+    . (!$connect ? '' : preg_replace('/\W/', '_', $connect)) . '_'
1050
+    . md5($GLOBALS['spip_version_code'] . ' * ' . $skel . (isset($GLOBALS['marqueur_skel']) ? '*' . $GLOBALS['marqueur_skel'] : ''));
1051 1051
 }
Please login to merge, or discard this patch.
ecrire/auth/spip.php 1 patch
Indentation   +412 added lines, -412 removed lines patch added patch discarded remove patch
@@ -19,7 +19,7 @@  discard block
 block discarded – undo
19 19
 use Spip\Chiffrer\SpipCles;
20 20
 
21 21
 if (!defined('_ECRIRE_INC_VERSION')) {
22
-	return;
22
+    return;
23 23
 }
24 24
 
25 25
 /**
@@ -34,170 +34,170 @@  discard block
 block discarded – undo
34 34
  */
35 35
 function auth_spip_dist($login, $pass, $serveur = '', $phpauth = false) {
36 36
 
37
-	// retrouver le login
38
-	$login = auth_spip_retrouver_login($login);
39
-	// login inconnu, n'allons pas plus loin
40
-	if (!$login) {
41
-		return [];
42
-	}
43
-
44
-	$md5pass = '';
45
-	$shapass = $shanext = '';
46
-	$auteur_peut_sauver_cles = false;
47
-
48
-	if ($pass) {
49
-		$row = sql_fetsel(
50
-			'*',
51
-			'spip_auteurs',
52
-			'login=' . sql_quote($login, $serveur, 'text') . " AND statut<>'5poubelle'",
53
-			'',
54
-			'',
55
-			'',
56
-			'',
57
-			$serveur
58
-		);
59
-
60
-		// lever un flag si cet auteur peut sauver les cles
61
-		if ($row['statut'] === '0minirezo' and $row['webmestre'] === 'oui' and isset($row['backup_cles'])) {
62
-			$auteur_peut_sauver_cles = true;
63
-		}
64
-	}
65
-
66
-	// login inexistant ou mot de passe vide
67
-	if (!$pass or !$row) {
68
-		return [];
69
-	}
70
-
71
-	include_spip('inc/chiffrer');
72
-	$cles = SpipCles::instance();
73
-	$secret = $cles->getSecretAuth();
74
-
75
-	$hash = null;
76
-	switch (strlen($row['pass'])) {
77
-		// legacy = md5 ou sha256
78
-		case 32:
79
-			// tres anciens mots de passe encodes en md5(alea.pass)
80
-			$hash = md5($row['alea_actuel'] . $pass);
81
-			$methode = 'md5';
82
-		case 64:
83
-			if (empty($hash)) {
84
-				// anciens mots de passe encodes en sha256(alea.pass)
85
-				include_spip('auth/sha256.inc');
86
-				$hash = spip_sha256($row['alea_actuel'] . $pass);
87
-				$methode = 'sha256';
88
-			}
89
-			if ($row['pass'] === $hash) {
90
-				spip_log("validation du mot de passe pour l'auteur #" . $row['id_auteur'] . " $login via $methode", 'auth' . _LOG_DEBUG);
91
-				// ce n'est pas cense arriver, mais si jamais c'est un backup inutilisable, il faut le nettoyer pour ne pas bloquer la creation d'une nouvelle cle d'auth
92
-				if (!empty($row['backup_cles'])) {
93
-					sql_updateq('spip_auteurs', ['backup_cles' => ''], 'id_auteur=' . intval($row['id_auteur']));
94
-				}
95
-				break;
96
-			}
97
-
98
-		// on teste la methode par defaut, au cas ou ce serait un pass moderne qui a la malchance d'etre en 64char de long
99
-
100
-		case 60:
101
-		case 98:
102
-		default:
103
-			// doit-on restaurer un backup des cles ?
104
-			// si on a le bon pass on peut decoder le backup, retrouver la cle, et du coup valider le pass
105
-			if (
106
-				!$secret
107
-				and $auteur_peut_sauver_cles
108
-				and !empty($row['backup_cles'])
109
-			) {
110
-				if ($cles->restore($row['backup_cles'], $pass, $row['pass'], $row['id_auteur'])) {
111
-					spip_log('Les cles secretes ont ete restaurées avec le backup du webmestre #' . $row['id_auteur'], 'auth' . _LOG_INFO_IMPORTANTE);
112
-					if ($cles->save()) {
113
-						$secret = $cles->getSecretAuth();
114
-					}
115
-					else {
116
-						spip_log("Echec restauration des cles : verifier les droits d'ecriture ?", 'auth' . _LOG_ERREUR);
117
-						// et on echoue car on ne veut pas que la situation reste telle quelle
118
-						raler_fichier(_DIR_ETC . 'cles.php');
119
-					}
120
-				}
121
-				else {
122
-					spip_log('Pas de cle secrete disponible (fichier config/cle.php absent ?) mais le backup du webmestre #' . $row['id_auteur'] . " n'est pas valide", 'auth' . _LOG_ERREUR);
123
-					sql_updateq('spip_auteurs', ['backup_cles' => ''], 'id_auteur=' . intval($row['id_auteur']));
124
-				}
125
-			}
126
-
127
-			if (!$secret or !Password::verifier($pass, $row['pass'], $secret)) {
128
-				unset($row);
129
-			}
130
-			else {
131
-				spip_log("validation du mot de passe pour l'auteur #" . $row['id_auteur'] . " $login via Password::verifier", 'auth' . _LOG_DEBUG);
132
-			}
133
-			break;
134
-	}
135
-
136
-	// Migration depuis ancienne version : si on a pas encore de cle
137
-	// ET si c'est le login d'un auteur qui peut sauver la cle
138
-	// créer la clé (en s'assurant bien que personne n'a de backup d'un precedent fichier cle.php)
139
-	// si c'est un auteur normal, on ne fait rien, il garde son ancien pass hashé en sha256 en attendant le login d'un webmestre
140
-	if (!$secret and $auteur_peut_sauver_cles) {
141
-		if (auth_spip_initialiser_secret()) {
142
-			$secret = $cles->getSecretAuth();
143
-		}
144
-	}
145
-
146
-	// login/mot de passe incorrect
147
-	if (empty($row)) {
148
-		return [];
149
-	}
150
-
151
-	// fait tourner le codage du pass dans la base
152
-	// sauf si phpauth : cela reviendrait a changer l'alea a chaque hit, et aucune action verifiable par securiser_action()
153
-	if (!$phpauth and $secret) {
154
-		include_spip('inc/acces'); // pour creer_uniqid et verifier_htaccess
155
-		$pass_hash_next = Password::hacher($pass, $secret);
156
-		if ($pass_hash_next) {
157
-			$set = [
158
-				'alea_actuel' => 'alea_futur', // @deprecated 4.1
159
-				'alea_futur' => sql_quote(creer_uniqid(), $serveur, 'text'), // @deprecated 4.1
160
-				'pass' => sql_quote($pass_hash_next, $serveur, 'text'),
161
-			];
162
-
163
-			// regenerer un htpass si on a active/desactive le plugin htpasswd
164
-			// et/ou que l'algo a change - pour etre certain de toujours utiliser le bon algo
165
-			$htpass = generer_htpass($pass);
166
-			if (strlen($htpass) !== strlen($row['htpass'])) {
167
-				$set['htpass'] = sql_quote($htpass, $serveur, 'text');
168
-			}
169
-
170
-			// a chaque login de webmestre : sauvegarde chiffree des clés du site (avec les pass du webmestre)
171
-			if ($auteur_peut_sauver_cles) {
172
-				$set['backup_cles'] = sql_quote($cles->backup($pass), $serveur, 'text');
173
-			}
174
-
175
-			@sql_update(
176
-				'spip_auteurs',
177
-				$set,
178
-				'id_auteur=' . intval($row['id_auteur']) . ' AND pass=' . sql_quote(
179
-					$row['pass'],
180
-					$serveur,
181
-					'text'
182
-				),
183
-				[],
184
-				$serveur
185
-			);
186
-
187
-			// si on a change le htpass car changement d'algo, regenerer les fichiers htpasswd
188
-			if (isset($set['htpass'])) {
189
-				ecrire_acces();
190
-			}
191
-		}
192
-
193
-		// En profiter pour verifier la securite de tmp/
194
-		// Si elle ne fonctionne pas a l'installation, prevenir
195
-		if (!verifier_htaccess(_DIR_TMP) and defined('_ECRIRE_INSTALL')) {
196
-			return false;
197
-		}
198
-	}
199
-
200
-	return $row;
37
+    // retrouver le login
38
+    $login = auth_spip_retrouver_login($login);
39
+    // login inconnu, n'allons pas plus loin
40
+    if (!$login) {
41
+        return [];
42
+    }
43
+
44
+    $md5pass = '';
45
+    $shapass = $shanext = '';
46
+    $auteur_peut_sauver_cles = false;
47
+
48
+    if ($pass) {
49
+        $row = sql_fetsel(
50
+            '*',
51
+            'spip_auteurs',
52
+            'login=' . sql_quote($login, $serveur, 'text') . " AND statut<>'5poubelle'",
53
+            '',
54
+            '',
55
+            '',
56
+            '',
57
+            $serveur
58
+        );
59
+
60
+        // lever un flag si cet auteur peut sauver les cles
61
+        if ($row['statut'] === '0minirezo' and $row['webmestre'] === 'oui' and isset($row['backup_cles'])) {
62
+            $auteur_peut_sauver_cles = true;
63
+        }
64
+    }
65
+
66
+    // login inexistant ou mot de passe vide
67
+    if (!$pass or !$row) {
68
+        return [];
69
+    }
70
+
71
+    include_spip('inc/chiffrer');
72
+    $cles = SpipCles::instance();
73
+    $secret = $cles->getSecretAuth();
74
+
75
+    $hash = null;
76
+    switch (strlen($row['pass'])) {
77
+        // legacy = md5 ou sha256
78
+        case 32:
79
+            // tres anciens mots de passe encodes en md5(alea.pass)
80
+            $hash = md5($row['alea_actuel'] . $pass);
81
+            $methode = 'md5';
82
+        case 64:
83
+            if (empty($hash)) {
84
+                // anciens mots de passe encodes en sha256(alea.pass)
85
+                include_spip('auth/sha256.inc');
86
+                $hash = spip_sha256($row['alea_actuel'] . $pass);
87
+                $methode = 'sha256';
88
+            }
89
+            if ($row['pass'] === $hash) {
90
+                spip_log("validation du mot de passe pour l'auteur #" . $row['id_auteur'] . " $login via $methode", 'auth' . _LOG_DEBUG);
91
+                // ce n'est pas cense arriver, mais si jamais c'est un backup inutilisable, il faut le nettoyer pour ne pas bloquer la creation d'une nouvelle cle d'auth
92
+                if (!empty($row['backup_cles'])) {
93
+                    sql_updateq('spip_auteurs', ['backup_cles' => ''], 'id_auteur=' . intval($row['id_auteur']));
94
+                }
95
+                break;
96
+            }
97
+
98
+        // on teste la methode par defaut, au cas ou ce serait un pass moderne qui a la malchance d'etre en 64char de long
99
+
100
+        case 60:
101
+        case 98:
102
+        default:
103
+            // doit-on restaurer un backup des cles ?
104
+            // si on a le bon pass on peut decoder le backup, retrouver la cle, et du coup valider le pass
105
+            if (
106
+                !$secret
107
+                and $auteur_peut_sauver_cles
108
+                and !empty($row['backup_cles'])
109
+            ) {
110
+                if ($cles->restore($row['backup_cles'], $pass, $row['pass'], $row['id_auteur'])) {
111
+                    spip_log('Les cles secretes ont ete restaurées avec le backup du webmestre #' . $row['id_auteur'], 'auth' . _LOG_INFO_IMPORTANTE);
112
+                    if ($cles->save()) {
113
+                        $secret = $cles->getSecretAuth();
114
+                    }
115
+                    else {
116
+                        spip_log("Echec restauration des cles : verifier les droits d'ecriture ?", 'auth' . _LOG_ERREUR);
117
+                        // et on echoue car on ne veut pas que la situation reste telle quelle
118
+                        raler_fichier(_DIR_ETC . 'cles.php');
119
+                    }
120
+                }
121
+                else {
122
+                    spip_log('Pas de cle secrete disponible (fichier config/cle.php absent ?) mais le backup du webmestre #' . $row['id_auteur'] . " n'est pas valide", 'auth' . _LOG_ERREUR);
123
+                    sql_updateq('spip_auteurs', ['backup_cles' => ''], 'id_auteur=' . intval($row['id_auteur']));
124
+                }
125
+            }
126
+
127
+            if (!$secret or !Password::verifier($pass, $row['pass'], $secret)) {
128
+                unset($row);
129
+            }
130
+            else {
131
+                spip_log("validation du mot de passe pour l'auteur #" . $row['id_auteur'] . " $login via Password::verifier", 'auth' . _LOG_DEBUG);
132
+            }
133
+            break;
134
+    }
135
+
136
+    // Migration depuis ancienne version : si on a pas encore de cle
137
+    // ET si c'est le login d'un auteur qui peut sauver la cle
138
+    // créer la clé (en s'assurant bien que personne n'a de backup d'un precedent fichier cle.php)
139
+    // si c'est un auteur normal, on ne fait rien, il garde son ancien pass hashé en sha256 en attendant le login d'un webmestre
140
+    if (!$secret and $auteur_peut_sauver_cles) {
141
+        if (auth_spip_initialiser_secret()) {
142
+            $secret = $cles->getSecretAuth();
143
+        }
144
+    }
145
+
146
+    // login/mot de passe incorrect
147
+    if (empty($row)) {
148
+        return [];
149
+    }
150
+
151
+    // fait tourner le codage du pass dans la base
152
+    // sauf si phpauth : cela reviendrait a changer l'alea a chaque hit, et aucune action verifiable par securiser_action()
153
+    if (!$phpauth and $secret) {
154
+        include_spip('inc/acces'); // pour creer_uniqid et verifier_htaccess
155
+        $pass_hash_next = Password::hacher($pass, $secret);
156
+        if ($pass_hash_next) {
157
+            $set = [
158
+                'alea_actuel' => 'alea_futur', // @deprecated 4.1
159
+                'alea_futur' => sql_quote(creer_uniqid(), $serveur, 'text'), // @deprecated 4.1
160
+                'pass' => sql_quote($pass_hash_next, $serveur, 'text'),
161
+            ];
162
+
163
+            // regenerer un htpass si on a active/desactive le plugin htpasswd
164
+            // et/ou que l'algo a change - pour etre certain de toujours utiliser le bon algo
165
+            $htpass = generer_htpass($pass);
166
+            if (strlen($htpass) !== strlen($row['htpass'])) {
167
+                $set['htpass'] = sql_quote($htpass, $serveur, 'text');
168
+            }
169
+
170
+            // a chaque login de webmestre : sauvegarde chiffree des clés du site (avec les pass du webmestre)
171
+            if ($auteur_peut_sauver_cles) {
172
+                $set['backup_cles'] = sql_quote($cles->backup($pass), $serveur, 'text');
173
+            }
174
+
175
+            @sql_update(
176
+                'spip_auteurs',
177
+                $set,
178
+                'id_auteur=' . intval($row['id_auteur']) . ' AND pass=' . sql_quote(
179
+                    $row['pass'],
180
+                    $serveur,
181
+                    'text'
182
+                ),
183
+                [],
184
+                $serveur
185
+            );
186
+
187
+            // si on a change le htpass car changement d'algo, regenerer les fichiers htpasswd
188
+            if (isset($set['htpass'])) {
189
+                ecrire_acces();
190
+            }
191
+        }
192
+
193
+        // En profiter pour verifier la securite de tmp/
194
+        // Si elle ne fonctionne pas a l'installation, prevenir
195
+        if (!verifier_htaccess(_DIR_TMP) and defined('_ECRIRE_INSTALL')) {
196
+            return false;
197
+        }
198
+    }
199
+
200
+    return $row;
201 201
 }
202 202
 
203 203
 /**
@@ -212,37 +212,37 @@  discard block
 block discarded – undo
212 212
  * @return bool
213 213
  */
214 214
 function auth_spip_initialiser_secret(bool $force = false): bool {
215
-	include_spip('inc/chiffrer');
216
-	$cles = SpipCles::instance();
217
-	$secret = $cles->getSecretAuth();
218
-
219
-	// on ne fait rien si on a un secret dispo
220
-	if ($secret) {
221
-		return false;
222
-	}
223
-
224
-	// si force, on ne verifie pas la presence d'un backup chez un webmestre
225
-	if ($force) {
226
-		spip_log('Pas de cle secrete disponible, on regenere une nouvelle cle forcee - tous les mots de passe sont invalides', 'auth' . _LOG_INFO_IMPORTANTE);
227
-		$secret = $cles->getSecretAuth(true);
228
-		return true;
229
-	}
230
-
231
-	$has_backup = sql_allfetsel('id_auteur', 'spip_auteurs', 'statut=' . sql_quote('0minirezo') . ' AND webmestre=' . sql_quote('oui') . " AND backup_cles!=''");
232
-	$has_backup = array_column($has_backup, 'id_auteur');
233
-	if (empty($has_backup)) {
234
-		spip_log("Pas de cle secrete disponible, et aucun webmestre n'a de backup, on regenere une nouvelle cle - tous les mots de passe sont invalides", 'auth' . _LOG_INFO_IMPORTANTE);
235
-		if ($secret = $cles->getSecretAuth(true)) {
236
-			return true;
237
-		}
238
-		spip_log("Echec generation d'une nouvelle cle : verifier les droits d'ecriture ?", 'auth' . _LOG_ERREUR);
239
-		// et on echoue car on ne veut pas que la situation reste telle quelle
240
-		raler_fichier(_DIR_ETC . 'cles.php');
241
-	}
242
-	else {
243
-		spip_log('Pas de cle secrete disponible (fichier config/cle.php absent ?) un des webmestres #' . implode(', #', $has_backup) . ' doit se connecter pour restaurer son backup des cles', 'auth' . _LOG_ERREUR);
244
-	}
245
-	return false;
215
+    include_spip('inc/chiffrer');
216
+    $cles = SpipCles::instance();
217
+    $secret = $cles->getSecretAuth();
218
+
219
+    // on ne fait rien si on a un secret dispo
220
+    if ($secret) {
221
+        return false;
222
+    }
223
+
224
+    // si force, on ne verifie pas la presence d'un backup chez un webmestre
225
+    if ($force) {
226
+        spip_log('Pas de cle secrete disponible, on regenere une nouvelle cle forcee - tous les mots de passe sont invalides', 'auth' . _LOG_INFO_IMPORTANTE);
227
+        $secret = $cles->getSecretAuth(true);
228
+        return true;
229
+    }
230
+
231
+    $has_backup = sql_allfetsel('id_auteur', 'spip_auteurs', 'statut=' . sql_quote('0minirezo') . ' AND webmestre=' . sql_quote('oui') . " AND backup_cles!=''");
232
+    $has_backup = array_column($has_backup, 'id_auteur');
233
+    if (empty($has_backup)) {
234
+        spip_log("Pas de cle secrete disponible, et aucun webmestre n'a de backup, on regenere une nouvelle cle - tous les mots de passe sont invalides", 'auth' . _LOG_INFO_IMPORTANTE);
235
+        if ($secret = $cles->getSecretAuth(true)) {
236
+            return true;
237
+        }
238
+        spip_log("Echec generation d'une nouvelle cle : verifier les droits d'ecriture ?", 'auth' . _LOG_ERREUR);
239
+        // et on echoue car on ne veut pas que la situation reste telle quelle
240
+        raler_fichier(_DIR_ETC . 'cles.php');
241
+    }
242
+    else {
243
+        spip_log('Pas de cle secrete disponible (fichier config/cle.php absent ?) un des webmestres #' . implode(', #', $has_backup) . ' doit se connecter pour restaurer son backup des cles', 'auth' . _LOG_ERREUR);
244
+    }
245
+    return false;
246 246
 }
247 247
 
248 248
 /**
@@ -252,19 +252,19 @@  discard block
 block discarded – undo
252 252
  * @return array
253 253
  */
254 254
 function auth_spip_formulaire_login($flux) {
255
-	// javascript qui gere la securite du login en evitant de faire circuler le pass en clair
256
-	$js = file_get_contents(find_in_path('prive/javascript/login.js'));
257
-	$flux['data'] .=
258
-		  '<script type="text/javascript">/*<![CDATA[*/'
259
-		. "$js\n"
260
-		. "var login_info={'login':'" . $flux['args']['contexte']['var_login'] . "',"
261
-		. "'page_auteur': '" . generer_url_public('informer_auteur') . "',"
262
-		. "'informe_auteur_en_cours':false,"
263
-		. "'attente_informe':0};"
264
-		. "jQuery(function(){jQuery('#var_login').change(actualise_auteur);});"
265
-		. '/*]]>*/</script>';
266
-
267
-	return $flux;
255
+    // javascript qui gere la securite du login en evitant de faire circuler le pass en clair
256
+    $js = file_get_contents(find_in_path('prive/javascript/login.js'));
257
+    $flux['data'] .=
258
+            '<script type="text/javascript">/*<![CDATA[*/'
259
+        . "$js\n"
260
+        . "var login_info={'login':'" . $flux['args']['contexte']['var_login'] . "',"
261
+        . "'page_auteur': '" . generer_url_public('informer_auteur') . "',"
262
+        . "'informe_auteur_en_cours':false,"
263
+        . "'attente_informe':0};"
264
+        . "jQuery(function(){jQuery('#var_login').change(actualise_auteur);});"
265
+        . '/*]]>*/</script>';
266
+
267
+    return $flux;
268 268
 }
269 269
 
270 270
 
@@ -276,11 +276,11 @@  discard block
 block discarded – undo
276 276
  *   toujours true pour un auteur cree dans SPIP
277 277
  */
278 278
 function auth_spip_autoriser_modifier_login(string $serveur = ''): bool {
279
-	// les fonctions d'ecriture sur base distante sont encore incompletes
280
-	if (strlen($serveur)) {
281
-		return false;
282
-	}
283
-	return true;
279
+    // les fonctions d'ecriture sur base distante sont encore incompletes
280
+    if (strlen($serveur)) {
281
+        return false;
282
+    }
283
+    return true;
284 284
 }
285 285
 
286 286
 /**
@@ -294,25 +294,25 @@  discard block
 block discarded – undo
294 294
  *  message d'erreur si login non valide, chaine vide sinon
295 295
  */
296 296
 function auth_spip_verifier_login($new_login, $id_auteur = 0, $serveur = '') {
297
-	// login et mot de passe
298
-	if (strlen($new_login)) {
299
-		if (strlen($new_login) < _LOGIN_TROP_COURT) {
300
-			return _T('info_login_trop_court_car_pluriel', ['nb' => _LOGIN_TROP_COURT]);
301
-		} else {
302
-			$n = sql_countsel(
303
-				'spip_auteurs',
304
-				'login=' . sql_quote($new_login) . ' AND id_auteur!=' . intval($id_auteur) . " AND statut!='5poubelle'",
305
-				'',
306
-				'',
307
-				$serveur
308
-			);
309
-			if ($n) {
310
-				return _T('info_login_existant');
311
-			}
312
-		}
313
-	}
314
-
315
-	return '';
297
+    // login et mot de passe
298
+    if (strlen($new_login)) {
299
+        if (strlen($new_login) < _LOGIN_TROP_COURT) {
300
+            return _T('info_login_trop_court_car_pluriel', ['nb' => _LOGIN_TROP_COURT]);
301
+        } else {
302
+            $n = sql_countsel(
303
+                'spip_auteurs',
304
+                'login=' . sql_quote($new_login) . ' AND id_auteur!=' . intval($id_auteur) . " AND statut!='5poubelle'",
305
+                '',
306
+                '',
307
+                $serveur
308
+            );
309
+            if ($n) {
310
+                return _T('info_login_existant');
311
+            }
312
+        }
313
+    }
314
+
315
+    return '';
316 316
 }
317 317
 
318 318
 /**
@@ -324,41 +324,41 @@  discard block
 block discarded – undo
324 324
  * @return bool
325 325
  */
326 326
 function auth_spip_modifier_login($new_login, $id_auteur, $serveur = '') {
327
-	if (is_null($new_login) or auth_spip_verifier_login($new_login, $id_auteur, $serveur) != '') {
328
-		return false;
329
-	}
330
-	if (
331
-		!$id_auteur = intval($id_auteur)
332
-		or !$auteur = sql_fetsel('login', 'spip_auteurs', 'id_auteur=' . intval($id_auteur), '', '', '', '', $serveur)
333
-	) {
334
-		return false;
335
-	}
336
-	if ($new_login == $auteur['login']) {
337
-		return true;
338
-	} // on a rien fait mais c'est bon !
339
-
340
-	include_spip('action/editer_auteur');
341
-
342
-	// vider le login des auteurs a la poubelle qui avaient ce meme login
343
-	if (strlen($new_login)) {
344
-		$anciens = sql_allfetsel(
345
-			'id_auteur',
346
-			'spip_auteurs',
347
-			'login=' . sql_quote($new_login, $serveur, 'text') . " AND statut='5poubelle'",
348
-			'',
349
-			'',
350
-			'',
351
-			'',
352
-			$serveur
353
-		);
354
-		while ($row = array_pop($anciens)) {
355
-			auteur_modifier($row['id_auteur'], ['login' => ''], true); // manque la gestion de $serveur
356
-		}
357
-	}
358
-
359
-	auteur_modifier($id_auteur, ['login' => $new_login], true); // manque la gestion de $serveur
360
-
361
-	return true;
327
+    if (is_null($new_login) or auth_spip_verifier_login($new_login, $id_auteur, $serveur) != '') {
328
+        return false;
329
+    }
330
+    if (
331
+        !$id_auteur = intval($id_auteur)
332
+        or !$auteur = sql_fetsel('login', 'spip_auteurs', 'id_auteur=' . intval($id_auteur), '', '', '', '', $serveur)
333
+    ) {
334
+        return false;
335
+    }
336
+    if ($new_login == $auteur['login']) {
337
+        return true;
338
+    } // on a rien fait mais c'est bon !
339
+
340
+    include_spip('action/editer_auteur');
341
+
342
+    // vider le login des auteurs a la poubelle qui avaient ce meme login
343
+    if (strlen($new_login)) {
344
+        $anciens = sql_allfetsel(
345
+            'id_auteur',
346
+            'spip_auteurs',
347
+            'login=' . sql_quote($new_login, $serveur, 'text') . " AND statut='5poubelle'",
348
+            '',
349
+            '',
350
+            '',
351
+            '',
352
+            $serveur
353
+        );
354
+        while ($row = array_pop($anciens)) {
355
+            auteur_modifier($row['id_auteur'], ['login' => ''], true); // manque la gestion de $serveur
356
+        }
357
+    }
358
+
359
+    auteur_modifier($id_auteur, ['login' => $new_login], true); // manque la gestion de $serveur
360
+
361
+    return true;
362 362
 }
363 363
 
364 364
 /**
@@ -370,44 +370,44 @@  discard block
 block discarded – undo
370 370
  * @return string
371 371
  */
372 372
 function auth_spip_retrouver_login($login, $serveur = '') {
373
-	if (!strlen($login)) {
374
-		return null;
375
-	} // pas la peine de requeter
376
-	$l = sql_quote($login, $serveur, 'text');
377
-	if (
378
-		$r = sql_getfetsel(
379
-			'login',
380
-			'spip_auteurs',
381
-			"statut<>'5poubelle'" .
382
-			' AND (length(pass)>0)' .
383
-			" AND (login=$l)",
384
-			'',
385
-			'',
386
-			'',
387
-			'',
388
-			$serveur
389
-		)
390
-	) {
391
-		return $r;
392
-	}
393
-	// Si pas d'auteur avec ce login
394
-	// regarder s'il a saisi son nom ou son mail.
395
-	// Ne pas fusionner avec la requete precedente
396
-	// car un nom peut etre homonyme d'un autre login
397
-	else {
398
-		return sql_getfetsel(
399
-			'login',
400
-			'spip_auteurs',
401
-			"statut<>'5poubelle'" .
402
-			' AND (length(pass)>0)' .
403
-			" AND (login<>'' AND (nom=$l OR email=$l))",
404
-			'',
405
-			'',
406
-			'',
407
-			'',
408
-			$serveur
409
-		);
410
-	}
373
+    if (!strlen($login)) {
374
+        return null;
375
+    } // pas la peine de requeter
376
+    $l = sql_quote($login, $serveur, 'text');
377
+    if (
378
+        $r = sql_getfetsel(
379
+            'login',
380
+            'spip_auteurs',
381
+            "statut<>'5poubelle'" .
382
+            ' AND (length(pass)>0)' .
383
+            " AND (login=$l)",
384
+            '',
385
+            '',
386
+            '',
387
+            '',
388
+            $serveur
389
+        )
390
+    ) {
391
+        return $r;
392
+    }
393
+    // Si pas d'auteur avec ce login
394
+    // regarder s'il a saisi son nom ou son mail.
395
+    // Ne pas fusionner avec la requete precedente
396
+    // car un nom peut etre homonyme d'un autre login
397
+    else {
398
+        return sql_getfetsel(
399
+            'login',
400
+            'spip_auteurs',
401
+            "statut<>'5poubelle'" .
402
+            ' AND (length(pass)>0)' .
403
+            " AND (login<>'' AND (nom=$l OR email=$l))",
404
+            '',
405
+            '',
406
+            '',
407
+            '',
408
+            $serveur
409
+        );
410
+    }
411 411
 }
412 412
 
413 413
 /**
@@ -418,11 +418,11 @@  discard block
 block discarded – undo
418 418
  *  toujours true pour un auteur cree dans SPIP
419 419
  */
420 420
 function auth_spip_autoriser_modifier_pass(string $serveur = ''): bool {
421
-	// les fonctions d'ecriture sur base distante sont encore incompletes
422
-	if (strlen($serveur)) {
423
-		return false;
424
-	}
425
-	return true;
421
+    // les fonctions d'ecriture sur base distante sont encore incompletes
422
+    if (strlen($serveur)) {
423
+        return false;
424
+    }
425
+    return true;
426 426
 }
427 427
 
428 428
 
@@ -443,12 +443,12 @@  discard block
 block discarded – undo
443 443
  *  message d'erreur si login non valide, chaine vide sinon
444 444
  */
445 445
 function auth_spip_verifier_pass($login, $new_pass, $id_auteur = 0, $serveur = '') {
446
-	// login et mot de passe
447
-	if (strlen($new_pass) < _PASS_LONGUEUR_MINI) {
448
-		return _T('info_passe_trop_court_car_pluriel', ['nb' => _PASS_LONGUEUR_MINI]);
449
-	}
446
+    // login et mot de passe
447
+    if (strlen($new_pass) < _PASS_LONGUEUR_MINI) {
448
+        return _T('info_passe_trop_court_car_pluriel', ['nb' => _PASS_LONGUEUR_MINI]);
449
+    }
450 450
 
451
-	return '';
451
+    return '';
452 452
 }
453 453
 
454 454
 /**
@@ -462,48 +462,48 @@  discard block
 block discarded – undo
462 462
  * @return bool
463 463
  */
464 464
 function auth_spip_modifier_pass($login, $new_pass, $id_auteur, $serveur = '') {
465
-	if (is_null($new_pass) or auth_spip_verifier_pass($login, $new_pass, $id_auteur, $serveur) != '') {
466
-		return false;
467
-	}
468
-
469
-	if (
470
-		!$id_auteur = intval($id_auteur)
471
-		or !$auteur = sql_fetsel('login, statut, webmestre', 'spip_auteurs', 'id_auteur=' . intval($id_auteur), '', '', '', '', $serveur)
472
-	) {
473
-		return false;
474
-	}
475
-
476
-	include_spip('inc/chiffrer');
477
-	$cles = SpipCles::instance();
478
-	$secret = $cles->getSecretAuth();
479
-	if (!$secret) {
480
-		if (auth_spip_initialiser_secret()) {
481
-			$secret = $cles->getSecretAuth();
482
-		}
483
-		else {
484
-			return false;
485
-		}
486
-	}
487
-
488
-
489
-	include_spip('inc/acces');
490
-	$set = [
491
-		'pass' => Password::hacher($new_pass, $secret),
492
-		'htpass' => generer_htpass($new_pass),
493
-		'alea_actuel' => creer_uniqid(), // @deprecated 4.1
494
-		'alea_futur' => creer_uniqid(), // @deprecated 4.1
495
-		'low_sec' => '',
496
-	];
497
-
498
-	// si c'est un webmestre, on met a jour son backup des cles
499
-	if ($auteur['statut'] === '0minirezo' and $auteur['webmestre'] === 'oui') {
500
-		$set['backup_cles'] = $cles->backup($new_pass);
501
-	}
502
-
503
-	include_spip('action/editer_auteur');
504
-	auteur_modifier($id_auteur, $set, true); // manque la gestion de $serveur
505
-
506
-	return true; // on a bien modifie le pass
465
+    if (is_null($new_pass) or auth_spip_verifier_pass($login, $new_pass, $id_auteur, $serveur) != '') {
466
+        return false;
467
+    }
468
+
469
+    if (
470
+        !$id_auteur = intval($id_auteur)
471
+        or !$auteur = sql_fetsel('login, statut, webmestre', 'spip_auteurs', 'id_auteur=' . intval($id_auteur), '', '', '', '', $serveur)
472
+    ) {
473
+        return false;
474
+    }
475
+
476
+    include_spip('inc/chiffrer');
477
+    $cles = SpipCles::instance();
478
+    $secret = $cles->getSecretAuth();
479
+    if (!$secret) {
480
+        if (auth_spip_initialiser_secret()) {
481
+            $secret = $cles->getSecretAuth();
482
+        }
483
+        else {
484
+            return false;
485
+        }
486
+    }
487
+
488
+
489
+    include_spip('inc/acces');
490
+    $set = [
491
+        'pass' => Password::hacher($new_pass, $secret),
492
+        'htpass' => generer_htpass($new_pass),
493
+        'alea_actuel' => creer_uniqid(), // @deprecated 4.1
494
+        'alea_futur' => creer_uniqid(), // @deprecated 4.1
495
+        'low_sec' => '',
496
+    ];
497
+
498
+    // si c'est un webmestre, on met a jour son backup des cles
499
+    if ($auteur['statut'] === '0minirezo' and $auteur['webmestre'] === 'oui') {
500
+        $set['backup_cles'] = $cles->backup($new_pass);
501
+    }
502
+
503
+    include_spip('action/editer_auteur');
504
+    auteur_modifier($id_auteur, $set, true); // manque la gestion de $serveur
505
+
506
+    return true; // on a bien modifie le pass
507 507
 }
508 508
 
509 509
 /**
@@ -517,58 +517,58 @@  discard block
 block discarded – undo
517 517
  * @return void
518 518
  */
519 519
 function auth_spip_synchroniser_distant($id_auteur, $champs, $options = [], string $serveur = ''): void {
520
-	// ne rien faire pour une base distante : on ne sait pas regenerer les htaccess
521
-	if (strlen($serveur)) {
522
-		return;
523
-	}
524
-	// si un login, pass ou statut a ete modifie
525
-	// regenerer les fichier htpass
526
-	if (
527
-		isset($champs['login'])
528
-		or isset($champs['pass'])
529
-		or isset($champs['statut'])
530
-		or (isset($options['all']) and $options['all'])
531
-	) {
532
-		$htaccess = _DIR_RESTREINT . _ACCESS_FILE_NAME;
533
-		$htpasswd = _DIR_TMP . _AUTH_USER_FILE;
534
-
535
-		// Cette variable de configuration peut etre posee par un plugin
536
-		// par exemple acces_restreint ;
537
-		// si .htaccess existe, outrepasser spip_meta
538
-		if (
539
-			(!isset($GLOBALS['meta']['creer_htpasswd']) or ($GLOBALS['meta']['creer_htpasswd'] != 'oui'))
540
-			and !@file_exists($htaccess)
541
-		) {
542
-			spip_unlink($htpasswd);
543
-			spip_unlink($htpasswd . '-admin');
544
-
545
-			return;
546
-		}
547
-
548
-		# remarque : ici on laisse passer les "nouveau" de maniere a leur permettre
549
-		# de devenir redacteur le cas echeant (auth http)... a nettoyer
550
-		// attention, il faut au prealable se connecter a la base (necessaire car utilise par install)
551
-
552
-		$p1 = ''; // login:htpass pour tous
553
-		$p2 = ''; // login:htpass pour les admins
554
-		$s = sql_select(
555
-			'login, htpass, statut',
556
-			'spip_auteurs',
557
-			sql_in('statut', ['1comite', '0minirezo', 'nouveau'])
558
-		);
559
-		while ($t = sql_fetch($s)) {
560
-			if (strlen($t['login']) and strlen($t['htpass'])) {
561
-				$p1 .= $t['login'] . ':' . $t['htpass'] . "\n";
562
-				if ($t['statut'] == '0minirezo') {
563
-					$p2 .= $t['login'] . ':' . $t['htpass'] . "\n";
564
-				}
565
-			}
566
-		}
567
-		sql_free($s);
568
-		if ($p1) {
569
-			ecrire_fichier($htpasswd, $p1);
570
-			ecrire_fichier($htpasswd . '-admin', $p2);
571
-			spip_log("Ecriture de $htpasswd et $htpasswd-admin");
572
-		}
573
-	}
520
+    // ne rien faire pour une base distante : on ne sait pas regenerer les htaccess
521
+    if (strlen($serveur)) {
522
+        return;
523
+    }
524
+    // si un login, pass ou statut a ete modifie
525
+    // regenerer les fichier htpass
526
+    if (
527
+        isset($champs['login'])
528
+        or isset($champs['pass'])
529
+        or isset($champs['statut'])
530
+        or (isset($options['all']) and $options['all'])
531
+    ) {
532
+        $htaccess = _DIR_RESTREINT . _ACCESS_FILE_NAME;
533
+        $htpasswd = _DIR_TMP . _AUTH_USER_FILE;
534
+
535
+        // Cette variable de configuration peut etre posee par un plugin
536
+        // par exemple acces_restreint ;
537
+        // si .htaccess existe, outrepasser spip_meta
538
+        if (
539
+            (!isset($GLOBALS['meta']['creer_htpasswd']) or ($GLOBALS['meta']['creer_htpasswd'] != 'oui'))
540
+            and !@file_exists($htaccess)
541
+        ) {
542
+            spip_unlink($htpasswd);
543
+            spip_unlink($htpasswd . '-admin');
544
+
545
+            return;
546
+        }
547
+
548
+        # remarque : ici on laisse passer les "nouveau" de maniere a leur permettre
549
+        # de devenir redacteur le cas echeant (auth http)... a nettoyer
550
+        // attention, il faut au prealable se connecter a la base (necessaire car utilise par install)
551
+
552
+        $p1 = ''; // login:htpass pour tous
553
+        $p2 = ''; // login:htpass pour les admins
554
+        $s = sql_select(
555
+            'login, htpass, statut',
556
+            'spip_auteurs',
557
+            sql_in('statut', ['1comite', '0minirezo', 'nouveau'])
558
+        );
559
+        while ($t = sql_fetch($s)) {
560
+            if (strlen($t['login']) and strlen($t['htpass'])) {
561
+                $p1 .= $t['login'] . ':' . $t['htpass'] . "\n";
562
+                if ($t['statut'] == '0minirezo') {
563
+                    $p2 .= $t['login'] . ':' . $t['htpass'] . "\n";
564
+                }
565
+            }
566
+        }
567
+        sql_free($s);
568
+        if ($p1) {
569
+            ecrire_fichier($htpasswd, $p1);
570
+            ecrire_fichier($htpasswd . '-admin', $p2);
571
+            spip_log("Ecriture de $htpasswd et $htpasswd-admin");
572
+        }
573
+    }
574 574
 }
Please login to merge, or discard this patch.