Completed
Push — master ( 2867a8...86ed55 )
by cam
06:18
created

filtres_images_lib_mini.php ➔ _image_trouver_extension()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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