Completed
Push — master ( 2ca868...d39161 )
by cam
08:10 queued 03:16
created

filtres_images_lib_mini.php ➔ _image_imagewebp()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20

Duplication

Lines 20
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 3
dl 20
loc 20
rs 9.6
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 traitement d'image
104
 *
105
 * Uniquement pour GD2.
106
 *
107
 * @pipeline_appel image_preparer_filtre
108
 * @uses extraire_attribut()
109
 * @uses inserer_attribut()
110
 * @uses tester_url_absolue()
111
 * @uses copie_locale() Si l'image est distante
112
 * @uses taille_image()
113
 * @uses _image_ratio()
114
 * @uses reconstruire_image_intermediaire()
115
 *
116
 * @param string $img
117
 *     Chemin de l'image ou balise html `<img src=... />`.
118
 * @param string $effet
119
 *     Les nom et paramètres de l'effet à apporter sur l'image
120
 *     (par exemple : reduire-300-200).
121
 * @param bool|string $forcer_format
122
 *     Un nom d'extension spécifique demandé (par exemple : jpg, png, txt...).
123
 *     Par défaut false : GD se débrouille seule).
124
 * @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...
125
 *     Un tableau à 2 éléments :
126
 *     1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ;
127
 *     2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé.
128
 * @param bool $find_in_path
129
 *     false (par défaut) indique que l'on travaille sur un fichier
130
 *     temporaire (.src) ; true, sur un fichier définitif déjà existant.
131
 * @param bool $support_svg
132
 *     false (par defaut) indique que le filtre ne sait pas traiter le cas particulier du SVG
133
 *     on lui substitue un filtre generique qui ne fait rien pour ne pas briser la chaine des filtres images
134
 *     true si le filtre appelant sait traiter les SVG
135
 * @return bool|string|array
136
 *
137
 *     - false si pas de tag `<img`,
138
 *       -   si l'extension n'existe pas,
139
 *       -   si le fichier source n'existe pas,
140
 *       -   si les dimensions de la source ne sont pas accessibles,
141
 *       -   si le fichier temporaire n'existe pas,
142
 *       -   si la fonction `_imagecreatefrom{extension}` n'existe pas ;
143
 *     - "" (chaîne vide) si le fichier source est distant et n'a pas
144
 *       réussi à être copié sur le serveur ;
145
 *     - array : tableau décrivant de l'image
146
 */
147
function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = null, $find_in_path = false, $support_svg = false) {
148
	static $images_recalcul = array();
149
	if (strlen($img) == 0) {
150
		return false;
151
	}
152
153
	$source = trim(extraire_attribut($img, 'src'));
154
	if (strlen($source) < 1) {
155
		$source = $img;
156
		$img = "<img src='$source' />";
157
	} # gerer img src="data:....base64"
158
	elseif (preg_match('@^data:image/([^;]*);base64,(.*)$@isS', $source, $regs)
159
	  and $extension = _image_trouver_extension_depuis_mime("image/".$regs[1])
160
		and in_array($extension, _image_extensions_acceptees_en_entree())
161
	) {
162
		$local = sous_repertoire(_DIR_VAR, 'image-data') . md5($regs[2]) . '.' . _image_extension_normalisee($extension);
163
		if (!file_exists($local)) {
164
			ecrire_fichier($local, base64_decode($regs[2]));
165
		}
166
		$source = $local;
167
		$img = inserer_attribut($img, 'src', $source);
168
		# eviter les mauvaises surprises lors de conversions de format
169
		$img = inserer_attribut($img, 'width', '');
170
		$img = inserer_attribut($img, 'height', '');
171
	}
172
173
	// les protocoles web prennent au moins 3 lettres
174
	if (tester_url_absolue($source)) {
175
		include_spip('inc/distant');
176
		$fichier = _DIR_RACINE . copie_locale($source);
177
		if (!$fichier) {
178
			return "";
179
		}
180
	} else {
181
		// enlever le timestamp eventuel
182
		if (strpos($source, "?") !== false) {
183
			$source = preg_replace(',[?][0-9]+$,', '', $source);
184
		}
185
		if (strpos($source, "?") !== false
186
			and strncmp($source, _DIR_IMG, strlen(_DIR_IMG)) == 0
187
			and file_exists($f = preg_replace(',[?].*$,', '', $source))
188
		) {
189
			$source = $f;
190
		}
191
		$fichier = $source;
192
	}
193
194
	$terminaison_dest = "";
195
	if ($terminaison = _image_trouver_extension($fichier)) {
196
		$terminaison_dest = ($terminaison == 'gif') ? 'png' : $terminaison;
197
	}
198
199
	if ($forcer_format !== false
200
		// 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
201
		and ($terminaison_dest !== 'svg' or $support_svg or !in_array($forcer_format,_image_extensions_acceptees_en_sortie()))) {
202
		$terminaison_dest = $forcer_format;
203
	}
204
205
	if (!$terminaison_dest) {
206
		return false;
207
	}
208
209
	$nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
210
	$fichier_dest = $nom_fichier;
211
	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...
212
		or @file_exists($f = $fichier)
213
	) {
214
		// on passe la balise img a taille image qui exraira les attributs si possible
215
		// au lieu de faire un acces disque sur le fichier
216
		list($ret["hauteur"], $ret["largeur"]) = taille_image($find_in_path ? $f : $img);
217
		$date_src = @filemtime($f);
218
	} elseif (@file_exists($f = "$fichier.src")
219
		and lire_fichier($f, $valeurs)
220
		and $valeurs = unserialize($valeurs)
221
		and isset($valeurs["hauteur_dest"])
222
		and isset($valeurs["largeur_dest"])
223
	) {
224
		$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...
225
		$ret["largeur"] = $valeurs["largeur_dest"];
226
		$date_src = $valeurs["date"];
227
	} // pas de fichier source par la
228
	else {
229
		return false;
230
	}
231
232
	// pas de taille mesurable
233
	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...
234
		return false;
235
	}
236
237
	// les images calculees dependent du chemin du fichier source
238
	// 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
239
	// ce n'est pas totalement optimal en terme de stockage, mais chaque image est associee a un fichier .src
240
	// qui contient la methode de reconstrucion (le filtre + les arguments d'appel) et les arguments different entre prive et public
241
	// la mise en commun du fichier image cree donc un bug et des problemes qui necessiteraient beaucoup de complexite de code
242
	// alors que ca concerne peu de site au final
243
	// la release de r23632+r23633+r23634 a provoque peu de remontee de bug attestant du peu de sites impactes
244
	$identifiant = $fichier;
245
246
	// cas general :
247
	// on a un dossier cache commun et un nom de fichier qui varie avec l'effet
248
	// cas particulier de reduire :
249
	// un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
250
	$cache = "cache-gd2";
251
	if (substr($effet, 0, 7) == 'reduire') {
252
		list(, $maxWidth, $maxHeight) = explode('-', $effet);
253
		list($destWidth, $destHeight) = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
254
		$ret['largeur_dest'] = $destWidth;
255
		$ret['hauteur_dest'] = $destHeight;
256
		$effet = "L{$destWidth}xH$destHeight";
257
		$cache = "cache-vignettes";
258
		$fichier_dest = basename($fichier_dest);
259
		if (($ret['largeur'] <= $maxWidth) && ($ret['hauteur'] <= $maxHeight)) {
260
			// on garde la terminaison initiale car image simplement copiee
261
			// et on postfixe son nom avec un md5 du path
262
			$terminaison_dest = $terminaison;
263
			$fichier_dest .= '-' . substr(md5("$identifiant"), 0, 5);
264
		} else {
265
			$fichier_dest .= '-' . substr(md5("$identifiant-$effet"), 0, 5);
266
		}
267
		$cache = sous_repertoire(_DIR_VAR, $cache);
268
		$cache = sous_repertoire($cache, $effet);
269
	} else {
270
		$fichier_dest = md5("$identifiant-$effet");
271
		$cache = sous_repertoire(_DIR_VAR, $cache);
272
		$cache = sous_repertoire($cache, substr($fichier_dest, 0, 2));
273
		$fichier_dest = substr($fichier_dest, 2);
274
	}
275
276
	$fichier_dest = $cache . $fichier_dest . "." . $terminaison_dest;
277
278
	$GLOBALS["images_calculees"][] = $fichier_dest;
279
280
	$creer = true;
281
	// si recalcul des images demande, recalculer chaque image une fois
282
	if (defined('_VAR_IMAGES') and _VAR_IMAGES and !isset($images_recalcul[$fichier_dest])) {
283
		$images_recalcul[$fichier_dest] = true;
284
	} else {
285
		if (@file_exists($f = $fichier_dest)) {
286
			if (filemtime($f) >= $date_src) {
287
				$creer = false;
288
			}
289
		} else {
290
			if (@file_exists($f = "$fichier_dest.src")
291
				and lire_fichier($f, $valeurs)
292
				and $valeurs = unserialize($valeurs)
293
				and $valeurs["date"] >= $date_src
294
			) {
295
				$creer = false;
296
			}
297
		}
298
	}
299
	if ($creer) {
300
		if (!@file_exists($fichier)) {
301
			if (!@file_exists("$fichier.src")) {
302
				spip_log("Image absente : $fichier");
303
304
				return false;
305
			}
306
			# on reconstruit l'image source absente a partir de la chaine des .src
307
			reconstruire_image_intermediaire($fichier);
0 ignored issues
show
Bug introduced by
It seems like $fichier defined by $f on line 211 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...
308
		}
309
	}
310
311
	if ($creer) {
312
		spip_log("filtre image " . ($fonction_creation ? reset($fonction_creation) : '') . "[$effet] sur $fichier",
313
			"images" . _LOG_DEBUG);
314
	}
315
316
	$term_fonction = _image_trouver_extension_pertinente($fichier);
0 ignored issues
show
Bug introduced by
It seems like $fichier defined by $f on line 211 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...
317
	$ret["fonction_imagecreatefrom"] = "_imagecreatefrom" . $term_fonction;
318
	$ret["fichier"] = $fichier;
319
	$ret["fonction_image"] = "_image_image" . $terminaison_dest;
320
	$ret["fichier_dest"] = $fichier_dest;
321
	$ret["format_source"] = _image_extension_normalisee($terminaison);
322
	$ret["format_dest"] = $terminaison_dest;
323
	$ret["date_src"] = $date_src;
324
	$ret["creer"] = $creer;
325
	$ret["class"] = extraire_attribut($img, 'class');
326
	$ret["alt"] = extraire_attribut($img, 'alt');
327
	$ret["style"] = extraire_attribut($img, 'style');
328
	$ret["tag"] = $img;
329
	if ($fonction_creation) {
330
		$ret["reconstruction"] = $fonction_creation;
331
		# ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement 
332
		# cas de image_reduire qui finalement ne reduit pas l'image source
333
		# ca evite d'essayer de le creer au prochain hit si il n'est pas la
334
		#ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
335
	}
336
337
	$ret = pipeline('image_preparer_filtre', array(
338
			'args' => array(
339
				'img' => $img,
340
				'effet' => $effet,
341
				'forcer_format' => $forcer_format,
342
				'fonction_creation' => $fonction_creation,
343
				'find_in_path' => $find_in_path,
344
			),
345
			'data' => $ret
346
		)
347
	);
348
349
	// une globale pour le debug en cas de crash memoire
350
	$GLOBALS["derniere_image_calculee"] = $ret;
351
352
	// traiter le cas particulier des SVG : si le filtre n'a pas annonce explicitement qu'il savait faire, on delegue
353
	if ($term_fonction === 'svg') {
354
		if ($creer and !$support_svg) {
355
			process_image_svg_identite($ret);
356
			$ret['creer'] = false;
357
		}
358
	}
359
	else {
360
		if (!function_exists($ret["fonction_imagecreatefrom"])) {
361
			return false;
362
		}
363
	}
364
365
	return $ret;
366
}
367
368
369
/**
370
 * @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...
371
 * @return array
372
 */
373
function _image_extensions_acceptees_en_entree() {
374
	static $extensions = null;
375
	if (empty($extensions)) {
376
		$extensions = ['png', 'gif', 'jpg', 'jpeg', 'svg'];
377
		if (!empty($GLOBALS['meta']['gd_formats'])) {
378
			// action=tester renseigne gd_formats et detecte le support de webp
379
			$extensions = array_merge(explode(',', $GLOBALS['meta']['gd_formats']));
380
			$extensions = array_map('trim', $extensions);
381
			$extensions = array_filter($extensions);
382
			$extensions = array_unique($extensions);
383
		}
384
	}
385
386
	return $extensions;
387
}
388
389
/**
390
 * @return array|string[]|null
391
 */
392
function _image_extensions_acceptees_en_sortie(){
393
	static $extensions = null;
394
	if (empty($extensions)){
395
		$extensions = _image_extensions_acceptees_en_entree();
396
		$extensions = array_diff($extensions, ['jpeg']);
397 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...
398
			$extensions = array_diff($extensions, ['gif']);
399
		}
400 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...
401
			$extensions = array_diff($extensions, ['webp']);
402
		}
403
	}
404
405
	return $extensions;
406
}
407
408
function _image_extension_normalisee($extension){
409
	$extension = strtolower($extension);
410
	if ($extension === 'jpeg') {
411
		$extension = 'jpg';
412
	}
413
	return $extension;
414
}
415
416
function _image_extensions_conservent_transparence(){
417
	return ['png', 'webp'];
418
}
419
420
421
/**
422
 * Retourne la terminaison d’un fichier image
423
 * @param string $path
424
 * @return string
425
 */
426
function _image_trouver_extension($path) {
427
	$preg_extensions = implode('|', _image_extensions_acceptees_en_entree());
428
	if (preg_match(",\.($preg_extensions)($|[?]),i", $path, $regs)) {
429
		$terminaison = strtolower($regs[1]);
430
		return $terminaison;
431
	}
432
	return '';
433
}
434
435
/**
436
 * Tente de trouver le véritable type d’une image,
437
 * même si une image est d’extension .jpg alors que son contenu est autre chose (gif ou png)
438
 *
439
 * @param string $path
440
 * @return string Extension, dans le format attendu par les fonctions 'gd' ('jpeg' pour les .jpg par exemple)
441
 */
442
function _image_trouver_extension_pertinente($path) {
443
	$path = supprimer_timestamp($path);
444
	$terminaison = _image_trouver_extension($path);
445
	if ($terminaison == 'jpg') {
446
		$terminaison = 'jpeg';
447
	}
448
449
	if (!file_exists($path)) {
450
		return $terminaison;
451
	}
452
453
	if (!$info = @spip_getimagesize($path)) {
454
		return $terminaison;
455
	}
456
457
	if (isset($info['mime'])) {
458
		$mime = $info['mime'];
459
	}
460
	else {
461
		$mime = image_type_to_mime_type($info[2]);
462
	}
463
464
	$_terminaison = _image_trouver_extension_depuis_mime($mime);
465
	if ($_terminaison and $_terminaison !== $terminaison) {
466
		spip_log("Mauvaise extension du fichier : $path . Son type mime est : $mime", "images." . _LOG_INFO_IMPORTANTE);
467
		$terminaison = $_terminaison;
468
	}
469
	return $terminaison;
470
}
471
472
/**
473
 * @param string $mime
474
 * @return string
475
 */
476
function _image_trouver_extension_depuis_mime($mime) {
477
	switch (strtolower($mime)) {
478
		case 'image/png':
479
		case 'image/x-png':
480
			$terminaison = 'png';
481
			break;
482
483
		case 'image/jpg':
484
		case 'image/jpeg':
485
		case 'image/pjpeg':
486
			$terminaison = 'jpeg';
487
			break;
488
489
		case 'image/gif':
490
			$terminaison = 'gif';
491
			break;
492
493
		case 'image/webp':
494
		case 'image/x-webp':
495
			$terminaison = 'webp';
496
			break;
497
498
		case 'image/svg+xml':
499
			$terminaison = 'svg';
500
			break;
501
502
		default:
503
			$terminaison = '';
504
	}
505
506
	return $terminaison;
507
}
508
509
/**
510
 * Crée une image depuis un fichier ou une URL
511
 *
512
 * Utilise les fonctions spécifiques GD.
513
 *
514
 * @param string $filename
515
 *     Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg
516
 *     ou local/cache-vignettes/L180xH51/image.jpg).
517
 * @return resource
518
 *     Une ressource de type Image GD.
519
 */
520 View Code Duplication
function _imagecreatefromjpeg($filename) {
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...
521
	$img = @imagecreatefromjpeg($filename);
522
	if (!$img) {
523
		spip_log("Erreur lecture imagecreatefromjpeg $filename", _LOG_CRITIQUE);
524
		erreur_squelette("Erreur lecture imagecreatefromjpeg $filename");
525
		$img = imagecreate(10, 10);
526
	}
527
528
	return $img;
529
}
530
531
/**
532
 * Crée une image depuis un fichier ou une URL (au format png)
533
 *
534
 * Utilise les fonctions spécifiques GD.
535
 *
536
 * @param string $filename
537
 *     Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png
538
 *     ou local/cache-vignettes/L180xH51/image.png).
539
 * @return resource
540
 *     Une ressource de type Image GD.
541
 */
542 View Code Duplication
function _imagecreatefrompng($filename) {
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...
543
	$img = @imagecreatefrompng($filename);
544
	if (!$img) {
545
		spip_log("Erreur lecture imagecreatefrompng $filename", _LOG_CRITIQUE);
546
		erreur_squelette("Erreur lecture imagecreatefrompng $filename");
547
		$img = imagecreate(10, 10);
548
	}
549
550
	return $img;
551
}
552
553
/**
554
 * Crée une image depuis un fichier ou une URL (au format gif)
555
 *
556
 * Utilise les fonctions spécifiques GD.
557
 *
558
 * @param string $filename
559
 *     Le path vers l'image à traiter (par exemple : IMG/distant/gif/image.gif
560
 *     ou local/cache-vignettes/L180xH51/image.gif).
561
 * @return resource
562
 *     Une ressource de type Image GD.
563
 */
564 View Code Duplication
function _imagecreatefromgif($filename) {
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...
565
	$img = @imagecreatefromgif($filename);
566
	if (!$img) {
567
		spip_log("Erreur lecture imagecreatefromgif $filename", _LOG_CRITIQUE);
568
		erreur_squelette("Erreur lecture imagecreatefromgif $filename");
569
		$img = imagecreate(10, 10);
570
	}
571
572
	return $img;
573
}
574
575
576
/**
577
 * Crée une image depuis un fichier ou une URL (au format webp)
578
 *
579
 * Utilise les fonctions spécifiques GD.
580
 *
581
 * @param string $filename
582
 *     Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png
583
 *     ou local/cache-vignettes/L180xH51/image.png).
584
 * @return resource
585
 *     Une ressource de type Image GD.
586
 */
587 View Code Duplication
function _imagecreatefromwebp($filename) {
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...
588
	$img = @imagecreatefromwebp($filename);
589
	if (!$img) {
590
		spip_log("Erreur lecture imagecreatefromwebp $filename", _LOG_CRITIQUE);
591
		erreur_squelette("Erreur lecture imagecreatefrompng $filename");
592
		$img = imagecreate(10, 10);
593
	}
594
595
	return $img;
596
}
597
598
/**
599
 * Affiche ou sauvegarde une image au format PNG
600
 *
601
 * Utilise les fonctions spécifiques GD.
602
 *
603
 * @param ressource $img
604
 *     Une ressource de type Image GD.
605
 * @param string $fichier
606
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
607
 * @return bool
608
 *
609
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
610
 *     - true si une image est bien retournée.
611
 */
612 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...
613
	if (!function_exists('imagepng')) {
614
		return false;
615
	}
616
	$tmp = $fichier . ".tmp";
617
	$ret = imagepng($img, $tmp);
618
	if (file_exists($tmp)) {
619
		$taille_test = getimagesize($tmp);
620
		if ($taille_test[0] < 1) {
621
			return false;
622
		}
623
624
		spip_unlink($fichier); // le fichier peut deja exister
625
		@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...
626
627
		return $ret;
628
	}
629
630
	return false;
631
}
632
633
/**
634
 * Affiche ou sauvegarde une image au format GIF
635
 *
636
 * Utilise les fonctions spécifiques GD.
637
 *
638
 * @param resource $img
639
 *     Une ressource de type Image GD.
640
 * @param string $fichier
641
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.gif).
642
 * @return bool
643
 *
644
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
645
 *     - true si une image est bien retournée.
646
 */
647 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...
648
	if (!function_exists('imagegif')) {
649
		return false;
650
	}
651
	$tmp = $fichier . ".tmp";
652
	$ret = imagegif($img, $tmp);
653
	if (file_exists($tmp)) {
654
		$taille_test = getimagesize($tmp);
655
		if ($taille_test[0] < 1) {
656
			return false;
657
		}
658
659
		spip_unlink($fichier); // le fichier peut deja exister
660
		@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...
661
662
		return $ret;
663
	}
664
665
	return false;
666
}
667
668
/**
669
 * Affiche ou sauvegarde une image au format JPG
670
 *
671
 * Utilise les fonctions spécifiques GD.
672
 *
673
 * @param resource $img
674
 *     Une ressource de type Image GD.
675
 * @param string $fichier
676
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
677
 * @param int $qualite
678
 *     Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
679
 *     fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
680
 *     valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
681
 *     mes_options.php).
682
 * @return bool
683
 *
684
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
685
 *     - true si une image est bien retournée.
686
 */
687
function _image_imagejpg($img, $fichier, $qualite = _IMG_GD_QUALITE) {
688
	if (!function_exists('imagejpeg')) {
689
		return false;
690
	}
691
	$tmp = $fichier . ".tmp";
692
693
	// Enable interlancing
694
	imageinterlace($img, true);
695
696
	$ret = imagejpeg($img, $tmp, $qualite);
697
698
	if (file_exists($tmp)) {
699
		$taille_test = getimagesize($tmp);
700
		if ($taille_test[0] < 1) {
701
			return false;
702
		}
703
704
		spip_unlink($fichier); // le fichier peut deja exister
705
		@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...
706
707
		return $ret;
708
	}
709
710
	return false;
711
}
712
713
/**
714
 * Crée un fichier-image au format ICO
715
 *
716
 * Utilise les fonctions de la classe phpthumb_functions.
717
 *
718
 * @uses phpthumb_functions::GD2ICOstring()
719
 *
720
 * @param resource $img
721
 *     Une ressource de type Image GD.
722
 * @param string $fichier
723
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
724
 * @return bool
725
 *     true si le fichier a bien été créé ; false sinon.
726
 */
727
function _image_imageico($img, $fichier) {
728
	$gd_image_array = array($img);
729
730
	return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
731
}
732
733
734
/**
735
 * Affiche ou sauvegarde une image au format WEBP
736
 *
737
 * Utilise les fonctions spécifiques GD.
738
 *
739
 * @param resource $img
740
 *     Une ressource de type Image GD.
741
 * @param string $fichier
742
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
743
 * @return bool
744
 *
745
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
746
 *     - true si une image est bien retournée.
747
 */
748 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...
749
	if (!function_exists('imagewebp')) {
750
		return false;
751
	}
752
	$tmp = $fichier . ".tmp";
753
	$ret = imagewebp($img, $tmp, $qualite);
754
	if (file_exists($tmp)) {
755
		$taille_test = getimagesize($tmp);
756
		if ($taille_test[0] < 1) {
757
			return false;
758
		}
759
760
		spip_unlink($fichier); // le fichier peut deja exister
761
		@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...
762
763
		return $ret;
764
	}
765
766
	return false;
767
}
768
769
/**
770
 * Sauvegarde une image au format SVG
771
 *
772
 * - N'UTILISE PAS GD -
773
 * C'est une fonction derogatoire pour faciliter le traitement des SVG
774
 *
775
 * @param string $img
776
 *     contenu du SVG ou chemin vers le SVG source (et c'est alors une copie)
777
 * @param string $fichier
778
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
779
 * @return bool
780
 *
781
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
782
 *     - true si une image est bien retournée.
783
 */
784
function _image_imagesvg($img, $fichier) {
785
786
	$tmp = $fichier . ".tmp";
787
	if (strpos($img, "<") === false) {
788
		$img = supprimer_timestamp($img);
789
		if (!file_exists($img)) {
790
			return false;
791
		}
792
		@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...
793
		if (filesize($tmp) == filesize($img)) {
794
			spip_unlink($fichier); // le fichier peut deja exister
795
			@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...
796
			return true;
797
		}
798
		return false;
799
	}
800
801
	file_put_contents($tmp, $img);
802
	if (file_exists($tmp)) {
803
		$taille_test = spip_getimagesize($tmp);
804
		if ($taille_test[0] < 1) {
805
			return false;
806
		}
807
808
		spip_unlink($fichier); // le fichier peut deja exister
809
		@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...
810
811
		return true;
812
	}
813
814
	return false;
815
}
816
817
818
/**
819
 * Finalise le traitement GD
820
 *
821
 * Crée un fichier_image temporaire .src ou vérifie que le fichier_image
822
 * définitif a bien été créé.
823
 *
824
 * @uses statut_effacer_images_temporaires()
825
 *
826
 * @param resource|string $img
827
 *     Une ressource de type Image GD (ou une string pour un SVG)
828
 * @param array $valeurs
829
 *     Un tableau des informations (tailles, traitement, path...) accompagnant
830
 *     l'image.
831
 * @param int $qualite
832
 *     N'est utilisé que pour les images jpg.
833
 *     Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
834
 *     fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
835
 *     valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
836
 *     mes_options.php).
837
 * @return bool
838
 *     - true si le traitement GD s'est bien finalisé ;
839
 *     - false sinon.
840
 */
841
function _image_gd_output($img, $valeurs, $qualite = _IMG_GD_QUALITE) {
842
	$fonction = "_image_image" . $valeurs['format_dest'];
843
	$ret = false;
844
	#un flag pour reperer les images gravees
845
	$lock =
846
		!statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
847
	or (@file_exists($valeurs['fichier_dest']) and !@file_exists($valeurs['fichier_dest'] . '.src'));
848
	if (
849
		function_exists($fonction)
850
		&& ($ret = $fonction($img, $valeurs['fichier_dest'], $qualite)) # on a reussi a creer l'image
851
		&& isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
852
		&& !$lock
853
	) {
854
		if (@file_exists($valeurs['fichier_dest'])) {
855
			// dans tous les cas mettre a jour la taille de l'image finale
856
			list($valeurs["hauteur_dest"], $valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']);
857
			$valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
858
			ecrire_fichier($valeurs['fichier_dest'] . '.src', serialize($valeurs), true);
859
		}
860
	}
861
862
	return $ret;
863
}
864
865
/**
866
 * Reconstruit une image à partir des sources de contrôle de son ancienne
867
 * construction
868
 *
869
 * @uses ramasse_miettes()
870
 *
871
 * @param string $fichier_manquant
872
 *     Chemin vers le fichier manquant
873
 **/
874
function reconstruire_image_intermediaire($fichier_manquant) {
875
	$reconstruire = array();
876
	$fichier = $fichier_manquant;
877
	while (strpos($fichier,"://")===false
878
		and !@file_exists($fichier)
879
		and lire_fichier($src = "$fichier.src", $source)
880
		and $valeurs = unserialize($source)
881
		and ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
882
	) {
883
		spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
884
		$reconstruire[] = $valeurs['reconstruction'];
885
	}
886
	while (count($reconstruire)) {
887
		$r = array_pop($reconstruire);
888
		$fonction = $r[0];
889
		$args = $r[1];
890
		call_user_func_array($fonction, $args);
891
	}
892
	// cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
893
	// mais l'on peut nettoyer les miettes de sa creation
894
	ramasse_miettes($fichier_manquant);
895
}
896
897
/**
898
 * Indique qu'un fichier d'image calculé est à conserver
899
 *
900
 * Permet de rendre une image définitive et de supprimer les images
901
 * intermédiaires à son calcul.
902
 *
903
 * Supprime le fichier de contrôle de l’image cible (le $fichier.src)
904
 * ce qui indique que l'image est définitive.
905
 *
906
 * Remonte ensuite la chaîne des fichiers de contrôle pour supprimer
907
 * les images temporaires (mais laisse les fichiers de contrôle permettant
908
 * de les reconstruire).
909
 *
910
 * @param string $fichier
911
 *     Chemin du fichier d'image calculé
912
 **/
913
function ramasse_miettes($fichier) {
914
	if (strpos($fichier,"://")!==false
915
		or !lire_fichier($src = "$fichier.src", $source)
916
		or !$valeurs = unserialize($source)
917
	) {
918
		return;
919
	}
920
	spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
921
	while (
922
		($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
923
		and (substr($fichier, 0, strlen(_DIR_VAR)) == _DIR_VAR) # et est dans local
924
		and (lire_fichier($src = "$fichier.src",
925
			$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire)
926
		and ($valeurs = unserialize($source))  # et valide
927
	) {
928
		# on efface le fichier
929
		spip_unlink($fichier);
930
		# mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
931
		#spip_unlink($src);
932
	}
933
}
934
935
936
/**
937
 * Clôture une série de filtres d'images
938
 *
939
 * Ce filtre est automatiquement appelé à la fin d'une série de filtres
940
 * d'images dans un squelette.
941
 *
942
 * @filtre
943
 * @uses reconstruire_image_intermediaire()
944
 *     Si l'image finale a déjà été supprimée car considérée comme temporaire
945
 *     par une autre série de filtres images débutant pareil
946
 * @uses ramasse_miettes()
947
 *     Pour déclarer l'image définitive et nettoyer les images intermédiaires.
948
 *
949
 * @pipeline_appel post_image_filtrer
950
 *
951
 * @param string $img
952
 *     Code HTML de l'image
953
 * @return string
954
 *     Code HTML de l'image
955
 **/
956
function image_graver($img) {
957
	// appeler le filtre post_image_filtrer qui permet de faire
958
	// des traitements auto a la fin d'une serie de filtres
959
	$img = pipeline('post_image_filtrer', $img);
960
961
	$fichier_ori = $fichier = extraire_attribut($img, 'src');
962 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...
963
		$fichier = substr($fichier, 0, $p);
964
	}
965
	if (strlen($fichier) < 1) {
966
		$fichier = $img;
967
	}
968
	# si jamais le fichier final n'a pas ete calcule car suppose temporaire
969
	# et qu'il ne s'agit pas d'une URL
970
	if (strpos($fichier,"://")===false and !@file_exists($fichier)) {
971
		reconstruire_image_intermediaire($fichier);
972
	}
973
	ramasse_miettes($fichier);
974
975
	// ajouter le timestamp si besoin
976
	if (strpos($fichier_ori, "?") === false) {
977
		// on utilise str_replace pour attraper le onmouseover des logo si besoin
978
		$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 961 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...
979
	}
980
981
	return $img;
982
}
983
984
985
if (!function_exists("imagepalettetotruecolor")) {
986
	/**
987
	 * Transforme une image à palette indexée (256 couleurs max) en "vraies" couleurs RGB
988
	 *
989
	 * @note Pour compatibilité avec PHP < 5.5
990
	 *
991
	 * @link http://php.net/manual/fr/function.imagepalettetotruecolor.php
992
	 *
993
	 * @param ressource $img
994
	 * @return bool
995
	 *     - true si l'image est déjà en vrai RGB ou peut être transformée
996
	 *     - false si la transformation ne peut être faite.
997
	 **/
998
	function imagepalettetotruecolor(&$img) {
999
		if (!$img or !function_exists('imagecreatetruecolor')) {
1000
			return false;
1001
		} elseif (!imageistruecolor($img)) {
1002
			$w = imagesx($img);
1003
			$h = imagesy($img);
1004
			$img1 = imagecreatetruecolor($w, $h);
1005
			//Conserver la transparence si possible
1006
			if (function_exists('ImageCopyResampled')) {
1007
				if (function_exists("imageAntiAlias")) {
1008
					imageAntiAlias($img1, true);
1009
				}
1010
				@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...
1011
				@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...
1012
				@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...
1013
			} else {
1014
				imagecopy($img1, $img, 0, 0, 0, 0, $w, $h);
1015
			}
1016
1017
			$img = $img1;
1018
		}
1019
1020
		return true;
1021
	}
1022
}
1023
1024
/**
1025
 * Applique des attributs de taille (width, height) à une balise HTML
1026
 *
1027
 * Utilisé avec des balises `<img>` tout particulièrement.
1028
 *
1029
 * Modifie l'attribut style s'il était renseigné, en enlevant les
1030
 * informations éventuelles width / height dedans.
1031
 *
1032
 * @uses extraire_attribut()
1033
 * @uses inserer_attribut()
1034
 *
1035
 * @param string $tag
1036
 *     Code html de la balise
1037
 * @param int $width
1038
 *     Hauteur
1039
 * @param int $height
1040
 *     Largeur
1041
 * @param bool|string $style
1042
 *     Attribut html style à appliquer.
1043
 *     False extrait celui présent dans la balise
1044
 * @return string
1045
 *     Code html modifié de la balise.
1046
 **/
1047
function _image_tag_changer_taille($tag, $width, $height, $style = false) {
1048
	if ($style === false) {
1049
		$style = extraire_attribut($tag, 'style');
1050
	}
1051
1052
	// enlever le width et height du style
1053
	$style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims", "", $style);
1054
	if ($style and $style[0] == ';') {
1055
		$style = substr($style, 1);
1056
	}
1057
1058
	// mettre des attributs de width et height sur les images, 
1059
	// ca accelere le rendu du navigateur
1060
	// ca permet aux navigateurs de reserver la bonne taille 
1061
	// quand on a desactive l'affichage des images.
1062
	$tag = inserer_attribut($tag, 'width', round($width));
1063
	$tag = inserer_attribut($tag, 'height', round($height));
1064
1065
	// attributs deprecies. Transformer en CSS
1066
	if ($espace = extraire_attribut($tag, 'hspace')) {
1067
		$style = "margin:${espace}px;" . $style;
1068
		$tag = inserer_attribut($tag, 'hspace', '');
1069
	}
1070
1071
	$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 1053 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...
1072
1073
	return $tag;
1074
}
1075
1076
1077
/**
1078
 * Écriture de la balise img en sortie de filtre image
1079
 *
1080
 * Reprend le tag initial et surcharge les attributs modifiés
1081
 *
1082
 * @pipeline_appel image_ecrire_tag_preparer
1083
 * @pipeline_appel image_ecrire_tag_finir
1084
 *
1085
 * @uses _image_tag_changer_taille()
1086
 * @uses extraire_attribut()
1087
 * @uses inserer_attribut()
1088
 * @see  _image_valeurs_trans()
1089
 *
1090
 * @param array $valeurs
1091
 *     Description de l'image tel que retourné par `_image_valeurs_trans()`
1092
 * @param array $surcharge
1093
 *     Permet de surcharger certaines descriptions présentes dans `$valeurs`
1094
 *     tel que 'style', 'width', 'height'
1095
 * @return string
1096
 *     Retourne le code HTML de l'image
1097
 **/
1098
function _image_ecrire_tag($valeurs, $surcharge = array()) {
1099
	$valeurs = pipeline('image_ecrire_tag_preparer', $valeurs);
1100
1101
	// fermer les tags img pas bien fermes;
1102
	$tag = str_replace(">", "/>", str_replace("/>", ">", $valeurs['tag']));
1103
1104
	// le style
1105
	$style = $valeurs['style'];
1106
	if (isset($surcharge['style'])) {
1107
		$style = $surcharge['style'];
1108
		unset($surcharge['style']);
1109
	}
1110
1111
	// traiter specifiquement la largeur et la hauteur
1112
	$width = $valeurs['largeur'];
1113
	if (isset($surcharge['width'])) {
1114
		$width = $surcharge['width'];
1115
		unset($surcharge['width']);
1116
	}
1117
	$height = $valeurs['hauteur'];
1118
	if (isset($surcharge['height'])) {
1119
		$height = $surcharge['height'];
1120
		unset($surcharge['height']);
1121
	}
1122
1123
	$tag = _image_tag_changer_taille($tag, $width, $height, $style);
1124
	// traiter specifiquement le src qui peut etre repris dans un onmouseout
1125
	// on remplace toute les ref a src dans le tag
1126
	$src = extraire_attribut($tag, 'src');
1127
	if (isset($surcharge['src'])) {
1128
		$tag = str_replace($src, $surcharge['src'], $tag);
1129
		// si il y a des & dans src, alors ils peuvent provenir d'un &amp
1130
		// pas garanti comme methode, mais mieux que rien
1131
		if (strpos($src, '&') !== false) {
1132
			$tag = str_replace(str_replace("&", "&amp;", $src), $surcharge['src'], $tag);
1133
		}
1134
		$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...
1135
		unset($surcharge['src']);
1136
	}
1137
1138
	$class = $valeurs['class'];
1139
	if (isset($surcharge['class'])) {
1140
		$class = $surcharge['class'];
1141
		unset($surcharge['class']);
1142
	}
1143
	if (strlen($class)) {
1144
		$tag = inserer_attribut($tag, 'class', $class);
1145
	}
1146
1147
	if (count($surcharge)) {
1148
		foreach ($surcharge as $attribut => $valeur) {
1149
			$tag = inserer_attribut($tag, $attribut, $valeur);
1150
		}
1151
	}
1152
1153
	$tag = pipeline('image_ecrire_tag_finir',
1154
		array(
1155
			'args' => array(
1156
				'valeurs' => $valeurs,
1157
				'surcharge' => $surcharge,
1158
			),
1159
			'data' => $tag
1160
		)
1161
	);
1162
1163
	return $tag;
1164
}
1165
1166
/**
1167
 * Crée si possible une miniature d'une image
1168
 *
1169
 * @see  _image_valeurs_trans()
1170
 * @uses _image_ratio()
1171
 *
1172
 * @param array $valeurs
1173
 *     Description de l'image, telle que retournée par `_image_valeurs_trans()`
1174
 * @param int $maxWidth
1175
 *     Largeur maximum en px de la miniature à réaliser
1176
 * @param int $maxHeight
1177
 *     Hauteur maximum en px de la miniateure à réaliser
1178
 * @param string $process
1179
 *     Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
1180
 *     AUTO utilise la librairie sélectionnée dans la configuration.
1181
 * @param bool $force
1182
 * @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...
1183
 *     Description de l'image, sinon null.
1184
 **/
1185
function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process = 'AUTO', $force = false) {
1186
	// ordre de preference des formats graphiques pour creer les vignettes
1187
	// le premier format disponible, selon la methode demandee, est utilise
1188
	$image = $valeurs['fichier'];
1189
	$format = $valeurs['format_source'];
1190
	$destdir = dirname($valeurs['fichier_dest']);
1191
	$destfile = basename($valeurs['fichier_dest'], "." . $valeurs["format_dest"]);
1192
1193
	$format_sortie = $valeurs['format_dest'];
1194
1195 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...
1196
		$process = $GLOBALS['meta']['image_process'];
1197
	}
1198
1199
	// si le doc n'est pas une image dans un format accetpable, refuser
1200
	if (!$force and !in_array($format, formats_image_acceptables(in_array($process, ['gd1', 'gd2'])))) {
1201
		return;
1202
	}
1203
	$destination = "$destdir/$destfile";
1204
1205
	// calculer la taille
1206
	if (($srcWidth = $valeurs['largeur']) && ($srcHeight = $valeurs['hauteur'])) {
1207
		if (!($destWidth = $valeurs['largeur_dest']) || !($destHeight = $valeurs['hauteur_dest'])) {
1208
			list($destWidth, $destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight);
1209
		}
1210
	} elseif ($process == 'convert' or $process == 'imagick') {
1211
		$destWidth = $maxWidth;
1212
		$destHeight = $maxHeight;
1213
	} else {
1214
		spip_log("echec $process sur $image");
1215
1216
		return;
1217
	}
1218
1219
	$vignette = '';
1220
1221
	// Si l'image est de la taille demandee (ou plus petite), simplement la retourner
1222
	if ($srcWidth and $srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1223
		$vignette = $destination . '.' . $format;
1224
		@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...
1225
	}
1226
1227
	elseif ($valeurs["format_source"] === 'svg') {
1228
		if ($svg = svg_redimensionner($valeurs['fichier'], $destWidth, $destHeight)){
1229
			$format_sortie = 'svg';
1230
			$vignette = $destination . "." . $format_sortie;
1231
			$valeurs['fichier_dest'] = $vignette;
1232
			_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 1228 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...
1233
		}
1234
	}
1235
1236
	// imagemagick en ligne de commande
1237
	elseif ($process == 'convert') {
1238
		if (!defined('_CONVERT_COMMAND')) {
1239
			define('_CONVERT_COMMAND', 'convert');
1240
		} // Securite : mes_options.php peut preciser le chemin absolu
1241
		if (!defined('_RESIZE_COMMAND')) {
1242
			define('_RESIZE_COMMAND', _CONVERT_COMMAND . ' -quality ' . _IMG_CONVERT_QUALITE . ' -resize %xx%y! %src %dest');
1243
		}
1244
		$vignette = $destination . "." . $format_sortie;
1245
		$commande = str_replace(
1246
			array('%x', '%y', '%src', '%dest'),
1247
			array(
1248
				$destWidth,
1249
				$destHeight,
1250
				escapeshellcmd($image),
1251
				escapeshellcmd($vignette)
1252
			),
1253
			_RESIZE_COMMAND);
1254
		spip_log($commande);
1255
		exec($commande);
1256
		if (!@file_exists($vignette)) {
1257
			spip_log("echec convert sur $vignette");
1258
1259
			return;  // echec commande
1260
		}
1261
	}
1262
1263
	// php5 imagemagick
1264
	elseif ($process == 'imagick') {
1265
		$vignette = "$destination." . $format_sortie;
1266
1267
		if (!class_exists('Imagick')) {
1268
			spip_log("Classe Imagick absente !", _LOG_ERREUR);
1269
1270
			return;
1271
		}
1272
		$imagick = new Imagick();
1273
		$imagick->readImage($image);
1274
		$imagick->resizeImage($destWidth, $destHeight, Imagick::FILTER_LANCZOS,
1275
			1);//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100);
1276
		$imagick->writeImage($vignette);
1277
1278
		if (!@file_exists($vignette)) {
1279
			spip_log("echec imagick sur $vignette");
1280
1281
			return;
1282
		}
1283
	}
1284
1285
	// netpbm
1286
	elseif ($process == "netpbm") {
1287
		if (!defined('_PNMSCALE_COMMAND')) {
1288
			define('_PNMSCALE_COMMAND', 'pnmscale');
1289
		} // Securite : mes_options.php peut preciser le chemin absolu
1290
		if (_PNMSCALE_COMMAND == '') {
1291
			return;
1292
		}
1293
		$vignette = $destination . "." . $format_sortie;
1294
		$pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND);
1295
		if ($format == "jpg") {
1296
1297
			$jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND);
1298
			exec("$jpegtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1299
			if (!($s = @filesize($vignette))) {
1300
				spip_unlink($vignette);
1301
			}
1302
			if (!@file_exists($vignette)) {
1303
				spip_log("echec netpbm-jpg sur $vignette");
1304
1305
				return;
1306
			}
1307
		} else {
1308
			if ($format == "gif") {
1309
				$giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND);
1310
				exec("$giftopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1311
				if (!($s = @filesize($vignette))) {
1312
					spip_unlink($vignette);
1313
				}
1314
				if (!@file_exists($vignette)) {
1315
					spip_log("echec netpbm-gif sur $vignette");
1316
1317
					return;
1318
				}
1319
			} else {
1320
				if ($format == "png") {
1321
					$pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND);
1322
					exec("$pngtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1323
					if (!($s = @filesize($vignette))) {
1324
						spip_unlink($vignette);
1325
					}
1326
					if (!@file_exists($vignette)) {
1327
						spip_log("echec netpbm-png sur $vignette");
1328
1329
						return;
1330
					}
1331
				}
1332
			}
1333
		}
1334
	}
1335
1336
	// gd ou gd2
1337
	elseif ($process == 'gd1' or $process == 'gd2') {
1338
		if (!function_exists('gd_info')) {
1339
			spip_log("Librairie GD absente !", _LOG_ERREUR);
1340
1341
			return;
1342
		}
1343
		if (_IMG_GD_MAX_PIXELS && $srcWidth * $srcHeight > _IMG_GD_MAX_PIXELS) {
1344
			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...
1345
1346
			return;
1347
		}
1348
		$destFormat = $format_sortie;
1349
		if (!$destFormat) {
1350
			spip_log("pas de format pour $image");
1351
1352
			return;
1353
		}
1354
1355
		$fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
1356
		if (!function_exists($fonction_imagecreatefrom)) {
1357
			return '';
1358
		}
1359
		$srcImage = @$fonction_imagecreatefrom($image);
1360
		if (!$srcImage) {
1361
			spip_log("echec gd1/gd2");
1362
1363
			return;
1364
		}
1365
1366
		// Initialisation de l'image destination
1367
		$destImage = null;
1368
		if ($process == 'gd2' and $destFormat != "gif") {
1369
			$destImage = ImageCreateTrueColor($destWidth, $destHeight);
1370
		}
1371
		if (!$destImage) {
1372
			$destImage = ImageCreate($destWidth, $destHeight);
1373
		}
1374
1375
		// Recopie de l'image d'origine avec adaptation de la taille 
1376
		$ok = false;
1377
		if (($process == 'gd2') and function_exists('ImageCopyResampled')) {
1378
			if ($format == "gif") {
1379
				// Si un GIF est transparent, 
1380
				// fabriquer un PNG transparent  
1381
				$transp = imagecolortransparent($srcImage);
1382
				if ($transp > 0) {
1383
					$destFormat = "png";
1384
				}
1385
			}
1386
			if (in_array($destFormat, _image_extensions_conservent_transparence())) {
1387
				// Conserver la transparence 
1388
				if (function_exists("imageAntiAlias")) {
1389
					imageAntiAlias($destImage, true);
1390
				}
1391
				@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...
1392
				@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...
1393
			}
1394
			$ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1395
		}
1396
		if (!$ok) {
1397
			$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...
1398
		}
1399
1400
		// Sauvegarde de l'image destination
1401
		$valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
1402
		$valeurs['format_dest'] = $format = $destFormat;
1403
		_image_gd_output($destImage, $valeurs);
1404
1405
		if ($srcImage) {
1406
			ImageDestroy($srcImage);
1407
		}
1408
		ImageDestroy($destImage);
1409
	}
1410
1411
	if (!$vignette or !$size = @spip_getimagesize($vignette)) {
1412
		$size = array($destWidth, $destHeight);
1413
	}
1414
1415
	// Gaffe: en safe mode, pas d'acces a la vignette,
1416
	// donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
1417
	if ($size[0] < 1) {
1418
		$size[0] = $destWidth;
1419
	}
1420
	if ($size[1] < 1) {
1421
		$size[1] = $destHeight;
1422
	}
1423
1424
	$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...
1425
	$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...
1426
1427
	$retour['fichier'] = $vignette;
1428
	$retour['format'] = $format;
1429
	$retour['date'] = @filemtime($vignette);
1430
1431
	// renvoyer l'image
1432
	return $retour;
1433
}
1434
1435
/**
1436
 * Réduire des dimensions en respectant un ratio
1437
 *
1438
 * Réduit des dimensions (hauteur, largeur) pour qu'elles
1439
 * soient incluses dans une hauteur et largeur maximum fournies
1440
 * en respectant la proportion d'origine
1441
 *
1442
 * @example `image_ratio(1000, 1000, 100, 10)` donne `array(10, 10, 100)`
1443
 * @see ratio_passe_partout() Assez proche.
1444
 *
1445
 * @param int $srcWidth Largeur de l'image source
1446
 * @param int $srcHeight Hauteur de l'image source
1447
 * @param int $maxWidth Largeur maximum souhaitée
1448
 * @param int $maxHeight Hauteur maximum souhaitée
1449
 * @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 array<double|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...
1450
 **/
1451 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...
1452
	$ratioWidth = $srcWidth / $maxWidth;
1453
	$ratioHeight = $srcHeight / $maxHeight;
1454
1455
	if ($ratioWidth <= 1 and $ratioHeight <= 1) {
1456
		$destWidth = $srcWidth;
1457
		$destHeight = $srcHeight;
1458
	} elseif ($ratioWidth < $ratioHeight) {
1459
		$destWidth = $srcWidth / $ratioHeight;
1460
		$destHeight = $maxHeight;
1461
	} else {
1462
		$destWidth = $maxWidth;
1463
		$destHeight = $srcHeight / $ratioWidth;
1464
	}
1465
1466
	return array(
1467
		ceil($destWidth),
1468
		ceil($destHeight),
1469
		max($ratioWidth, $ratioHeight)
1470
	);
1471
}
1472
1473
/**
1474
 * Réduire des dimensions en respectant un ratio sur la plus petite dimension
1475
 *
1476
 * Réduit des dimensions (hauteur, largeur) pour qu'elles
1477
 * soient incluses dans la plus grande hauteur ou largeur maximum fournie
1478
 * en respectant la proportion d'origine
1479
 *
1480
 * @example `ratio_passe_partout(1000, 1000, 100, 10)` donne `array(100, 100, 10)`
1481
 * @see _image_ratio() Assez proche.
1482
 *
1483
 * @param int $srcWidth Largeur de l'image source
1484
 * @param int $srcHeight Hauteur de l'image source
1485
 * @param int $maxWidth Largeur maximum souhaitée
1486
 * @param int $maxHeight Hauteur maximum souhaitée
1487
 * @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 array<double|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...
1488
 **/
1489 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...
1490
	$ratioWidth = $srcWidth / $maxWidth;
1491
	$ratioHeight = $srcHeight / $maxHeight;
1492
1493
	if ($ratioWidth <= 1 and $ratioHeight <= 1) {
1494
		$destWidth = $srcWidth;
1495
		$destHeight = $srcHeight;
1496
	} elseif ($ratioWidth > $ratioHeight) {
1497
		$destWidth = $srcWidth / $ratioHeight;
1498
		$destHeight = $maxHeight;
1499
	} else {
1500
		$destWidth = $maxWidth;
1501
		$destHeight = $srcHeight / $ratioWidth;
1502
	}
1503
1504
	return array(
1505
		ceil($destWidth),
1506
		ceil($destHeight),
1507
		min($ratioWidth, $ratioHeight)
1508
	);
1509
}
1510
1511
1512
/**
1513
 * Fonction identite de traitement par defaut des images SVG
1514
 * (quand un filtre n'annonce pas qu'il sait traiter un SVG on applique cette fonction a la place)
1515
 *
1516
 * @param array $image
1517
 *   tableau des valeurs crees par _image_valeurs_trans
1518
 * @return string
1519
 */
1520
function process_image_svg_identite($image) {
1521
	if ($image['creer']) {
1522
		$source = $image['fichier'];
1523
		_image_gd_output($source, $image);
1524
	}
1525
1526
	return _image_ecrire_tag($image, array('src' => $image['fichier_dest']));
1527
}
1528
1529
1530
/**
1531
 * Réduit une image
1532
 *
1533
 * @uses extraire_attribut()
1534
 * @uses inserer_attribut()
1535
 * @uses _image_valeurs_trans()
1536
 * @uses _image_ratio()
1537
 * @uses _image_tag_changer_taille()
1538
 * @uses _image_ecrire_tag()
1539
 * @uses _image_creer_vignette()
1540
 *
1541
 * @param array $fonction
1542
 *     Un tableau à 2 éléments :
1543
 *     1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ;
1544
 *     2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé.
1545
 * @param string $img
1546
 *     Chemin de l'image ou texte contenant une balise img
1547
 * @param int $taille
1548
 *     Largeur désirée
1549
 * @param int $taille_y
1550
 *     Hauteur désirée
1551
 * @param bool $force
1552
 * @param string $process
1553
 *     Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
1554
 *     AUTO utilise la librairie sélectionnée dans la configuration.
1555
 * @return string
1556
 *     Code HTML de la balise img produite
1557
 **/
1558
function process_image_reduire($fonction, $img, $taille, $taille_y, $force, $process = 'AUTO') {
1559
	$image = false;
1560 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...
1561
		$process = $GLOBALS['meta']['image_process'];
1562
	}
1563
	# determiner le format de sortie
1564
	$format_sortie = false; // le choix par defaut sera bon
1565
	if ($process == "netpbm") {
1566
		$format_sortie = "jpg";
1567
	} elseif ($process == 'gd1' or $process == 'gd2') {
1568
		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1569
		// on verifie que l'extension choisie est bonne (en principe oui)
1570
		$gd_formats = formats_image_acceptables(true);
1571
		if (is_array($image)
1572
			and (!in_array($image['format_dest'], $gd_formats)
1573
				or (!in_array($image['format_dest'], _image_extensions_acceptees_en_sortie()))
1574
			)
1575
		) {
1576
			if ($image['format_source'] == 'jpg') {
1577
				$formats_sortie = array('jpg', 'png', 'gif');
1578
			} else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
1579
			{
1580
				$formats_sortie = array('png', 'jpg', 'gif');
1581
			}
1582
			// Choisir le format destination
1583
			// - on sauve de preference en JPEG (meilleure compression)
1584
			// - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
1585
			# bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
1586
			# pas *ecrire*
1587
			$format_sortie = "";
1588
			foreach ($formats_sortie as $fmt) {
1589
				if (in_array($fmt, $gd_formats) and in_array($fmt, _image_extensions_acceptees_en_sortie())) {
1590
					$format_sortie = $fmt;
1591
					break;
1592
				}
1593
			}
1594
			$image = false;
1595
		}
1596
	}
1597
1598
	if (!is_array($image)) {
1599
		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1600
	}
1601
1602
	if (!is_array($image) or !$image['largeur'] or !$image['hauteur']) {
1603
		spip_log("image_reduire_src:pas de version locale de $img");
1604
		// on peut resizer en mode html si on dispose des elements
1605
		if ($srcw = extraire_attribut($img, 'width')
1606
			and $srch = extraire_attribut($img, 'height')
1607
		) {
1608
			list($w, $h) = _image_ratio($srcw, $srch, $taille, $taille_y);
1609
1610
			return _image_tag_changer_taille($img, $w, $h);
1611
		}
1612
		// la on n'a pas d'infos sur l'image source... on refile le truc a css
1613
		// sous la forme style='max-width: NNpx;'
1614
		return inserer_attribut($img, 'style',
1615
			"max-width: ${taille}px; max-height: ${taille_y}px");
1616
	}
1617
1618
	// si l'image est plus petite que la cible retourner une copie cachee de l'image
1619
	if (($image['largeur'] <= $taille) && ($image['hauteur'] <= $taille_y)) {
1620
		if ($image['creer']) {
1621
			@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...
1622
		}
1623
1624
		return _image_ecrire_tag($image, array('src' => $image['fichier_dest']));
1625
	}
1626
1627
	if ($image['creer'] == false && !$force) {
1628
		return _image_ecrire_tag($image,
1629
			array('src' => $image['fichier_dest'], 'width' => $image['largeur_dest'], 'height' => $image['hauteur_dest']));
1630
	}
1631
1632
	if (in_array($image["format_source"], _image_extensions_acceptees_en_entree())) {
1633
		$destWidth = $image['largeur_dest'];
1634
		$destHeight = $image['hauteur_dest'];
1635
		$logo = $image['fichier'];
1636
		$date = $image["date_src"];
1637
		$preview = _image_creer_vignette($image, $taille, $taille_y, $process, $force);
1638
1639
		if ($preview && $preview['fichier']) {
1640
			$logo = $preview['fichier'];
1641
			$destWidth = $preview['width'];
1642
			$destHeight = $preview['height'];
1643
			$date = $preview['date'];
1644
		}
1645
		// dans l'espace prive mettre un timestamp sur l'adresse 
1646
		// de l'image, de facon a tromper le cache du navigateur
1647
		// quand on fait supprimer/reuploader un logo
1648
		// (pas de filemtime si SAFE MODE)
1649
		$date = test_espace_prive() ? ('?' . $date) : '';
1650
1651
		return _image_ecrire_tag($image, array('src' => "$logo$date", 'width' => $destWidth, 'height' => $destHeight));
1652
	}
1653
	else {
1654
		# BMP, tiff ... les redacteurs osent tout!
1655
		return $img;
1656
	}
1657
}
1658
1659
/**
1660
 * Produire des fichiers au format .ico
1661
 *
1662
 * Avec du code récupéré de phpThumb()
1663
 *
1664
 * @author James Heinrich <[email protected]>
1665
 * @link http://phpthumb.sourceforge.net
1666
 *
1667
 * Class phpthumb_functions
1668
 */
1669
class phpthumb_functions {
1670
1671
	/**
1672
	 * Retourne la couleur d'un pixel dans une image
1673
	 *
1674
	 * @param ressource $img
1675
	 * @param int $x
1676
	 * @param int $y
1677
	 * @return array|bool
1678
	 */
1679
	public static function GetPixelColor(&$img, $x, $y) {
1680
		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...
1681
			return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
1682
		}
1683
		return false;
1684
	}
1685
1686
	/**
1687
	 * Retourne un nombre dans une représentation en Little Endian
1688
	 *
1689
	 * @param int $number
1690
	 * @param int $minbytes
1691
	 * @return string
1692
	 */
1693
	public static function LittleEndian2String($number, $minbytes = 1) {
1694
		$intstring = '';
1695
		while ($number > 0) {
1696
			$intstring = $intstring . chr($number & 255);
1697
			$number >>= 8;
1698
		}
1699
1700
		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
1701
	}
1702
1703
	/**
1704
	 * Transforme une ressource GD en image au format ICO
1705
	 *
1706
	 * @param array $gd_image_array
1707
	 *     Tableau de ressources d'images GD
1708
	 * @return string
1709
	 *     Image au format ICO
1710
	 */
1711
	public static function GD2ICOstring(&$gd_image_array) {
1712
		foreach ($gd_image_array as $key => $gd_image) {
1713
1714
			$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...
1715
			$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...
1716
			$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...
1717
			$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...
1718
1719
			$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...
1720
			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...
1721
				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...
1722
					$argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
1723
					$a = round(255 * ((127 - $argb['alpha']) / 127));
1724
					$r = $argb['red'];
1725
					$g = $argb['green'];
1726
					$b = $argb['blue'];
1727
1728
					if ($bpp[$key] == 32) {
1729
						$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...
1730
					} 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...
1731
						$icXOR[$key] .= chr($b) . chr($g) . chr($r);
1732
					}
1733
1734
					if ($a < 128) {
1735
						@$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...
1736
					} else {
1737
						@$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...
1738
					}
1739
				}
1740
				// mask bits are 32-bit aligned per scanline
1741
				while (strlen($icANDmask[$key][$y]) % 32) {
1742
					$icANDmask[$key][$y] .= '0';
1743
				}
1744
			}
1745
			$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...
1746
			foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
1747
				for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
1748
					$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...
1749
				}
1750
			}
1751
1752
		}
1753
1754
		foreach ($gd_image_array as $key => $gd_image) {
1755
			$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
1756
1757
			// BITMAPINFOHEADER - 40 bytes
1758
			$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...
1759
			$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";                // DWORD  biSize;
1760
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);    // LONG   biWidth;
1761
			// The biHeight member specifies the combined
1762
			// height of the XOR and AND masks.
1763
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
1764
			$BitmapInfoHeader[$key] .= "\x01\x00";                    // WORD   biPlanes;
1765
			$BitmapInfoHeader[$key] .= chr($bpp[$key]) . "\x00";              // wBitCount;
1766
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biCompression;
1767
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);      // DWORD  biSizeImage;
1768
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biXPelsPerMeter;
1769
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biYPelsPerMeter;
1770
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrUsed;
1771
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrImportant;
1772
		}
1773
1774
1775
		$icondata = "\x00\x00";                    // idReserved;   // Reserved (must be 0)
1776
		$icondata .= "\x01\x00";                    // idType;	   // Resource Type (1 for icons)
1777
		$icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2);  // idCount;	  // How many images?
1778
1779
		$dwImageOffset = 6 + (count($gd_image_array) * 16);
1780
		foreach ($gd_image_array as $key => $gd_image) {
1781
			// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
1782
1783
			$icondata .= chr($ImageWidths[$key]);           // bWidth;		  // Width, in pixels, of the image
1784
			$icondata .= chr($ImageHeights[$key]);          // bHeight;		 // Height, in pixels, of the image
1785
			$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...
1786
			$icondata .= "\x00";                    // bReserved;	   // Reserved ( must be 0)
1787
1788
			$icondata .= "\x01\x00";                  // wPlanes;		 // Color Planes
1789
			$icondata .= chr($bpp[$key]) . "\x00";            // wBitCount;	   // Bits per pixel
1790
1791
			$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
1792
			$icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes,
1793
				4);     // dwBytesInRes;	// How many bytes in this resource?
1794
1795
			$icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset,
1796
				4);    // dwImageOffset;   // Where in the file is this image?
1797
			$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...
1798
			$dwImageOffset += strlen($icXOR[$key]);
1799
			$dwImageOffset += strlen($icAND[$key]);
1800
		}
1801
1802
		foreach ($gd_image_array as $key => $gd_image) {
1803
			$icondata .= $BitmapInfoHeader[$key];
1804
			$icondata .= $icXOR[$key];
1805
			$icondata .= $icAND[$key];
1806
		}
1807
1808
		return $icondata;
1809
	}
1810
1811
}
1812