Completed
Push — master ( 52184e...8915f1 )
by cam
04:39
created

filtres_images_lib_mini.php ➔ _imagecreatefrom_func()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 10
Ratio 71.43 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 10
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
/* *************************************************************************\
4
 *  SPIP, Système de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright © avec tendresse depuis 2001                                 *
7
 *  Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James  *
8
 *                                                                         *
9
 *  Ce programme est un logiciel libre distribué sous licence GNU/GPL.     *
10
 *  Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne.   *
11
\***************************************************************************/
12
13
/**
14
 * Ce fichier contient les fonctions utilisées
15
 * par les fonctions-filtres de traitement d'image.
16
 *
17
 * @package SPIP\Core\Filtres\Images
18
 */
19
20
21
if (!defined('_ECRIRE_INC_VERSION')) {
22
	return;
23
}
24
include_spip('inc/filtres'); // par precaution
25
include_spip('inc/filtres_images_mini'); // par precaution
26
27
define('_SVG_SUPPORTED', true); // ne sert qu'a la lisibilite du code
28
29
/**
30
 * Transforme une couleur vectorielle R,G,B en hexa (par exemple pour usage css)
31
 *
32
 * @param int $red
33
 *     Valeur du rouge de 0 à 255.
34
 * @param int $green
35
 *     Valeur du vert de 0 à 255.
36
 * @param int $blue
37
 *     Valeur du bleu de 0 à 255.
38
 * @return string
39
 *     Le code de la couleur en hexadécimal.
40
 */
41
function _couleur_dec_to_hex($red, $green, $blue) {
42
	$red = dechex($red);
43
	$green = dechex($green);
44
	$blue = dechex($blue);
45
46
	if (strlen($red) == 1) {
47
		$red = "0" . $red;
48
	}
49
	if (strlen($green) == 1) {
50
		$green = "0" . $green;
51
	}
52
	if (strlen($blue) == 1) {
53
		$blue = "0" . $blue;
54
	}
55
56
	return "$red$green$blue";
57
}
58
59
/**
60
 * Transforme une couleur hexa en vectorielle R,G,B
61
 *
62
 * @param string $couleur
63
 *     Code couleur en hexa (#000000 à #FFFFFF).
64
 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,integer|double>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
65
 *     Un tableau des 3 éléments : rouge, vert, bleu.
66
 */
67
function _couleur_hex_to_dec($couleur) {
68
	$couleur = couleur_html_to_hex($couleur);
69
	$couleur = ltrim($couleur, '#');
70
	if (strlen($couleur) === 3) {
71
		$couleur = $couleur[0] . $couleur[0] . $couleur[1] . $couleur[1] . $couleur[2] . $couleur[2];
72
	}
73
	$retour["red"] = hexdec(substr($couleur, 0, 2));
0 ignored issues
show
Coding Style Comprehensibility introduced by
$retour was never initialized. Although not strictly required by PHP, it is generally a good practice to add $retour = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
74
	$retour["green"] = hexdec(substr($couleur, 2, 2));
75
	$retour["blue"] = hexdec(substr($couleur, 4, 2));
76
77
	return $retour;
78
}
79
80
/**
81
 * Donne un statut au fichier-image intermédiaire servant au traitement d'image
82
 * selon qu'il doit être gravé (fichier .src) ou pas.
83
 *
84
 * Un appel PHP direct aux fonctions de filtre d'image produira ainsi une image
85
 * permanente (gravée) ; un appel généré par le compilateur via
86
 * `filtrer('image_xx, ...)` effacera automatiquement le fichier-image temporaire.
87
 *
88
 * @param bool|string $stat
89
 *     true, false ou le statut déjà défini si traitements enchaînés.
90
 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|null?

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

Loading history...
91
 *     true si il faut supprimer le fichier temporaire ; false sinon.
92
 */
93
function statut_effacer_images_temporaires($stat) {
94
	static $statut = false; // par defaut on grave toute les images
95
	if ($stat === 'get') {
96
		return $statut;
97
	}
98
	$statut = $stat ? true : false;
99
}
100
101
102
/**
103
 * Fonctions de preparation aux filtres de traitement d'image
104
 * les fonctions de lecture et d'ecriture renseignees traitent uniquement le cas GD2
105
 * qui est le cas general des filtres images
106
 *
107
 * mais image_reduire utilise aussi cette fonction en adaptant le traitement
108
 * en fonction de la librairie graphique choisie dans la configuration de SPIP
109
 *
110
 * @pipeline_appel image_preparer_filtre
111
 * @uses extraire_attribut()
112
 * @uses inserer_attribut()
113
 * @uses tester_url_absolue()
114
 * @uses copie_locale() Si l'image est distante
115
 * @uses taille_image()
116
 * @uses _image_ratio()
117
 * @uses reconstruire_image_intermediaire()
118
 *
119
 * @param string $img
120
 *     Chemin de l'image ou balise html `<img src=... />`.
121
 * @param string $effet
122
 *     Les nom et paramètres de l'effet à apporter sur l'image
123
 *     (par exemple : reduire-300-200).
124
 * @param bool|string $forcer_format
125
 *     Un nom d'extension spécifique demandé (par exemple : jpg, png, txt...).
126
 *     Par défaut false : GD se débrouille seule).
127
 * @param array $fonction_creation
0 ignored issues
show
Documentation introduced by
Should the type for parameter $fonction_creation not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
128
 *     Un tableau à 2 éléments :
129
 *     1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ;
130
 *     2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé.
131
 * @param bool $find_in_path
132
 *     false (par défaut) indique que l'on travaille sur un fichier
133
 *     temporaire (.src) ; true, sur un fichier définitif déjà existant.
134
 * @param bool $support_svg
135
 *     false (par defaut) indique que le filtre ne sait pas traiter le cas particulier du SVG
136
 *     on lui substitue un filtre generique qui ne fait rien pour ne pas briser la chaine des filtres images
137
 *     true si le filtre appelant sait traiter les SVG
138
 * @return bool|string|array
139
 *
140
 *     - false si pas de tag `<img`,
141
 *       -   si l'extension n'existe pas,
142
 *       -   si le fichier source n'existe pas,
143
 *       -   si les dimensions de la source ne sont pas accessibles,
144
 *       -   si le fichier temporaire n'existe pas,
145
 *       -   si la fonction `_imagecreatefrom{extension}` n'existe pas ;
146
 *     - "" (chaîne vide) si le fichier source est distant et n'a pas
147
 *       réussi à être copié sur le serveur ;
148
 *     - array : tableau décrivant de l'image
149
 */
150
function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = null, $find_in_path = false, $support_svg = false) {
151
	static $images_recalcul = array();
152
	if (strlen($img) == 0) {
153
		return false;
154
	}
155
156
	$source = trim(extraire_attribut($img, 'src'));
157
	if (strlen($source) < 1) {
158
		$source = $img;
159
		$img = "<img src='$source' />";
160
	} # gerer img src="data:....base64"
161
	elseif (preg_match('@^data:image/([^;]*);base64,(.*)$@isS', $source, $regs)
162
	  and $extension = _image_trouver_extension_depuis_mime("image/".$regs[1])
163
		and in_array($extension, _image_extensions_acceptees_en_entree())
164
	) {
165
		$local = sous_repertoire(_DIR_VAR, 'image-data') . md5($regs[2]) . '.' . _image_extension_normalisee($extension);
166
		if (!file_exists($local)) {
167
			ecrire_fichier($local, base64_decode($regs[2]));
168
		}
169
		$source = $local;
170
		$img = inserer_attribut($img, 'src', $source);
171
		# eviter les mauvaises surprises lors de conversions de format
172
		$img = inserer_attribut($img, 'width', '');
173
		$img = inserer_attribut($img, 'height', '');
174
	}
175
176
	// les protocoles web prennent au moins 3 lettres
177
	if (tester_url_absolue($source)) {
178
		include_spip('inc/distant');
179
		$fichier = _DIR_RACINE . copie_locale($source);
180
		if (!$fichier) {
181
			return "";
182
		}
183
	} else {
184
		// enlever le timestamp eventuel
185
		if (strpos($source, "?") !== false) {
186
			$source = preg_replace(',[?][0-9]+$,', '', $source);
187
		}
188
		if (strpos($source, "?") !== false
189
			and strncmp($source, _DIR_IMG, strlen(_DIR_IMG)) == 0
190
			and file_exists($f = preg_replace(',[?].*$,', '', $source))
191
		) {
192
			$source = $f;
193
		}
194
		$fichier = $source;
195
	}
196
197
	$terminaison_dest = "";
198
	if ($terminaison = _image_trouver_extension($fichier)) {
199
		$terminaison_dest = ($terminaison == 'gif') ? 'png' : $terminaison;
200
	}
201
202
	if ($forcer_format !== false
203
		// 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
204
		and ($terminaison_dest !== 'svg' or $support_svg or !in_array($forcer_format,_image_extensions_acceptees_en_sortie()))) {
205
		$terminaison_dest = $forcer_format;
206
	}
207
208
	if (!$terminaison_dest) {
209
		return false;
210
	}
211
212
	$nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
213
	$fichier_dest = $nom_fichier;
214
	if (($find_in_path and $f = find_in_path($fichier) and $fichier = $f)
0 ignored issues
show
Bug introduced by
The variable $f does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
215
		or @file_exists($f = $fichier)
216
	) {
217
		// on passe la balise img a taille image qui exraira les attributs si possible
218
		// au lieu de faire un acces disque sur le fichier
219
		list($ret["hauteur"], $ret["largeur"]) = taille_image($find_in_path ? $f : $img);
220
		$date_src = @filemtime($f);
221
	} elseif (@file_exists($f = "$fichier.src")
222
		and lire_fichier($f, $valeurs)
223
		and $valeurs = unserialize($valeurs)
224
		and isset($valeurs["hauteur_dest"])
225
		and isset($valeurs["largeur_dest"])
226
	) {
227
		$ret["hauteur"] = $valeurs["hauteur_dest"];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ret was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ret = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
228
		$ret["largeur"] = $valeurs["largeur_dest"];
229
		$date_src = $valeurs["date"];
230
	} // pas de fichier source par la
231
	else {
232
		return false;
233
	}
234
235
	// pas de taille mesurable
236
	if (!($ret["hauteur"] or $ret["largeur"])) {
0 ignored issues
show
Bug introduced by
The variable $ret does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
237
		return false;
238
	}
239
240
	// les images calculees dependent du chemin du fichier source
241
	// 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
242
	// ce n'est pas totalement optimal en terme de stockage, mais chaque image est associee a un fichier .src
243
	// qui contient la methode de reconstrucion (le filtre + les arguments d'appel) et les arguments different entre prive et public
244
	// la mise en commun du fichier image cree donc un bug et des problemes qui necessiteraient beaucoup de complexite de code
245
	// alors que ca concerne peu de site au final
246
	// la release de r23632+r23633+r23634 a provoque peu de remontee de bug attestant du peu de sites impactes
247
	$identifiant = $fichier;
248
249
	// cas general :
250
	// on a un dossier cache commun et un nom de fichier qui varie avec l'effet
251
	// cas particulier de reduire :
252
	// un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
253
	$cache = "cache-gd2";
254
	if (substr($effet, 0, 7) == 'reduire') {
255
		list(, $maxWidth, $maxHeight) = explode('-', $effet);
256
		list($destWidth, $destHeight) = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
257
		$ret['largeur_dest'] = $destWidth;
258
		$ret['hauteur_dest'] = $destHeight;
259
		$effet = "L{$destWidth}xH$destHeight";
260
		$cache = "cache-vignettes";
261
		$fichier_dest = basename($fichier_dest);
262
		if (($ret['largeur'] <= $maxWidth) && ($ret['hauteur'] <= $maxHeight)) {
263
			// on garde la terminaison initiale car image simplement copiee
264
			// et on postfixe son nom avec un md5 du path
265
			$terminaison_dest = $terminaison;
266
			$fichier_dest .= '-' . substr(md5("$identifiant"), 0, 5);
267
		} else {
268
			$fichier_dest .= '-' . substr(md5("$identifiant-$effet"), 0, 5);
269
		}
270
		$cache = sous_repertoire(_DIR_VAR, $cache);
271
		$cache = sous_repertoire($cache, $effet);
272
	} else {
273
		$fichier_dest = md5("$identifiant-$effet");
274
		$cache = sous_repertoire(_DIR_VAR, $cache);
275
		$cache = sous_repertoire($cache, substr($fichier_dest, 0, 2));
276
		$fichier_dest = substr($fichier_dest, 2);
277
	}
278
279
	$fichier_dest = $cache . $fichier_dest . "." . $terminaison_dest;
280
281
	$GLOBALS["images_calculees"][] = $fichier_dest;
282
283
	$creer = true;
284
	// si recalcul des images demande, recalculer chaque image une fois
285
	if (defined('_VAR_IMAGES') and _VAR_IMAGES and !isset($images_recalcul[$fichier_dest])) {
286
		$images_recalcul[$fichier_dest] = true;
287
	} else {
288
		if (@file_exists($f = $fichier_dest)) {
289
			if (filemtime($f) >= $date_src) {
290
				$creer = false;
291
			}
292
		} else {
293
			if (@file_exists($f = "$fichier_dest.src")
294
				and lire_fichier($f, $valeurs)
295
				and $valeurs = unserialize($valeurs)
296
				and $valeurs["date"] >= $date_src
297
			) {
298
				$creer = false;
299
			}
300
		}
301
	}
302
	if ($creer) {
303
		if (!@file_exists($fichier)) {
304
			if (!@file_exists("$fichier.src")) {
305
				spip_log("Image absente : $fichier");
306
307
				return false;
308
			}
309
			# on reconstruit l'image source absente a partir de la chaine des .src
310
			reconstruire_image_intermediaire($fichier);
0 ignored issues
show
Bug introduced by
It seems like $fichier defined by $f on line 214 can also be of type boolean; however, reconstruire_image_intermediaire() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
311
		}
312
	}
313
314
	if ($creer) {
315
		spip_log("filtre image " . ($fonction_creation ? reset($fonction_creation) : '') . "[$effet] sur $fichier",
316
			"images" . _LOG_DEBUG);
317
	}
318
319
	$term_fonction = _image_trouver_extension_pertinente($fichier);
0 ignored issues
show
Bug introduced by
It seems like $fichier defined by $f on line 214 can also be of type boolean; however, _image_trouver_extension_pertinente() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
320
	$ret["fonction_imagecreatefrom"] = "_imagecreatefrom" . $term_fonction;
321
	$ret["fichier"] = $fichier;
322
	$ret["fonction_image"] = "_image_image" . $terminaison_dest;
323
	$ret["fichier_dest"] = $fichier_dest;
324
	$ret["format_source"] = _image_extension_normalisee($terminaison);
325
	$ret["format_dest"] = $terminaison_dest;
326
	$ret["date_src"] = $date_src;
327
	$ret["creer"] = $creer;
328
	$ret["class"] = extraire_attribut($img, 'class');
329
	$ret["alt"] = extraire_attribut($img, 'alt');
330
	$ret["style"] = extraire_attribut($img, 'style');
331
	$ret["tag"] = $img;
332
	if ($fonction_creation) {
333
		$ret["reconstruction"] = $fonction_creation;
334
		# ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement 
335
		# cas de image_reduire qui finalement ne reduit pas l'image source
336
		# ca evite d'essayer de le creer au prochain hit si il n'est pas la
337
		#ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
338
	}
339
340
	$ret = pipeline('image_preparer_filtre', array(
341
			'args' => array(
342
				'img' => $img,
343
				'effet' => $effet,
344
				'forcer_format' => $forcer_format,
345
				'fonction_creation' => $fonction_creation,
346
				'find_in_path' => $find_in_path,
347
			),
348
			'data' => $ret
349
		)
350
	);
351
352
	// une globale pour le debug en cas de crash memoire
353
	$GLOBALS["derniere_image_calculee"] = $ret;
354
355
	// traiter le cas particulier des SVG : si le filtre n'a pas annonce explicitement qu'il savait faire, on delegue
356
	if ($term_fonction === 'svg') {
357
		if ($creer and !$support_svg) {
358
			process_image_svg_identite($ret);
359
			$ret['creer'] = false;
360
		}
361
	}
362
	else {
363
		if (!function_exists($ret["fonction_imagecreatefrom"])) {
364
			return false;
365
		}
366
	}
367
368
	return $ret;
369
}
370
371
372
/**
373
 * @param string $quoi
0 ignored issues
show
Bug introduced by
There is no parameter named $quoi. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
374
 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
375
 */
376
function _image_extensions_acceptees_en_entree() {
377
	static $extensions = null;
378
	if (empty($extensions)) {
379
		$extensions = ['png', 'gif', 'jpg', 'jpeg'];
380
		if (!empty($GLOBALS['meta']['gd_formats'])) {
381
			// action=tester renseigne gd_formats et detecte le support de webp
382
			$extensions = array_merge(explode(',', $GLOBALS['meta']['gd_formats']));
383
			$extensions = array_map('trim', $extensions);
384
			$extensions = array_filter($extensions);
385
			$extensions = array_unique($extensions);
386
		}
387
		$extensions[] = 'svg'; // on le supporte toujours avec des fonctions specifiques
388
	}
389
390
	return $extensions;
391
}
392
393
/**
394
 * @return array|string[]|null
395
 */
396
function _image_extensions_acceptees_en_sortie(){
397
	static $extensions = null;
398
	if (empty($extensions)){
399
		$extensions = _image_extensions_acceptees_en_entree();
400
		$extensions = array_diff($extensions, ['jpeg']);
401 View Code Duplication
		if (in_array('gif', $extensions) and !function_exists('imagegif')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
402
			$extensions = array_diff($extensions, ['gif']);
403
		}
404 View Code Duplication
		if (in_array('webp', $extensions) and !function_exists('imagewebp')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
405
			$extensions = array_diff($extensions, ['webp']);
406
		}
407
	}
408
409
	return $extensions;
410
}
411
412
function _image_extension_normalisee($extension){
413
	$extension = strtolower($extension);
414
	if ($extension === 'jpeg') {
415
		$extension = 'jpg';
416
	}
417
	return $extension;
418
}
419
420
function _image_extensions_conservent_transparence(){
421
	return ['png', 'webp'];
422
}
423
424
425
/**
426
 * Retourne la terminaison d’un fichier image
427
 * @param string $path
428
 * @return string
429
 */
430
function _image_trouver_extension($path) {
431
	$preg_extensions = implode('|', _image_extensions_acceptees_en_entree());
432
	if (preg_match(",\.($preg_extensions)($|[?]),i", $path, $regs)) {
433
		$terminaison = strtolower($regs[1]);
434
		return $terminaison;
435
	}
436
	return '';
437
}
438
439
/**
440
 * Tente de trouver le véritable type d’une image,
441
 * même si une image est d’extension .jpg alors que son contenu est autre chose (gif ou png)
442
 *
443
 * @param string $path
444
 * @return string Extension, dans le format attendu par les fonctions 'gd' ('jpeg' pour les .jpg par exemple)
445
 */
446
function _image_trouver_extension_pertinente($path) {
447
	$path = supprimer_timestamp($path);
448
	$terminaison = _image_trouver_extension($path);
449
	if ($terminaison == 'jpg') {
450
		$terminaison = 'jpeg';
451
	}
452
453
	if (!file_exists($path)) {
454
		return $terminaison;
455
	}
456
457
	if (!$info = @spip_getimagesize($path)) {
458
		return $terminaison;
459
	}
460
461
	if (isset($info['mime'])) {
462
		$mime = $info['mime'];
463
	}
464
	else {
465
		$mime = image_type_to_mime_type($info[2]);
466
	}
467
468
	$_terminaison = _image_trouver_extension_depuis_mime($mime);
469
	if ($_terminaison and $_terminaison !== $terminaison) {
470
		spip_log("Mauvaise extension du fichier : $path . Son type mime est : $mime", "images." . _LOG_INFO_IMPORTANTE);
471
		$terminaison = $_terminaison;
472
	}
473
	return $terminaison;
474
}
475
476
/**
477
 * @param string $mime
478
 * @return string
479
 */
480
function _image_trouver_extension_depuis_mime($mime) {
481
	switch (strtolower($mime)) {
482
		case 'image/png':
483
		case 'image/x-png':
484
			$terminaison = 'png';
485
			break;
486
487
		case 'image/jpg':
488
		case 'image/jpeg':
489
		case 'image/pjpeg':
490
			$terminaison = 'jpeg';
491
			break;
492
493
		case 'image/gif':
494
			$terminaison = 'gif';
495
			break;
496
497
		case 'image/webp':
498
		case 'image/x-webp':
499
			$terminaison = 'webp';
500
			break;
501
502
		case 'image/svg+xml':
503
			$terminaison = 'svg';
504
			break;
505
506
		default:
507
			$terminaison = '';
508
	}
509
510
	return $terminaison;
511
}
512
513
514
/**
515
 * Crée une image depuis un fichier ou une URL (un indiquant la fonction GD à utiliser)
516
 *
517
 * Utilise les fonctions spécifiques GD.
518
 * - Si la fonction GD n'existe pas (GD non actif?), génère une erreur, mais ne retourne rien
519
 * - Si l'image est impossible à créer avec la fonction indiquée, génère une erreur, et une image vide
520
 *
521
 * @param string $func
522
 *     Fonction GD à utiliser tel que 'imagecreatefromjpeg'
523
 * @param string $filename
524
 *     Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg
525
 *     ou local/cache-vignettes/L180xH51/image.jpg).
526
 * @return resource|null
527
 *     Une ressource de type Image GD.
528
 */
529
function _imagecreatefrom_func(string $func, string $filename) {
530 View Code Duplication
	if (!function_exists($func)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
531
		spip_log("GD indisponible : $func inexistante. Traitement $filename impossible.", _LOG_CRITIQUE);
532
		erreur_squelette("GD indisponible : $func inexistante. Traitement $filename impossible.");
533
		return null;
534
	}
535
	$img = @$func($filename);
536 View Code Duplication
	if (!$img) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
537
		spip_log("Erreur lecture imagecreatefromjpeg $filename", _LOG_CRITIQUE);
538
		erreur_squelette("Erreur lecture imagecreatefromjpeg $filename");
539
		$img = imagecreate(10, 10);
540
	}
541
	return $img;
542
}
543
544
/**
545
 * Crée une image depuis un fichier ou une URL (au format jpeg)
546
 *
547
 * Utilise les fonctions spécifiques GD.
548
 *
549
 * @uses _imagecreatefrom_func()
550
 * @param string $filename
551
 *     Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg
552
 *     ou local/cache-vignettes/L180xH51/image.jpg).
553
 * @return resource|null
554
 *     Une ressource de type Image GD.
555
 */
556
function _imagecreatefromjpeg($filename) {
557
	return _imagecreatefrom_func('imagecreatefromjpeg', $filename);
558
}
559
560
/**
561
 * Crée une image depuis un fichier ou une URL (au format png)
562
 *
563
 * Utilise les fonctions spécifiques GD.
564
 *
565
 * @uses _imagecreatefrom_func()
566
 * @param string $filename
567
 *     Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png
568
 *     ou local/cache-vignettes/L180xH51/image.png).
569
 * @return resource|null
570
 *     Une ressource de type Image GD.
571
 */
572
function _imagecreatefrompng($filename) {
573
	return _imagecreatefrom_func('imagecreatefrompng', $filename);
574
}
575
576
/**
577
 * Crée une image depuis un fichier ou une URL (au format gif)
578
 *
579
 * Utilise les fonctions spécifiques GD.
580
 *
581
 * @uses _imagecreatefrom_func()
582
 * @param string $filename
583
 *     Le path vers l'image à traiter (par exemple : IMG/distant/gif/image.gif
584
 *     ou local/cache-vignettes/L180xH51/image.gif).
585
 * @return resource|null
586
 *     Une ressource de type Image GD.
587
 */
588
function _imagecreatefromgif($filename) {
589
	return _imagecreatefrom_func('imagecreatefromgif', $filename);
590
}
591
592
593
/**
594
 * Crée une image depuis un fichier ou une URL (au format webp)
595
 *
596
 * Utilise les fonctions spécifiques GD.
597
 *
598
 * @uses _imagecreatefrom_func()
599
 * @param string $filename
600
 *     Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png
601
 *     ou local/cache-vignettes/L180xH51/image.png).
602
 * @return resource|null
603
 *     Une ressource de type Image GD.
604
 */
605
function _imagecreatefromwebp($filename) {
606
	return _imagecreatefrom_func('imagecreatefromwebp', $filename);
607
}
608
609
/**
610
 * Affiche ou sauvegarde une image au format PNG
611
 *
612
 * Utilise les fonctions spécifiques GD.
613
 *
614
 * @param ressource $img
615
 *     Une ressource de type Image GD.
616
 * @param string $fichier
617
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
618
 * @return bool
619
 *
620
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
621
 *     - true si une image est bien retournée.
622
 */
623 View Code Duplication
function _image_imagepng($img, $fichier) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
624
	if (!function_exists('imagepng')) {
625
		return false;
626
	}
627
	$tmp = $fichier . ".tmp";
628
	$ret = imagepng($img, $tmp);
629
	if (file_exists($tmp)) {
630
		$taille_test = getimagesize($tmp);
631
		if ($taille_test[0] < 1) {
632
			return false;
633
		}
634
635
		spip_unlink($fichier); // le fichier peut deja exister
636
		@rename($tmp, $fichier);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
637
638
		return $ret;
639
	}
640
641
	return false;
642
}
643
644
/**
645
 * Affiche ou sauvegarde une image au format GIF
646
 *
647
 * Utilise les fonctions spécifiques GD.
648
 *
649
 * @param resource $img
650
 *     Une ressource de type Image GD.
651
 * @param string $fichier
652
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.gif).
653
 * @return bool
654
 *
655
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
656
 *     - true si une image est bien retournée.
657
 */
658 View Code Duplication
function _image_imagegif($img, $fichier) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
659
	if (!function_exists('imagegif')) {
660
		return false;
661
	}
662
	$tmp = $fichier . ".tmp";
663
	$ret = imagegif($img, $tmp);
664
	if (file_exists($tmp)) {
665
		$taille_test = getimagesize($tmp);
666
		if ($taille_test[0] < 1) {
667
			return false;
668
		}
669
670
		spip_unlink($fichier); // le fichier peut deja exister
671
		@rename($tmp, $fichier);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
672
673
		return $ret;
674
	}
675
676
	return false;
677
}
678
679
/**
680
 * Affiche ou sauvegarde une image au format JPG
681
 *
682
 * Utilise les fonctions spécifiques GD.
683
 *
684
 * @param resource $img
685
 *     Une ressource de type Image GD.
686
 * @param string $fichier
687
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
688
 * @param int $qualite
689
 *     Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
690
 *     fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
691
 *     valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
692
 *     mes_options.php).
693
 * @return bool
694
 *
695
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
696
 *     - true si une image est bien retournée.
697
 */
698
function _image_imagejpg($img, $fichier, $qualite = _IMG_GD_QUALITE) {
699
	if (!function_exists('imagejpeg')) {
700
		return false;
701
	}
702
	$tmp = $fichier . ".tmp";
703
704
	// Enable interlancing
705
	imageinterlace($img, true);
706
707
	$ret = imagejpeg($img, $tmp, $qualite);
708
709
	if (file_exists($tmp)) {
710
		$taille_test = getimagesize($tmp);
711
		if ($taille_test[0] < 1) {
712
			return false;
713
		}
714
715
		spip_unlink($fichier); // le fichier peut deja exister
716
		@rename($tmp, $fichier);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
717
718
		return $ret;
719
	}
720
721
	return false;
722
}
723
724
/**
725
 * Crée un fichier-image au format ICO
726
 *
727
 * Utilise les fonctions de la classe phpthumb_functions.
728
 *
729
 * @uses phpthumb_functions::GD2ICOstring()
730
 *
731
 * @param resource $img
732
 *     Une ressource de type Image GD.
733
 * @param string $fichier
734
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
735
 * @return bool
736
 *     true si le fichier a bien été créé ; false sinon.
737
 */
738
function _image_imageico($img, $fichier) {
739
	$gd_image_array = array($img);
740
741
	return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
742
}
743
744
745
/**
746
 * Affiche ou sauvegarde une image au format WEBP
747
 *
748
 * Utilise les fonctions spécifiques GD.
749
 *
750
 * @param resource $img
751
 *     Une ressource de type Image GD.
752
 * @param string $fichier
753
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
754
 * @return bool
755
 *
756
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
757
 *     - true si une image est bien retournée.
758
 */
759 View Code Duplication
function _image_imagewebp($img, $fichier, $qualite = _IMG_GD_QUALITE) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
760
	if (!function_exists('imagewebp')) {
761
		return false;
762
	}
763
	$tmp = $fichier . ".tmp";
764
	$ret = imagewebp($img, $tmp, $qualite);
765
	if (file_exists($tmp)) {
766
		$taille_test = getimagesize($tmp);
767
		if ($taille_test[0] < 1) {
768
			return false;
769
		}
770
771
		spip_unlink($fichier); // le fichier peut deja exister
772
		@rename($tmp, $fichier);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
773
774
		return $ret;
775
	}
776
777
	return false;
778
}
779
780
/**
781
 * Sauvegarde une image au format SVG
782
 *
783
 * - N'UTILISE PAS GD -
784
 * C'est une fonction derogatoire pour faciliter le traitement des SVG
785
 *
786
 * @param string $img
787
 *     contenu du SVG ou chemin vers le SVG source (et c'est alors une copie)
788
 * @param string $fichier
789
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
790
 * @return bool
791
 *
792
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
793
 *     - true si une image est bien retournée.
794
 */
795
function _image_imagesvg($img, $fichier) {
796
797
	$tmp = $fichier . ".tmp";
798
	if (strpos($img, "<") === false) {
799
		$img = supprimer_timestamp($img);
800
		if (!file_exists($img)) {
801
			return false;
802
		}
803
		@copy($img, $tmp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
807
			return true;
808
		}
809
		return false;
810
	}
811
812
	file_put_contents($tmp, $img);
813
	if (file_exists($tmp)) {
814
		$taille_test = spip_getimagesize($tmp);
815
		if ($taille_test[0] < 1) {
816
			return false;
817
		}
818
819
		spip_unlink($fichier); // le fichier peut deja exister
820
		@rename($tmp, $fichier);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
821
822
		return true;
823
	}
824
825
	return false;
826
}
827
828
829
/**
830
 * Finalise le traitement GD
831
 *
832
 * Crée un fichier_image temporaire .src ou vérifie que le fichier_image
833
 * définitif a bien été créé.
834
 *
835
 * @uses statut_effacer_images_temporaires()
836
 *
837
 * @param resource|string $img
838
 *     Une ressource de type Image GD (ou une string pour un SVG)
839
 * @param array $valeurs
840
 *     Un tableau des informations (tailles, traitement, path...) accompagnant
841
 *     l'image.
842
 * @param int $qualite
843
 *     N'est utilisé que pour les images jpg.
844
 *     Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
845
 *     fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
846
 *     valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
847
 *     mes_options.php).
848
 * @return bool
849
 *     - true si le traitement GD s'est bien finalisé ;
850
 *     - false sinon.
851
 */
852
function _image_gd_output($img, $valeurs, $qualite = _IMG_GD_QUALITE) {
853
	$fonction = "_image_image" . $valeurs['format_dest'];
854
	$ret = false;
855
	#un flag pour reperer les images gravees
856
	$lock =
857
		!statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
858
	or (@file_exists($valeurs['fichier_dest']) and !@file_exists($valeurs['fichier_dest'] . '.src'));
859
	if (
860
		function_exists($fonction)
861
		&& ($ret = $fonction($img, $valeurs['fichier_dest'], $qualite)) # on a reussi a creer l'image
862
		&& isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
863
		&& !$lock
864
	) {
865
		if (@file_exists($valeurs['fichier_dest'])) {
866
			// dans tous les cas mettre a jour la taille de l'image finale
867
			list($valeurs["hauteur_dest"], $valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']);
868
			$valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
869
			ecrire_fichier($valeurs['fichier_dest'] . '.src', serialize($valeurs), true);
870
		}
871
	}
872
873
	return $ret;
874
}
875
876
/**
877
 * Reconstruit une image à partir des sources de contrôle de son ancienne
878
 * construction
879
 *
880
 * @uses ramasse_miettes()
881
 *
882
 * @param string $fichier_manquant
883
 *     Chemin vers le fichier manquant
884
 **/
885
function reconstruire_image_intermediaire($fichier_manquant) {
886
	$reconstruire = array();
887
	$fichier = $fichier_manquant;
888
	while (strpos($fichier,"://")===false
889
		and !@file_exists($fichier)
890
		and lire_fichier($src = "$fichier.src", $source)
891
		and $valeurs = unserialize($source)
892
		and ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
893
	) {
894
		spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
895
		$reconstruire[] = $valeurs['reconstruction'];
896
	}
897
	while (count($reconstruire)) {
898
		$r = array_pop($reconstruire);
899
		$fonction = $r[0];
900
		$args = $r[1];
901
		call_user_func_array($fonction, $args);
902
	}
903
	// cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
904
	// mais l'on peut nettoyer les miettes de sa creation
905
	ramasse_miettes($fichier_manquant);
906
}
907
908
/**
909
 * Indique qu'un fichier d'image calculé est à conserver
910
 *
911
 * Permet de rendre une image définitive et de supprimer les images
912
 * intermédiaires à son calcul.
913
 *
914
 * Supprime le fichier de contrôle de l’image cible (le $fichier.src)
915
 * ce qui indique que l'image est définitive.
916
 *
917
 * Remonte ensuite la chaîne des fichiers de contrôle pour supprimer
918
 * les images temporaires (mais laisse les fichiers de contrôle permettant
919
 * de les reconstruire).
920
 *
921
 * @param string $fichier
922
 *     Chemin du fichier d'image calculé
923
 **/
924
function ramasse_miettes($fichier) {
925
	if (strpos($fichier,"://")!==false
926
		or !lire_fichier($src = "$fichier.src", $source)
927
		or !$valeurs = unserialize($source)
928
	) {
929
		return;
930
	}
931
	spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
932
	while (
933
		($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
934
		and (substr($fichier, 0, strlen(_DIR_VAR)) == _DIR_VAR) # et est dans local
935
		and (lire_fichier($src = "$fichier.src",
936
			$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire)
937
		and ($valeurs = unserialize($source))  # et valide
938
	) {
939
		# on efface le fichier
940
		spip_unlink($fichier);
941
		# mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
942
		#spip_unlink($src);
943
	}
944
}
945
946
947
/**
948
 * Clôture une série de filtres d'images
949
 *
950
 * Ce filtre est automatiquement appelé à la fin d'une série de filtres
951
 * d'images dans un squelette.
952
 *
953
 * @filtre
954
 * @uses reconstruire_image_intermediaire()
955
 *     Si l'image finale a déjà été supprimée car considérée comme temporaire
956
 *     par une autre série de filtres images débutant pareil
957
 * @uses ramasse_miettes()
958
 *     Pour déclarer l'image définitive et nettoyer les images intermédiaires.
959
 *
960
 * @pipeline_appel post_image_filtrer
961
 *
962
 * @param string $img
963
 *     Code HTML de l'image
964
 * @return string
965
 *     Code HTML de l'image
966
 **/
967
function image_graver($img) {
968
	// appeler le filtre post_image_filtrer qui permet de faire
969
	// des traitements auto a la fin d'une serie de filtres
970
	$img = pipeline('post_image_filtrer', $img);
971
972
	$fichier_ori = $fichier = extraire_attribut($img, 'src');
973 View Code Duplication
	if (($p = strpos($fichier, '?')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
974
		$fichier = substr($fichier, 0, $p);
975
	}
976
	if (strlen($fichier) < 1) {
977
		$fichier = $img;
978
	}
979
	# si jamais le fichier final n'a pas ete calcule car suppose temporaire
980
	# et qu'il ne s'agit pas d'une URL
981
	if (strpos($fichier,"://")===false and !@file_exists($fichier)) {
982
		reconstruire_image_intermediaire($fichier);
983
	}
984
	ramasse_miettes($fichier);
985
986
	// ajouter le timestamp si besoin
987
	if (strpos($fichier_ori, "?") === false) {
988
		// on utilise str_replace pour attraper le onmouseover des logo si besoin
989
		$img = str_replace($fichier_ori, timestamp($fichier_ori), $img);
0 ignored issues
show
Bug introduced by
It seems like $fichier_ori defined by $fichier = extraire_attribut($img, 'src') on line 972 can also be of type array; however, timestamp() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
990
	}
991
992
	return $img;
993
}
994
995
996
if (!function_exists("imagepalettetotruecolor")) {
997
	/**
998
	 * Transforme une image à palette indexée (256 couleurs max) en "vraies" couleurs RGB
999
	 *
1000
	 * @note Pour compatibilité avec PHP < 5.5
1001
	 *
1002
	 * @link http://php.net/manual/fr/function.imagepalettetotruecolor.php
1003
	 *
1004
	 * @param ressource $img
1005
	 * @return bool
1006
	 *     - true si l'image est déjà en vrai RGB ou peut être transformée
1007
	 *     - false si la transformation ne peut être faite.
1008
	 **/
1009
	function imagepalettetotruecolor(&$img) {
1010
		if (!$img or !function_exists('imagecreatetruecolor')) {
1011
			return false;
1012
		} elseif (!imageistruecolor($img)) {
1013
			$w = imagesx($img);
1014
			$h = imagesy($img);
1015
			$img1 = imagecreatetruecolor($w, $h);
1016
			//Conserver la transparence si possible
1017
			if (function_exists('ImageCopyResampled')) {
1018
				if (function_exists("imageAntiAlias")) {
1019
					imageAntiAlias($img1, true);
1020
				}
1021
				@imagealphablending($img1, false);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

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

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1024
			} else {
1025
				imagecopy($img1, $img, 0, 0, 0, 0, $w, $h);
1026
			}
1027
1028
			$img = $img1;
1029
		}
1030
1031
		return true;
1032
	}
1033
}
1034
1035
/**
1036
 * Applique des attributs de taille (width, height) à une balise HTML
1037
 *
1038
 * Utilisé avec des balises `<img>` tout particulièrement.
1039
 *
1040
 * Modifie l'attribut style s'il était renseigné, en enlevant les
1041
 * informations éventuelles width / height dedans.
1042
 *
1043
 * @uses extraire_attribut()
1044
 * @uses inserer_attribut()
1045
 *
1046
 * @param string $tag
1047
 *     Code html de la balise
1048
 * @param int $width
1049
 *     Hauteur
1050
 * @param int $height
1051
 *     Largeur
1052
 * @param bool|string $style
1053
 *     Attribut html style à appliquer.
1054
 *     False extrait celui présent dans la balise
1055
 * @return string
1056
 *     Code html modifié de la balise.
1057
 **/
1058
function _image_tag_changer_taille($tag, $width, $height, $style = false) {
1059
	if ($style === false) {
1060
		$style = extraire_attribut($tag, 'style');
1061
	}
1062
1063
	// enlever le width et height du style
1064
	$style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims", "", $style);
1065
	if ($style and $style[0] == ';') {
1066
		$style = substr($style, 1);
1067
	}
1068
1069
	// mettre des attributs de width et height sur les images, 
1070
	// ca accelere le rendu du navigateur
1071
	// ca permet aux navigateurs de reserver la bonne taille 
1072
	// quand on a desactive l'affichage des images.
1073
	$tag = inserer_attribut($tag, 'width', round($width));
1074
	$tag = inserer_attribut($tag, 'height', round($height));
1075
1076
	// attributs deprecies. Transformer en CSS
1077
	if ($espace = extraire_attribut($tag, 'hspace')) {
1078
		$style = "margin:${espace}px;" . $style;
1079
		$tag = inserer_attribut($tag, 'hspace', '');
1080
	}
1081
1082
	$tag = inserer_attribut($tag, 'style', $style, true, $style ? false : true);
0 ignored issues
show
Bug introduced by
It seems like $style defined by preg_replace(',(^|;)\\s*...[^;]+,ims', '', $style) on line 1064 can also be of type array<integer,string>; however, inserer_attribut() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1083
1084
	return $tag;
1085
}
1086
1087
1088
/**
1089
 * Écriture de la balise img en sortie de filtre image
1090
 *
1091
 * Reprend le tag initial et surcharge les attributs modifiés
1092
 *
1093
 * @pipeline_appel image_ecrire_tag_preparer
1094
 * @pipeline_appel image_ecrire_tag_finir
1095
 *
1096
 * @uses _image_tag_changer_taille()
1097
 * @uses extraire_attribut()
1098
 * @uses inserer_attribut()
1099
 * @see  _image_valeurs_trans()
1100
 *
1101
 * @param array $valeurs
1102
 *     Description de l'image tel que retourné par `_image_valeurs_trans()`
1103
 * @param array $surcharge
1104
 *     Permet de surcharger certaines descriptions présentes dans `$valeurs`
1105
 *     tel que 'style', 'width', 'height'
1106
 * @return string
1107
 *     Retourne le code HTML de l'image
1108
 **/
1109
function _image_ecrire_tag($valeurs, $surcharge = array()) {
1110
	$valeurs = pipeline('image_ecrire_tag_preparer', $valeurs);
1111
1112
	// fermer les tags img pas bien fermes;
1113
	$tag = str_replace(">", "/>", str_replace("/>", ">", $valeurs['tag']));
1114
1115
	// le style
1116
	$style = $valeurs['style'];
1117
	if (isset($surcharge['style'])) {
1118
		$style = $surcharge['style'];
1119
		unset($surcharge['style']);
1120
	}
1121
1122
	// traiter specifiquement la largeur et la hauteur
1123
	$width = $valeurs['largeur'];
1124
	if (isset($surcharge['width'])) {
1125
		$width = $surcharge['width'];
1126
		unset($surcharge['width']);
1127
	}
1128
	$height = $valeurs['hauteur'];
1129
	if (isset($surcharge['height'])) {
1130
		$height = $surcharge['height'];
1131
		unset($surcharge['height']);
1132
	}
1133
1134
	$tag = _image_tag_changer_taille($tag, $width, $height, $style);
1135
	// traiter specifiquement le src qui peut etre repris dans un onmouseout
1136
	// on remplace toute les ref a src dans le tag
1137
	$src = extraire_attribut($tag, 'src');
1138
	if (isset($surcharge['src'])) {
1139
		$tag = str_replace($src, $surcharge['src'], $tag);
1140
		// si il y a des & dans src, alors ils peuvent provenir d'un &amp
1141
		// pas garanti comme methode, mais mieux que rien
1142
		if (strpos($src, '&') !== false) {
1143
			$tag = str_replace(str_replace("&", "&amp;", $src), $surcharge['src'], $tag);
1144
		}
1145
		$src = $surcharge['src'];
0 ignored issues
show
Unused Code introduced by
$src is not used, you could remove the assignment.

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

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

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

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

Loading history...
1146
		unset($surcharge['src']);
1147
	}
1148
1149
	$class = $valeurs['class'];
1150
	if (isset($surcharge['class'])) {
1151
		$class = $surcharge['class'];
1152
		unset($surcharge['class']);
1153
	}
1154
	if (strlen($class)) {
1155
		$tag = inserer_attribut($tag, 'class', $class);
1156
	}
1157
1158
	if (count($surcharge)) {
1159
		foreach ($surcharge as $attribut => $valeur) {
1160
			$tag = inserer_attribut($tag, $attribut, $valeur);
1161
		}
1162
	}
1163
1164
	$tag = pipeline('image_ecrire_tag_finir',
1165
		array(
1166
			'args' => array(
1167
				'valeurs' => $valeurs,
1168
				'surcharge' => $surcharge,
1169
			),
1170
			'data' => $tag
1171
		)
1172
	);
1173
1174
	return $tag;
1175
}
1176
1177
/**
1178
 * Crée si possible une miniature d'une image
1179
 *
1180
 * @see  _image_valeurs_trans()
1181
 * @uses _image_ratio()
1182
 *
1183
 * @param array $valeurs
1184
 *     Description de l'image, telle que retournée par `_image_valeurs_trans()`
1185
 * @param int $maxWidth
1186
 *     Largeur maximum en px de la miniature à réaliser
1187
 * @param int $maxHeight
1188
 *     Hauteur maximum en px de la miniateure à réaliser
1189
 * @param string $process
1190
 *     Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
1191
 *     AUTO utilise la librairie sélectionnée dans la configuration.
1192
 * @param bool $force
1193
 * @return array|null
0 ignored issues
show
Documentation introduced by
Should the return type not be null|string|array?

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

Loading history...
1194
 *     Description de l'image, sinon null.
1195
 **/
1196
function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process = 'AUTO', $force = false) {
1197
	// ordre de preference des formats graphiques pour creer les vignettes
1198
	// le premier format disponible, selon la methode demandee, est utilise
1199
	$image = $valeurs['fichier'];
1200
	$format = $valeurs['format_source'];
1201
	$destdir = dirname($valeurs['fichier_dest']);
1202
	$destfile = basename($valeurs['fichier_dest'], "." . $valeurs["format_dest"]);
1203
1204
	$format_sortie = $valeurs['format_dest'];
1205
1206 View Code Duplication
	if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1207
		$process = $GLOBALS['meta']['image_process'];
1208
	}
1209
1210
	// si le doc n'est pas une image dans un format accetpable, refuser
1211
	if (!$force and !in_array($format, formats_image_acceptables(in_array($process, ['gd1', 'gd2'])))) {
1212
		return;
1213
	}
1214
	$destination = "$destdir/$destfile";
1215
1216
	// calculer la taille
1217
	if (($srcWidth = $valeurs['largeur']) && ($srcHeight = $valeurs['hauteur'])) {
1218
		if (!($destWidth = $valeurs['largeur_dest']) || !($destHeight = $valeurs['hauteur_dest'])) {
1219
			list($destWidth, $destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight);
1220
		}
1221
	} elseif ($process == 'convert' or $process == 'imagick') {
1222
		$destWidth = $maxWidth;
1223
		$destHeight = $maxHeight;
1224
	} else {
1225
		spip_log("echec $process sur $image");
1226
1227
		return;
1228
	}
1229
1230
	$vignette = '';
1231
1232
	// Si l'image est de la taille demandee (ou plus petite), simplement la retourner
1233
	if ($srcWidth and $srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1234
		$vignette = $destination . '.' . $format;
1235
		@copy($image, $vignette);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1236
	}
1237
1238
	elseif ($valeurs["format_source"] === 'svg') {
1239
		if ($svg = svg_redimensionner($valeurs['fichier'], $destWidth, $destHeight)){
1240
			$format_sortie = 'svg';
1241
			$vignette = $destination . "." . $format_sortie;
1242
			$valeurs['fichier_dest'] = $vignette;
1243
			_image_gd_output($svg, $valeurs);
0 ignored issues
show
Bug introduced by
It seems like $svg defined by svg_redimensionner($vale...destWidth, $destHeight) on line 1239 can also be of type boolean; however, _image_gd_output() does only seem to accept resource|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1244
		}
1245
	}
1246
1247
	// imagemagick en ligne de commande
1248
	elseif ($process == 'convert') {
1249
		if (!defined('_CONVERT_COMMAND')) {
1250
			define('_CONVERT_COMMAND', 'convert');
1251
		} // Securite : mes_options.php peut preciser le chemin absolu
1252
		if (!defined('_RESIZE_COMMAND')) {
1253
			define('_RESIZE_COMMAND', _CONVERT_COMMAND . ' -quality ' . _IMG_CONVERT_QUALITE . ' -resize %xx%y! %src %dest');
1254
		}
1255
		$vignette = $destination . "." . $format_sortie;
1256
		$commande = str_replace(
1257
			array('%x', '%y', '%src', '%dest'),
1258
			array(
1259
				$destWidth,
1260
				$destHeight,
1261
				escapeshellcmd($image),
1262
				escapeshellcmd($vignette)
1263
			),
1264
			_RESIZE_COMMAND);
1265
		spip_log($commande);
1266
		exec($commande);
1267
		if (!@file_exists($vignette)) {
1268
			spip_log("echec convert sur $vignette");
1269
1270
			return;  // echec commande
1271
		}
1272
	}
1273
1274
	// php5 imagemagick
1275
	elseif ($process == 'imagick') {
1276
		$vignette = "$destination." . $format_sortie;
1277
1278
		if (!class_exists('Imagick')) {
1279
			spip_log("Classe Imagick absente !", _LOG_ERREUR);
1280
1281
			return;
1282
		}
1283
		$imagick = new Imagick();
1284
		$imagick->readImage($image);
1285
		$imagick->resizeImage($destWidth, $destHeight, Imagick::FILTER_LANCZOS,
1286
			1);//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100);
1287
		$imagick->writeImage($vignette);
1288
1289
		if (!@file_exists($vignette)) {
1290
			spip_log("echec imagick sur $vignette");
1291
1292
			return;
1293
		}
1294
	}
1295
1296
	// netpbm
1297
	elseif ($process == "netpbm") {
1298
		if (!defined('_PNMSCALE_COMMAND')) {
1299
			define('_PNMSCALE_COMMAND', 'pnmscale');
1300
		} // Securite : mes_options.php peut preciser le chemin absolu
1301
		if (_PNMSCALE_COMMAND == '') {
1302
			return;
1303
		}
1304
		$vignette = $destination . "." . $format_sortie;
1305
		$pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND);
1306
		if ($format == "jpg") {
1307
1308
			$jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND);
1309
			exec("$jpegtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1310
			if (!($s = @filesize($vignette))) {
1311
				spip_unlink($vignette);
1312
			}
1313
			if (!@file_exists($vignette)) {
1314
				spip_log("echec netpbm-jpg sur $vignette");
1315
1316
				return;
1317
			}
1318
		} else {
1319
			if ($format == "gif") {
1320
				$giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND);
1321
				exec("$giftopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1322
				if (!($s = @filesize($vignette))) {
1323
					spip_unlink($vignette);
1324
				}
1325
				if (!@file_exists($vignette)) {
1326
					spip_log("echec netpbm-gif sur $vignette");
1327
1328
					return;
1329
				}
1330
			} else {
1331
				if ($format == "png") {
1332
					$pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND);
1333
					exec("$pngtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1334
					if (!($s = @filesize($vignette))) {
1335
						spip_unlink($vignette);
1336
					}
1337
					if (!@file_exists($vignette)) {
1338
						spip_log("echec netpbm-png sur $vignette");
1339
1340
						return;
1341
					}
1342
				}
1343
			}
1344
		}
1345
	}
1346
1347
	// gd ou gd2
1348
	elseif ($process == 'gd1' or $process == 'gd2') {
1349
		if (!function_exists('gd_info')) {
1350
			spip_log("Librairie GD absente !", _LOG_ERREUR);
1351
1352
			return;
1353
		}
1354
		if (_IMG_GD_MAX_PIXELS && $srcWidth * $srcHeight > _IMG_GD_MAX_PIXELS) {
1355
			spip_log("vignette gd1/gd2 impossible : " . $srcWidth * $srcHeight . "pixels");
0 ignored issues
show
Bug introduced by
The variable $srcHeight does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1356
1357
			return;
1358
		}
1359
		$destFormat = $format_sortie;
1360
		if (!$destFormat) {
1361
			spip_log("pas de format pour $image");
1362
1363
			return;
1364
		}
1365
1366
		$fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
1367
		if (!function_exists($fonction_imagecreatefrom)) {
1368
			return '';
1369
		}
1370
		$srcImage = @$fonction_imagecreatefrom($image);
1371
		if (!$srcImage) {
1372
			spip_log("echec gd1/gd2");
1373
1374
			return;
1375
		}
1376
1377
		// Initialisation de l'image destination
1378
		$destImage = null;
1379
		if ($process == 'gd2' and $destFormat != "gif") {
1380
			$destImage = ImageCreateTrueColor($destWidth, $destHeight);
1381
		}
1382
		if (!$destImage) {
1383
			$destImage = ImageCreate($destWidth, $destHeight);
1384
		}
1385
1386
		// Recopie de l'image d'origine avec adaptation de la taille 
1387
		$ok = false;
1388
		if (($process == 'gd2') and function_exists('ImageCopyResampled')) {
1389
			if ($format == "gif") {
1390
				// Si un GIF est transparent, 
1391
				// fabriquer un PNG transparent  
1392
				$transp = imagecolortransparent($srcImage);
1393
				if ($transp > 0) {
1394
					$destFormat = "png";
1395
				}
1396
			}
1397
			if (in_array($destFormat, _image_extensions_conservent_transparence())) {
1398
				// Conserver la transparence 
1399
				if (function_exists("imageAntiAlias")) {
1400
					imageAntiAlias($destImage, true);
1401
				}
1402
				@imagealphablending($destImage, false);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1404
			}
1405
			$ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1406
		}
1407
		if (!$ok) {
1408
			$ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
0 ignored issues
show
Unused Code introduced by
$ok is not used, you could remove the assignment.

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

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

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

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

Loading history...
1409
		}
1410
1411
		// Sauvegarde de l'image destination
1412
		$valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
1413
		$valeurs['format_dest'] = $format = $destFormat;
1414
		_image_gd_output($destImage, $valeurs);
1415
1416
		if ($srcImage) {
1417
			ImageDestroy($srcImage);
1418
		}
1419
		ImageDestroy($destImage);
1420
	}
1421
1422
	if (!$vignette or !$size = @spip_getimagesize($vignette)) {
1423
		$size = array($destWidth, $destHeight);
1424
	}
1425
1426
	// Gaffe: en safe mode, pas d'acces a la vignette,
1427
	// donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
1428
	if ($size[0] < 1) {
1429
		$size[0] = $destWidth;
1430
	}
1431
	if ($size[1] < 1) {
1432
		$size[1] = $destHeight;
1433
	}
1434
1435
	$retour['width'] = $largeur = $size[0];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$retour was never initialized. Although not strictly required by PHP, it is generally a good practice to add $retour = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
Unused Code introduced by
$largeur is not used, you could remove the assignment.

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

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

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

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

Loading history...
1436
	$retour['height'] = $hauteur = $size[1];
0 ignored issues
show
Unused Code introduced by
$hauteur is not used, you could remove the assignment.

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

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

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

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

Loading history...
1437
1438
	$retour['fichier'] = $vignette;
1439
	$retour['format'] = $format;
1440
	$retour['date'] = @filemtime($vignette);
1441
1442
	// renvoyer l'image
1443
	return $retour;
1444
}
1445
1446
/**
1447
 * Réduire des dimensions en respectant un ratio
1448
 *
1449
 * Réduit des dimensions (hauteur, largeur) pour qu'elles
1450
 * soient incluses dans une hauteur et largeur maximum fournies
1451
 * en respectant la proportion d'origine
1452
 *
1453
 * @example `image_ratio(1000, 1000, 100, 10)` donne `array(10, 10, 100)`
1454
 * @see ratio_passe_partout() Assez proche.
1455
 *
1456
 * @param int $srcWidth Largeur de l'image source
1457
 * @param int $srcHeight Hauteur de l'image source
1458
 * @param int $maxWidth Largeur maximum souhaitée
1459
 * @param int $maxHeight Hauteur maximum souhaitée
1460
 * @return array Liste [ largeur, hauteur, ratio de réduction ]
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use integer[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1461
 **/
1462 View Code Duplication
function _image_ratio($srcWidth, $srcHeight, $maxWidth, $maxHeight) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1463
	$ratioWidth = $srcWidth / $maxWidth;
1464
	$ratioHeight = $srcHeight / $maxHeight;
1465
1466
	if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1467
		$destWidth = $srcWidth;
1468
		$destHeight = $srcHeight;
1469
	} elseif ($ratioWidth < $ratioHeight) {
1470
		$destWidth = $srcWidth / $ratioHeight;
1471
		$destHeight = $maxHeight;
1472
	} else {
1473
		$destWidth = $maxWidth;
1474
		$destHeight = $srcHeight / $ratioWidth;
1475
	}
1476
1477
	return array(
1478
		intval(round($destWidth)),
1479
		intval(round($destHeight)),
1480
		max($ratioWidth, $ratioHeight)
1481
	);
1482
}
1483
1484
/**
1485
 * Réduire des dimensions en respectant un ratio sur la plus petite dimension
1486
 *
1487
 * Réduit des dimensions (hauteur, largeur) pour qu'elles
1488
 * soient incluses dans la plus grande hauteur ou largeur maximum fournie
1489
 * en respectant la proportion d'origine
1490
 *
1491
 * @example `ratio_passe_partout(1000, 1000, 100, 10)` donne `array(100, 100, 10)`
1492
 * @see _image_ratio() Assez proche.
1493
 *
1494
 * @param int $srcWidth Largeur de l'image source
1495
 * @param int $srcHeight Hauteur de l'image source
1496
 * @param int $maxWidth Largeur maximum souhaitée
1497
 * @param int $maxHeight Hauteur maximum souhaitée
1498
 * @return array Liste [ largeur, hauteur, ratio de réduction ]
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use integer[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1499
 **/
1500 View Code Duplication
function ratio_passe_partout($srcWidth, $srcHeight, $maxWidth, $maxHeight) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1501
	$ratioWidth = $srcWidth / $maxWidth;
1502
	$ratioHeight = $srcHeight / $maxHeight;
1503
1504
	if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1505
		$destWidth = $srcWidth;
1506
		$destHeight = $srcHeight;
1507
	} elseif ($ratioWidth > $ratioHeight) {
1508
		$destWidth = $srcWidth / $ratioHeight;
1509
		$destHeight = $maxHeight;
1510
	} else {
1511
		$destWidth = $maxWidth;
1512
		$destHeight = $srcHeight / $ratioWidth;
1513
	}
1514
1515
	return array(
1516
		intval(round($destWidth)),
1517
		intval(round($destHeight)),
1518
		min($ratioWidth, $ratioHeight)
1519
	);
1520
}
1521
1522
1523
/**
1524
 * Fonction identite de traitement par defaut des images SVG
1525
 * (quand un filtre n'annonce pas qu'il sait traiter un SVG on applique cette fonction a la place)
1526
 *
1527
 * @param array $image
1528
 *   tableau des valeurs crees par _image_valeurs_trans
1529
 * @return string
1530
 */
1531
function process_image_svg_identite($image) {
1532
	if ($image['creer']) {
1533
		$source = $image['fichier'];
1534
		_image_gd_output($source, $image);
1535
	}
1536
1537
	return _image_ecrire_tag($image, array('src' => $image['fichier_dest']));
1538
}
1539
1540
1541
/**
1542
 * Réduit une image
1543
 *
1544
 * @uses extraire_attribut()
1545
 * @uses inserer_attribut()
1546
 * @uses _image_valeurs_trans()
1547
 * @uses _image_ratio()
1548
 * @uses _image_tag_changer_taille()
1549
 * @uses _image_ecrire_tag()
1550
 * @uses _image_creer_vignette()
1551
 *
1552
 * @param array $fonction
1553
 *     Un tableau à 2 éléments :
1554
 *     1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ;
1555
 *     2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé.
1556
 * @param string $img
1557
 *     Chemin de l'image ou texte contenant une balise img
1558
 * @param int $taille
1559
 *     Largeur désirée
1560
 * @param int $taille_y
1561
 *     Hauteur désirée
1562
 * @param bool $force
1563
 * @param string $process
1564
 *     Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
1565
 *     AUTO utilise la librairie sélectionnée dans la configuration.
1566
 * @return string
1567
 *     Code HTML de la balise img produite
1568
 **/
1569
function process_image_reduire($fonction, $img, $taille, $taille_y, $force, $process = 'AUTO') {
1570
	$image = false;
1571 View Code Duplication
	if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1572
		$process = $GLOBALS['meta']['image_process'];
1573
	}
1574
	# determiner le format de sortie
1575
	$format_sortie = false; // le choix par defaut sera bon
1576
	if ($process == "netpbm") {
1577
		$format_sortie = "jpg";
1578
	} elseif ($process == 'gd1' or $process == 'gd2') {
1579
		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1580
		// on verifie que l'extension choisie est bonne (en principe oui)
1581
		$gd_formats = formats_image_acceptables(true);
1582
		if (is_array($image)
1583
			and (!in_array($image['format_dest'], $gd_formats)
1584
				or (!in_array($image['format_dest'], _image_extensions_acceptees_en_sortie()))
1585
			)
1586
		) {
1587
			if ($image['format_source'] == 'jpg') {
1588
				$formats_sortie = array('jpg', 'png', 'gif');
1589
			} else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
1590
			{
1591
				$formats_sortie = array('png', 'jpg', 'gif');
1592
			}
1593
			// Choisir le format destination
1594
			// - on sauve de preference en JPEG (meilleure compression)
1595
			// - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
1596
			# bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
1597
			# pas *ecrire*
1598
			$format_sortie = "";
1599
			foreach ($formats_sortie as $fmt) {
1600
				if (in_array($fmt, $gd_formats) and in_array($fmt, _image_extensions_acceptees_en_sortie())) {
1601
					$format_sortie = $fmt;
1602
					break;
1603
				}
1604
			}
1605
			$image = false;
1606
		}
1607
	}
1608
1609
	if (!is_array($image)) {
1610
		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1611
	}
1612
1613
	if (!is_array($image) or !$image['largeur'] or !$image['hauteur']) {
1614
		spip_log("image_reduire_src:pas de version locale de $img");
1615
		// on peut resizer en mode html si on dispose des elements
1616
		if ($srcw = extraire_attribut($img, 'width')
1617
			and $srch = extraire_attribut($img, 'height')
1618
		) {
1619
			list($w, $h) = _image_ratio($srcw, $srch, $taille, $taille_y);
1620
1621
			return _image_tag_changer_taille($img, $w, $h);
1622
		}
1623
		// la on n'a pas d'infos sur l'image source... on refile le truc a css
1624
		// sous la forme style='max-width: NNpx;'
1625
		return inserer_attribut($img, 'style',
1626
			"max-width: ${taille}px; max-height: ${taille_y}px");
1627
	}
1628
1629
	// si l'image est plus petite que la cible retourner une copie cachee de l'image
1630
	if (($image['largeur'] <= $taille) && ($image['hauteur'] <= $taille_y)) {
1631
		if ($image['creer']) {
1632
			@copy($image['fichier'], $image['fichier_dest']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1633
		}
1634
1635
		return _image_ecrire_tag($image, array('src' => $image['fichier_dest']));
1636
	}
1637
1638
	if ($image['creer'] == false && !$force) {
1639
		return _image_ecrire_tag($image,
1640
			array('src' => $image['fichier_dest'], 'width' => $image['largeur_dest'], 'height' => $image['hauteur_dest']));
1641
	}
1642
1643
	if (in_array($image["format_source"], _image_extensions_acceptees_en_entree())) {
1644
		$destWidth = $image['largeur_dest'];
1645
		$destHeight = $image['hauteur_dest'];
1646
		$logo = $image['fichier'];
1647
		$date = $image["date_src"];
1648
		$preview = _image_creer_vignette($image, $taille, $taille_y, $process, $force);
1649
1650
		if ($preview && $preview['fichier']) {
1651
			$logo = $preview['fichier'];
1652
			$destWidth = $preview['width'];
1653
			$destHeight = $preview['height'];
1654
			$date = $preview['date'];
1655
		}
1656
		// dans l'espace prive mettre un timestamp sur l'adresse 
1657
		// de l'image, de facon a tromper le cache du navigateur
1658
		// quand on fait supprimer/reuploader un logo
1659
		// (pas de filemtime si SAFE MODE)
1660
		$date = test_espace_prive() ? ('?' . $date) : '';
1661
1662
		return _image_ecrire_tag($image, array('src' => "$logo$date", 'width' => $destWidth, 'height' => $destHeight));
1663
	}
1664
	else {
1665
		# BMP, tiff ... les redacteurs osent tout!
1666
		return $img;
1667
	}
1668
}
1669
1670
/**
1671
 * Produire des fichiers au format .ico
1672
 *
1673
 * Avec du code récupéré de phpThumb()
1674
 *
1675
 * @author James Heinrich <[email protected]>
1676
 * @link http://phpthumb.sourceforge.net
1677
 *
1678
 * Class phpthumb_functions
1679
 */
1680
class phpthumb_functions {
1681
1682
	/**
1683
	 * Retourne la couleur d'un pixel dans une image
1684
	 *
1685
	 * @param ressource $img
1686
	 * @param int $x
1687
	 * @param int $y
1688
	 * @return array|bool
1689
	 */
1690
	public static function GetPixelColor(&$img, $x, $y) {
1691
		if (is_resource($img) || (is_object($img) && $img instanceof \GdImage)) {
0 ignored issues
show
Bug introduced by
The class GdImage does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1692
			return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
1693
		}
1694
		return false;
1695
	}
1696
1697
	/**
1698
	 * Retourne un nombre dans une représentation en Little Endian
1699
	 *
1700
	 * @param int $number
1701
	 * @param int $minbytes
1702
	 * @return string
1703
	 */
1704
	public static function LittleEndian2String($number, $minbytes = 1) {
1705
		$intstring = '';
1706
		while ($number > 0) {
1707
			$intstring = $intstring . chr($number & 255);
1708
			$number >>= 8;
1709
		}
1710
1711
		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
1712
	}
1713
1714
	/**
1715
	 * Transforme une ressource GD en image au format ICO
1716
	 *
1717
	 * @param array $gd_image_array
1718
	 *     Tableau de ressources d'images GD
1719
	 * @return string
1720
	 *     Image au format ICO
1721
	 */
1722
	public static function GD2ICOstring(&$gd_image_array) {
1723
		foreach ($gd_image_array as $key => $gd_image) {
1724
1725
			$ImageWidths[$key] = ImageSX($gd_image);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ImageWidths was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ImageWidths = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1726
			$ImageHeights[$key] = ImageSY($gd_image);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ImageHeights was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ImageHeights = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1727
			$bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$bpp was never initialized. Although not strictly required by PHP, it is generally a good practice to add $bpp = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1728
			$totalcolors[$key] = ImageColorsTotal($gd_image);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$totalcolors was never initialized. Although not strictly required by PHP, it is generally a good practice to add $totalcolors = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1729
1730
			$icXOR[$key] = '';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$icXOR was never initialized. Although not strictly required by PHP, it is generally a good practice to add $icXOR = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1731
			for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
0 ignored issues
show
Bug introduced by
The variable $ImageHeights does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1732
				for ($x = 0; $x < $ImageWidths[$key]; $x++) {
0 ignored issues
show
Bug introduced by
The variable $ImageWidths does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1733
					$argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
1734
					$a = round(255 * ((127 - $argb['alpha']) / 127));
1735
					$r = $argb['red'];
1736
					$g = $argb['green'];
1737
					$b = $argb['blue'];
1738
1739
					if ($bpp[$key] == 32) {
1740
						$icXOR[$key] .= chr($b) . chr($g) . chr($r) . chr($a);
0 ignored issues
show
Bug introduced by
The variable $icXOR does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1741
					} elseif ($bpp[$key] == 24) {
0 ignored issues
show
Bug introduced by
The variable $bpp does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1742
						$icXOR[$key] .= chr($b) . chr($g) . chr($r);
1743
					}
1744
1745
					if ($a < 128) {
1746
						@$icANDmask[$key][$y] .= '1';
0 ignored issues
show
Bug introduced by
The variable $icANDmask does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1749
					}
1750
				}
1751
				// mask bits are 32-bit aligned per scanline
1752
				while (strlen($icANDmask[$key][$y]) % 32) {
1753
					$icANDmask[$key][$y] .= '0';
1754
				}
1755
			}
1756
			$icAND[$key] = '';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$icAND was never initialized. Although not strictly required by PHP, it is generally a good practice to add $icAND = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1757
			foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
1758
				for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
1759
					$icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
0 ignored issues
show
Bug introduced by
The variable $icAND does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1760
				}
1761
			}
1762
1763
		}
1764
1765
		foreach ($gd_image_array as $key => $gd_image) {
1766
			$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
1767
1768
			// BITMAPINFOHEADER - 40 bytes
1769
			$BitmapInfoHeader[$key] = '';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$BitmapInfoHeader was never initialized. Although not strictly required by PHP, it is generally a good practice to add $BitmapInfoHeader = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1770
			$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";                // DWORD  biSize;
1771
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);    // LONG   biWidth;
1772
			// The biHeight member specifies the combined
1773
			// height of the XOR and AND masks.
1774
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
1775
			$BitmapInfoHeader[$key] .= "\x01\x00";                    // WORD   biPlanes;
1776
			$BitmapInfoHeader[$key] .= chr($bpp[$key]) . "\x00";              // wBitCount;
1777
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biCompression;
1778
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);      // DWORD  biSizeImage;
1779
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biXPelsPerMeter;
1780
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biYPelsPerMeter;
1781
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrUsed;
1782
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrImportant;
1783
		}
1784
1785
1786
		$icondata = "\x00\x00";                    // idReserved;   // Reserved (must be 0)
1787
		$icondata .= "\x01\x00";                    // idType;	   // Resource Type (1 for icons)
1788
		$icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2);  // idCount;	  // How many images?
1789
1790
		$dwImageOffset = 6 + (count($gd_image_array) * 16);
1791
		foreach ($gd_image_array as $key => $gd_image) {
1792
			// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
1793
1794
			$icondata .= chr($ImageWidths[$key]);           // bWidth;		  // Width, in pixels, of the image
1795
			$icondata .= chr($ImageHeights[$key]);          // bHeight;		 // Height, in pixels, of the image
1796
			$icondata .= chr($totalcolors[$key]);           // bColorCount;	 // Number of colors in image (0 if >=8bpp)
0 ignored issues
show
Bug introduced by
The variable $totalcolors does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1797
			$icondata .= "\x00";                    // bReserved;	   // Reserved ( must be 0)
1798
1799
			$icondata .= "\x01\x00";                  // wPlanes;		 // Color Planes
1800
			$icondata .= chr($bpp[$key]) . "\x00";            // wBitCount;	   // Bits per pixel
1801
1802
			$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
1803
			$icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes,
1804
				4);     // dwBytesInRes;	// How many bytes in this resource?
1805
1806
			$icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset,
1807
				4);    // dwImageOffset;   // Where in the file is this image?
1808
			$dwImageOffset += strlen($BitmapInfoHeader[$key]);
0 ignored issues
show
Bug introduced by
The variable $BitmapInfoHeader does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1809
			$dwImageOffset += strlen($icXOR[$key]);
1810
			$dwImageOffset += strlen($icAND[$key]);
1811
		}
1812
1813
		foreach ($gd_image_array as $key => $gd_image) {
1814
			$icondata .= $BitmapInfoHeader[$key];
1815
			$icondata .= $icXOR[$key];
1816
			$icondata .= $icAND[$key];
1817
		}
1818
1819
		return $icondata;
1820
	}
1821
1822
}
1823