Completed
Push — master ( 230805...a75156 )
by cam
05:02
created

filtres_images_lib_mini.php ➔ _image_imagesvg()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 6
nop 2
dl 0
loc 32
rs 8.7857
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
define('_SVG_SUPPORTED', true); // ne sert qu'a la lisibilite du code
28
29
/**
30
 * Transforme une couleur vectorielle R,G,B en hexa (par exemple pour usage css)
31
 *
32
 * @param int $red
33
 *     Valeur du rouge de 0 à 255.
34
 * @param int $green
35
 *     Valeur du vert de 0 à 255.
36
 * @param int $blue
37
 *     Valeur du bleu de 0 à 255.
38
 * @return string
39
 *     Le code de la couleur en hexadécimal.
40
 */
41
function _couleur_dec_to_hex($red, $green, $blue) {
42
	$red = dechex($red);
43
	$green = dechex($green);
44
	$blue = dechex($blue);
45
46
	if (strlen($red) == 1) {
47
		$red = "0" . $red;
48
	}
49
	if (strlen($green) == 1) {
50
		$green = "0" . $green;
51
	}
52
	if (strlen($blue) == 1) {
53
		$blue = "0" . $blue;
54
	}
55
56
	return "$red$green$blue";
57
}
58
59
/**
60
 * Transforme une couleur hexa en vectorielle R,G,B
61
 *
62
 * @param string $couleur
63
 *     Code couleur en hexa (#000000 à #FFFFFF).
64
 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,integer|double>.

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

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

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

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

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

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

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

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

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

Loading history...
125
 *     Un tableau à 2 éléments :
126
 *     1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ;
127
 *     2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé.
128
 * @param bool $find_in_path
129
 *     false (par défaut) indique que l'on travaille sur un fichier
130
 *     temporaire (.src) ; true, sur un fichier définitif déjà existant.
131
 * @param bool $support_svg
132
 *     false (par defaut) indique que le filtre ne sait pas traiter le cas particulier du SVG
133
 *     on lui substitue un filtre generique qui ne fait rien pour ne pas briser la chaine des filtres images
134
 *     true si le filtre appelant sait traiter les SVG
135
 * @return bool|string|array
136
 *
137
 *     - false si pas de tag `<img`,
138
 *       -   si l'extension n'existe pas,
139
 *       -   si le fichier source n'existe pas,
140
 *       -   si les dimensions de la source ne sont pas accessibles,
141
 *       -   si le fichier temporaire n'existe pas,
142
 *       -   si la fonction `_imagecreatefrom{extension}` n'existe pas ;
143
 *     - "" (chaîne vide) si le fichier source est distant et n'a pas
144
 *       réussi à être copié sur le serveur ;
145
 *     - array : tableau décrivant de l'image
146
 */
147
function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = null, $find_in_path = false, $support_svg = false) {
148
	static $images_recalcul = array();
149
	if (strlen($img) == 0) {
150
		return false;
151
	}
152
153
	$source = trim(extraire_attribut($img, 'src'));
154
	if (strlen($source) < 1) {
155
		$source = $img;
156
		$img = "<img src='$source' />";
157
	} # gerer img src="data:....base64"
158
	elseif (preg_match('@^data:image/(jpe?g|png|gif|svg+xml);base64,(.*)$@isS', $source, $regs)) {
159
		$local = sous_repertoire(_DIR_VAR, 'image-data') . md5($regs[2]) . '.' . str_replace('jpeg', 'jpg', $regs[1]);
160
		if (!file_exists($local)) {
161
			ecrire_fichier($local, base64_decode($regs[2]));
162
		}
163
		$source = $local;
164
		$img = inserer_attribut($img, 'src', $source);
165
		# eviter les mauvaises surprises lors de conversions de format
166
		$img = inserer_attribut($img, 'width', '');
167
		$img = inserer_attribut($img, 'height', '');
168
	}
169
170
	// les protocoles web prennent au moins 3 lettres
171
	if (tester_url_absolue($source)) {
172
		include_spip('inc/distant');
173
		$fichier = _DIR_RACINE . copie_locale($source);
174
		if (!$fichier) {
175
			return "";
176
		}
177
	} else {
178
		// enlever le timestamp eventuel
179
		if (strpos($source, "?") !== false) {
180
			$source = preg_replace(',[?][0-9]+$,', '', $source);
181
		}
182
		if (strpos($source, "?") !== false
183
			and strncmp($source, _DIR_IMG, strlen(_DIR_IMG)) == 0
184
			and file_exists($f = preg_replace(',[?].*$,', '', $source))
185
		) {
186
			$source = $f;
187
		}
188
		$fichier = $source;
189
	}
190
191
	$terminaison_dest = "";
192
	if ($terminaison = _image_trouver_extension($fichier)) {
193
		$terminaison_dest = ($terminaison == 'gif') ? 'png' : $terminaison;
194
	}
195
196
	if ($forcer_format !== false
197
		// ignorer forcer_format si on a une image svg, que le filtre appelant ne supporte pas SVG, et que le forcage est un autre format image
198
		and ($terminaison_dest !== 'svg' or $support_svg or !in_array($forcer_format,['png','gif','jpg']))) {
199
		$terminaison_dest = $forcer_format;
200
	}
201
202
	if (!$terminaison_dest) {
203
		return false;
204
	}
205
206
	$nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
207
	$fichier_dest = $nom_fichier;
208
	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...
209
		or @file_exists($f = $fichier)
210
	) {
211
		// on passe la balise img a taille image qui exraira les attributs si possible
212
		// au lieu de faire un acces disque sur le fichier
213
		list($ret["hauteur"], $ret["largeur"]) = taille_image($find_in_path ? $f : $img);
214
		$date_src = @filemtime($f);
215
	} elseif (@file_exists($f = "$fichier.src")
216
		and lire_fichier($f, $valeurs)
217
		and $valeurs = unserialize($valeurs)
218
		and isset($valeurs["hauteur_dest"])
219
		and isset($valeurs["largeur_dest"])
220
	) {
221
		$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...
222
		$ret["largeur"] = $valeurs["largeur_dest"];
223
		$date_src = $valeurs["date"];
224
	} // pas de fichier source par la
225
	else {
226
		return false;
227
	}
228
229
	// pas de taille mesurable
230
	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...
231
		return false;
232
	}
233
234
	// les images calculees dependent du chemin du fichier source
235
	// 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
236
	// ce n'est pas totalement optimal en terme de stockage, mais chaque image est associee a un fichier .src
237
	// qui contient la methode de reconstrucion (le filtre + les arguments d'appel) et les arguments different entre prive et public
238
	// la mise en commun du fichier image cree donc un bug et des problemes qui necessiteraient beaucoup de complexite de code
239
	// alors que ca concerne peu de site au final
240
	// la release de r23632+r23633+r23634 a provoque peu de remontee de bug attestant du peu de sites impactes
241
	$identifiant = $fichier;
242
243
	// cas general :
244
	// on a un dossier cache commun et un nom de fichier qui varie avec l'effet
245
	// cas particulier de reduire :
246
	// un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
247
	$cache = "cache-gd2";
248
	if (substr($effet, 0, 7) == 'reduire') {
249
		list(, $maxWidth, $maxHeight) = explode('-', $effet);
250
		list($destWidth, $destHeight) = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
251
		$ret['largeur_dest'] = $destWidth;
252
		$ret['hauteur_dest'] = $destHeight;
253
		$effet = "L{$destWidth}xH$destHeight";
254
		$cache = "cache-vignettes";
255
		$fichier_dest = basename($fichier_dest);
256
		if (($ret['largeur'] <= $maxWidth) && ($ret['hauteur'] <= $maxHeight)) {
257
			// on garde la terminaison initiale car image simplement copiee
258
			// et on postfixe son nom avec un md5 du path
259
			$terminaison_dest = $terminaison;
260
			$fichier_dest .= '-' . substr(md5("$identifiant"), 0, 5);
261
		} else {
262
			$fichier_dest .= '-' . substr(md5("$identifiant-$effet"), 0, 5);
263
		}
264
		$cache = sous_repertoire(_DIR_VAR, $cache);
265
		$cache = sous_repertoire($cache, $effet);
266
		# cherche un cache existant
267
		/*foreach (array('gif','jpg','png') as $fmt)
268
			if (@file_exists($cache . $fichier_dest . '.' . $fmt)) {
269
				$terminaison_dest = $fmt;
270
			}*/
271
	} else {
272
		$fichier_dest = md5("$identifiant-$effet");
273
		$cache = sous_repertoire(_DIR_VAR, $cache);
274
		$cache = sous_repertoire($cache, substr($fichier_dest, 0, 2));
275
		$fichier_dest = substr($fichier_dest, 2);
276
	}
277
278
	$fichier_dest = $cache . $fichier_dest . "." . $terminaison_dest;
279
280
	$GLOBALS["images_calculees"][] = $fichier_dest;
281
282
	$creer = true;
283
	// si recalcul des images demande, recalculer chaque image une fois
284
	if (defined('_VAR_IMAGES') and _VAR_IMAGES and !isset($images_recalcul[$fichier_dest])) {
285
		$images_recalcul[$fichier_dest] = true;
286
	} else {
287
		if (@file_exists($f = $fichier_dest)) {
288
			if (filemtime($f) >= $date_src) {
289
				$creer = false;
290
			}
291
		} else {
292
			if (@file_exists($f = "$fichier_dest.src")
293
				and lire_fichier($f, $valeurs)
294
				and $valeurs = unserialize($valeurs)
295
				and $valeurs["date"] >= $date_src
296
			) {
297
				$creer = false;
298
			}
299
		}
300
	}
301
	if ($creer) {
302
		if (!@file_exists($fichier)) {
303
			if (!@file_exists("$fichier.src")) {
304
				spip_log("Image absente : $fichier");
305
306
				return false;
307
			}
308
			# on reconstruit l'image source absente a partir de la chaine des .src
309
			reconstruire_image_intermediaire($fichier);
0 ignored issues
show
Bug introduced by
It seems like $fichier defined by $f on line 208 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...
310
		}
311
	}
312
313
	if ($creer) {
314
		spip_log("filtre image " . ($fonction_creation ? reset($fonction_creation) : '') . "[$effet] sur $fichier",
315
			"images" . _LOG_DEBUG);
316
	}
317
318
	$term_fonction = _image_trouver_extension_pertinente($fichier);
0 ignored issues
show
Bug introduced by
It seems like $fichier defined by $f on line 208 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...
319
	$ret["fonction_imagecreatefrom"] = "_imagecreatefrom" . $term_fonction;
320
	$ret["fichier"] = $fichier;
321
	$ret["fonction_image"] = "_image_image" . $terminaison_dest;
322
	$ret["fichier_dest"] = $fichier_dest;
323
	$ret["format_source"] = ($terminaison != 'jpeg' ? $terminaison : 'jpg');
324
	$ret["format_dest"] = $terminaison_dest;
325
	$ret["date_src"] = $date_src;
326
	$ret["creer"] = $creer;
327
	$ret["class"] = extraire_attribut($img, 'class');
328
	$ret["alt"] = extraire_attribut($img, 'alt');
329
	$ret["style"] = extraire_attribut($img, 'style');
330
	$ret["tag"] = $img;
331
	if ($fonction_creation) {
332
		$ret["reconstruction"] = $fonction_creation;
333
		# ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement 
334
		# cas de image_reduire qui finalement ne reduit pas l'image source
335
		# ca evite d'essayer de le creer au prochain hit si il n'est pas la
336
		#ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
337
	}
338
339
	$ret = pipeline('image_preparer_filtre', array(
340
			'args' => array(
341
				'img' => $img,
342
				'effet' => $effet,
343
				'forcer_format' => $forcer_format,
344
				'fonction_creation' => $fonction_creation,
345
				'find_in_path' => $find_in_path,
346
			),
347
			'data' => $ret
348
		)
349
	);
350
351
	// une globale pour le debug en cas de crash memoire
352
	$GLOBALS["derniere_image_calculee"] = $ret;
353
354
	// traiter le cas particulier des SVG : si le filtre n'a pas annonce explicitement qu'il savait faire, on delegue
355
	if ($term_fonction === 'svg') {
356
		if ($creer and !$support_svg) {
357
			process_image_svg_identite($ret);
358
			$ret['creer'] = false;
359
		}
360
	}
361
	else {
362
		if (!function_exists($ret["fonction_imagecreatefrom"])) {
363
			return false;
364
		}
365
	}
366
367
	return $ret;
368
}
369
370
/**
371
 * Retourne la terminaison d’un fichier image
372
 * @param string $path
373
 * @return string
374
 */
375
function _image_trouver_extension($path) {
376
	if (preg_match(",\.(gif|jpe?g|png|svg)($|[?]),i", $path, $regs)) {
377
		$terminaison = strtolower($regs[1]);
378
		return $terminaison;
379
	}
380
	return '';
381
}
382
383
/**
384
 * Tente de trouver le véritable type d’une image,
385
 * même si une image est d’extension .jpg alors que son contenu est autre chose (gif ou png)
386
 *
387
 * @param string $path
388
 * @return string Extension, dans le format attendu par les fonctions 'gd' ('jpeg' pour les .jpg par exemple)
389
 */
390
function _image_trouver_extension_pertinente($path) {
391
	$path = supprimer_timestamp($path);
392
	$terminaison = _image_trouver_extension($path);
393
	if ($terminaison == 'jpg') {
394
		$terminaison = 'jpeg';
395
	}
396
397
	if (!file_exists($path)) {
398
		return $terminaison;
399
	}
400
401
	if (!$info = @spip_getimagesize($path)) {
402
		return $terminaison;
403
	}
404
405
	if (isset($info['mime'])) {
406
		$mime = $info['mime'];
407
	}
408
	else {
409
		$mime = image_type_to_mime_type($info[2]);
410
	}
411
412
	switch (strtolower($mime)) {
413
		case 'image/png':
414
		case 'image/x-png':
415
			$_terminaison = 'png';
416
			break;
417
418
		case 'image/jpg':
419
		case 'image/jpeg':
420
		case 'image/pjpeg':
421
			$_terminaison = 'jpeg';
422
			break;
423
424
		case 'image/gif':
425
			$_terminaison = 'gif';
426
			break;
427
428
		case 'image/webp':
429
		case 'image/x-webp':
430
			$_terminaison = 'webp';
431
			break;
432
433
		case 'image/svg+xml':
434
			$_terminaison = 'svg';
435
			break;
436
437
		default:
438
			$_terminaison = '';
439
	}
440
	if ($_terminaison and $_terminaison !== $terminaison) {
441
		spip_log("Mauvaise extension du fichier : $path . Son type mime est : $mime", "images." . _LOG_INFO_IMPORTANTE);
442
		$terminaison = $_terminaison;
443
	}
444
	return $terminaison;
445
}
446
447
/**
448
 * Crée une image depuis un fichier ou une URL
449
 *
450
 * Utilise les fonctions spécifiques GD.
451
 *
452
 * @param string $filename
453
 *     Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg
454
 *     ou local/cache-vignettes/L180xH51/image.jpg).
455
 * @return ressource
456
 *     Une ressource de type Image GD.
457
 */
458 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...
459
	$img = @imagecreatefromjpeg($filename);
460
	if (!$img) {
461
		spip_log("Erreur lecture imagecreatefromjpeg $filename", _LOG_CRITIQUE);
462
		erreur_squelette("Erreur lecture imagecreatefromjpeg $filename");
463
		$img = imagecreate(10, 10);
464
	}
465
466
	return $img;
467
}
468
469
/**
470
 * Crée une image depuis un fichier ou une URL (au format png)
471
 *
472
 * Utilise les fonctions spécifiques GD.
473
 *
474
 * @param string $filename
475
 *     Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png
476
 *     ou local/cache-vignettes/L180xH51/image.png).
477
 * @return ressource
478
 *     Une ressource de type Image GD.
479
 */
480 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...
481
	$img = @imagecreatefrompng($filename);
482
	if (!$img) {
483
		spip_log("Erreur lecture imagecreatefrompng $filename", _LOG_CRITIQUE);
484
		erreur_squelette("Erreur lecture imagecreatefrompng $filename");
485
		$img = imagecreate(10, 10);
486
	}
487
488
	return $img;
489
}
490
491
/**
492
 * Crée une image depuis un fichier ou une URL (au format gif)
493
 *
494
 * Utilise les fonctions spécifiques GD.
495
 *
496
 * @param string $filename
497
 *     Le path vers l'image à traiter (par exemple : IMG/distant/gif/image.gif
498
 *     ou local/cache-vignettes/L180xH51/image.gif).
499
 * @return ressource
500
 *     Une ressource de type Image GD.
501
 */
502 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...
503
	$img = @imagecreatefromgif($filename);
504
	if (!$img) {
505
		spip_log("Erreur lecture imagecreatefromgif $filename", _LOG_CRITIQUE);
506
		erreur_squelette("Erreur lecture imagecreatefromgif $filename");
507
		$img = imagecreate(10, 10);
508
	}
509
510
	return $img;
511
}
512
513
/**
514
 * Affiche ou sauvegarde une image au format PNG
515
 *
516
 * Utilise les fonctions spécifiques GD.
517
 *
518
 * @param ressource $img
519
 *     Une ressource de type Image GD.
520
 * @param string $fichier
521
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
522
 * @return bool
523
 *
524
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
525
 *     - true si une image est bien retournée.
526
 */
527 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...
528
	if (!function_exists('imagepng')) {
529
		return false;
530
	}
531
	$tmp = $fichier . ".tmp";
532
	$ret = imagepng($img, $tmp);
533
	if (file_exists($tmp)) {
534
		$taille_test = getimagesize($tmp);
535
		if ($taille_test[0] < 1) {
536
			return false;
537
		}
538
539
		spip_unlink($fichier); // le fichier peut deja exister
540
		@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...
541
542
		return $ret;
543
	}
544
545
	return false;
546
}
547
548
/**
549
 * Affiche ou sauvegarde une image au format GIF
550
 *
551
 * Utilise les fonctions spécifiques GD.
552
 *
553
 * @param ressource $img
554
 *     Une ressource de type Image GD.
555
 * @param string $fichier
556
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.gif).
557
 * @return bool
558
 *
559
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
560
 *     - true si une image est bien retournée.
561
 */
562 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...
563
	if (!function_exists('imagegif')) {
564
		return false;
565
	}
566
	$tmp = $fichier . ".tmp";
567
	$ret = imagegif($img, $tmp);
568
	if (file_exists($tmp)) {
569
		$taille_test = getimagesize($tmp);
570
		if ($taille_test[0] < 1) {
571
			return false;
572
		}
573
574
		spip_unlink($fichier); // le fichier peut deja exister
575
		@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...
576
577
		return $ret;
578
	}
579
580
	return false;
581
}
582
583
/**
584
 * Affiche ou sauvegarde une image au format JPG
585
 *
586
 * Utilise les fonctions spécifiques GD.
587
 *
588
 * @param ressource $img
589
 *     Une ressource de type Image GD.
590
 * @param string $fichier
591
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
592
 * @param int $qualite
593
 *     Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
594
 *     fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
595
 *     valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
596
 *     mes_options.php).
597
 * @return bool
598
 *
599
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
600
 *     - true si une image est bien retournée.
601
 */
602
function _image_imagejpg($img, $fichier, $qualite = _IMG_GD_QUALITE) {
603
	if (!function_exists('imagejpeg')) {
604
		return false;
605
	}
606
	$tmp = $fichier . ".tmp";
607
608
	// Enable interlancing
609
	imageinterlace($img, true);
610
611
	$ret = imagejpeg($img, $tmp, $qualite);
612
613
	if (file_exists($tmp)) {
614
		$taille_test = getimagesize($tmp);
615
		if ($taille_test[0] < 1) {
616
			return false;
617
		}
618
619
		spip_unlink($fichier); // le fichier peut deja exister
620
		@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...
621
622
		return $ret;
623
	}
624
625
	return false;
626
}
627
628
/**
629
 * Crée un fichier-image au format ICO
630
 *
631
 * Utilise les fonctions de la classe phpthumb_functions.
632
 *
633
 * @uses phpthumb_functions::GD2ICOstring()
634
 *
635
 * @param ressource $img
636
 *     Une ressource de type Image GD.
637
 * @param string $fichier
638
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
639
 * @return bool
640
 *     true si le fichier a bien été créé ; false sinon.
641
 */
642
function _image_imageico($img, $fichier) {
643
	$gd_image_array = array($img);
644
645
	return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
646
}
647
648
649
/**
650
 * Sauvegarde une image au format SVG
651
 *
652
 * - N'UTILISE PAS GD -
653
 * C'est une fonction derogatoire pour faciliter le traitement des SVG
654
 *
655
 * @param string $img
656
 *     contenu du SVG ou chemin vers le SVG source (et c'est alors une copie)
657
 * @param string $fichier
658
 *     Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
659
 * @return bool
660
 *
661
 *     - false si l'image créée a une largeur nulle ou n'existe pas ;
662
 *     - true si une image est bien retournée.
663
 */
664
function _image_imagesvg($img, $fichier) {
665
666
	$tmp = $fichier . ".tmp";
667
	if (strpos($img, "<") === false) {
668
		$img = supprimer_timestamp($img);
669
		if (!file_exists($img)) {
670
			return false;
671
		}
672
		@copy($img, $tmp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
673
		if (filesize($tmp) == filesize($img)) {
674
			spip_unlink($fichier); // le fichier peut deja exister
675
			@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...
676
			return true;
677
		}
678
		return false;
679
	}
680
681
	file_put_contents($tmp, $img);
682
	if (file_exists($tmp)) {
683
		$taille_test = spip_getimagesize($tmp);
684
		if ($taille_test[0] < 1) {
685
			return false;
686
		}
687
688
		spip_unlink($fichier); // le fichier peut deja exister
689
		@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...
690
691
		return true;
692
	}
693
694
	return false;
695
}
696
697
698
/**
699
 * Finalise le traitement GD
700
 *
701
 * Crée un fichier_image temporaire .src ou vérifie que le fichier_image
702
 * définitif a bien été créé.
703
 *
704
 * @uses statut_effacer_images_temporaires()
705
 *
706
 * @param resource|string $img
707
 *     Une ressource de type Image GD (ou une string pour un SVG)
708
 * @param array $valeurs
709
 *     Un tableau des informations (tailles, traitement, path...) accompagnant
710
 *     l'image.
711
 * @param int $qualite
712
 *     N'est utilisé que pour les images jpg.
713
 *     Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
714
 *     fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
715
 *     valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
716
 *     mes_options.php).
717
 * @return bool
718
 *     - true si le traitement GD s'est bien finalisé ;
719
 *     - false sinon.
720
 */
721
function _image_gd_output($img, $valeurs, $qualite = _IMG_GD_QUALITE) {
722
	$fonction = "_image_image" . $valeurs['format_dest'];
723
	$ret = false;
724
	#un flag pour reperer les images gravees
725
	$lock =
726
		!statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
727
	or (@file_exists($valeurs['fichier_dest']) and !@file_exists($valeurs['fichier_dest'] . '.src'));
728
	if (
729
		function_exists($fonction)
730
		&& ($ret = $fonction($img, $valeurs['fichier_dest'], $qualite)) # on a reussi a creer l'image
731
		&& isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
732
		&& !$lock
733
	) {
734
		if (@file_exists($valeurs['fichier_dest'])) {
735
			// dans tous les cas mettre a jour la taille de l'image finale
736
			list($valeurs["hauteur_dest"], $valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']);
737
			$valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
738
			ecrire_fichier($valeurs['fichier_dest'] . '.src', serialize($valeurs), true);
739
		}
740
	}
741
742
	return $ret;
743
}
744
745
/**
746
 * Reconstruit une image à partir des sources de contrôle de son ancienne
747
 * construction
748
 *
749
 * @uses ramasse_miettes()
750
 *
751
 * @param string $fichier_manquant
752
 *     Chemin vers le fichier manquant
753
 **/
754
function reconstruire_image_intermediaire($fichier_manquant) {
755
	$reconstruire = array();
756
	$fichier = $fichier_manquant;
757
	while (strpos($fichier,"://")===false
758
		and !@file_exists($fichier)
759
		and lire_fichier($src = "$fichier.src", $source)
760
		and $valeurs = unserialize($source)
761
		and ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
762
	) {
763
		spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
764
		$reconstruire[] = $valeurs['reconstruction'];
765
	}
766
	while (count($reconstruire)) {
767
		$r = array_pop($reconstruire);
768
		$fonction = $r[0];
769
		$args = $r[1];
770
		call_user_func_array($fonction, $args);
771
	}
772
	// cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
773
	// mais l'on peut nettoyer les miettes de sa creation
774
	ramasse_miettes($fichier_manquant);
775
}
776
777
/**
778
 * Indique qu'un fichier d'image calculé est à conserver
779
 *
780
 * Permet de rendre une image définitive et de supprimer les images
781
 * intermédiaires à son calcul.
782
 *
783
 * Supprime le fichier de contrôle de l’image cible (le $fichier.src)
784
 * ce qui indique que l'image est définitive.
785
 *
786
 * Remonte ensuite la chaîne des fichiers de contrôle pour supprimer
787
 * les images temporaires (mais laisse les fichiers de contrôle permettant
788
 * de les reconstruire).
789
 *
790
 * @param string $fichier
791
 *     Chemin du fichier d'image calculé
792
 **/
793
function ramasse_miettes($fichier) {
794
	if (strpos($fichier,"://")!==false
795
		or !lire_fichier($src = "$fichier.src", $source)
796
		or !$valeurs = unserialize($source)
797
	) {
798
		return;
799
	}
800
	spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
801
	while (
802
		($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
803
		and (substr($fichier, 0, strlen(_DIR_VAR)) == _DIR_VAR) # et est dans local
804
		and (lire_fichier($src = "$fichier.src",
805
			$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire)
806
		and ($valeurs = unserialize($source))  # et valide
807
	) {
808
		# on efface le fichier
809
		spip_unlink($fichier);
810
		# mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
811
		#spip_unlink($src);
812
	}
813
}
814
815
816
/**
817
 * Clôture une série de filtres d'images
818
 *
819
 * Ce filtre est automatiquement appelé à la fin d'une série de filtres
820
 * d'images dans un squelette.
821
 *
822
 * @filtre
823
 * @uses reconstruire_image_intermediaire()
824
 *     Si l'image finale a déjà été supprimée car considérée comme temporaire
825
 *     par une autre série de filtres images débutant pareil
826
 * @uses ramasse_miettes()
827
 *     Pour déclarer l'image définitive et nettoyer les images intermédiaires.
828
 *
829
 * @pipeline_appel post_image_filtrer
830
 *
831
 * @param string $img
832
 *     Code HTML de l'image
833
 * @return string
834
 *     Code HTML de l'image
835
 **/
836
function image_graver($img) {
837
	// appeler le filtre post_image_filtrer qui permet de faire
838
	// des traitements auto a la fin d'une serie de filtres
839
	$img = pipeline('post_image_filtrer', $img);
840
841
	$fichier_ori = $fichier = extraire_attribut($img, 'src');
842 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...
843
		$fichier = substr($fichier, 0, $p);
844
	}
845
	if (strlen($fichier) < 1) {
846
		$fichier = $img;
847
	}
848
	# si jamais le fichier final n'a pas ete calcule car suppose temporaire
849
	# et qu'il ne s'agit pas d'une URL
850
	if (strpos($fichier,"://")===false and !@file_exists($fichier)) {
851
		reconstruire_image_intermediaire($fichier);
852
	}
853
	ramasse_miettes($fichier);
854
855
	// ajouter le timestamp si besoin
856
	if (strpos($fichier_ori, "?") === false) {
857
		// on utilise str_replace pour attraper le onmouseover des logo si besoin
858
		$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 841 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...
859
	}
860
861
	return $img;
862
}
863
864
865
if (!function_exists("imagepalettetotruecolor")) {
866
	/**
867
	 * Transforme une image à palette indexée (256 couleurs max) en "vraies" couleurs RGB
868
	 *
869
	 * @note Pour compatibilité avec PHP < 5.5
870
	 *
871
	 * @link http://php.net/manual/fr/function.imagepalettetotruecolor.php
872
	 *
873
	 * @param ressource $img
874
	 * @return bool
875
	 *     - true si l'image est déjà en vrai RGB ou peut être transformée
876
	 *     - false si la transformation ne peut être faite.
877
	 **/
878
	function imagepalettetotruecolor(&$img) {
879
		if (!$img or !function_exists('imagecreatetruecolor')) {
880
			return false;
881
		} elseif (!imageistruecolor($img)) {
882
			$w = imagesx($img);
883
			$h = imagesy($img);
884
			$img1 = imagecreatetruecolor($w, $h);
885
			//Conserver la transparence si possible
886
			if (function_exists('ImageCopyResampled')) {
887
				if (function_exists("imageAntiAlias")) {
888
					imageAntiAlias($img1, true);
889
				}
890
				@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...
891
				@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...
892
				@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...
893
			} else {
894
				imagecopy($img1, $img, 0, 0, 0, 0, $w, $h);
895
			}
896
897
			$img = $img1;
898
		}
899
900
		return true;
901
	}
902
}
903
904
/**
905
 * Applique des attributs de taille (width, height) à une balise HTML
906
 *
907
 * Utilisé avec des balises `<img>` tout particulièrement.
908
 *
909
 * Modifie l'attribut style s'il était renseigné, en enlevant les
910
 * informations éventuelles width / height dedans.
911
 *
912
 * @uses extraire_attribut()
913
 * @uses inserer_attribut()
914
 *
915
 * @param string $tag
916
 *     Code html de la balise
917
 * @param int $width
918
 *     Hauteur
919
 * @param int $height
920
 *     Largeur
921
 * @param bool|string $style
922
 *     Attribut html style à appliquer.
923
 *     False extrait celui présent dans la balise
924
 * @return string
925
 *     Code html modifié de la balise.
926
 **/
927
function _image_tag_changer_taille($tag, $width, $height, $style = false) {
928
	if ($style === false) {
929
		$style = extraire_attribut($tag, 'style');
930
	}
931
932
	// enlever le width et height du style
933
	$style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims", "", $style);
934
	if ($style and $style{0} == ';') {
935
		$style = substr($style, 1);
936
	}
937
938
	// mettre des attributs de width et height sur les images, 
939
	// ca accelere le rendu du navigateur
940
	// ca permet aux navigateurs de reserver la bonne taille 
941
	// quand on a desactive l'affichage des images.
942
	$tag = inserer_attribut($tag, 'width', round($width));
943
	$tag = inserer_attribut($tag, 'height', round($height));
944
945
	// attributs deprecies. Transformer en CSS
946
	if ($espace = extraire_attribut($tag, 'hspace')) {
947
		$style = "margin:${espace}px;" . $style;
948
		$tag = inserer_attribut($tag, 'hspace', '');
949
	}
950
951
	$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 933 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...
952
953
	return $tag;
954
}
955
956
957
/**
958
 * Écriture de la balise img en sortie de filtre image
959
 *
960
 * Reprend le tag initial et surcharge les attributs modifiés
961
 *
962
 * @pipeline_appel image_ecrire_tag_preparer
963
 * @pipeline_appel image_ecrire_tag_finir
964
 *
965
 * @uses _image_tag_changer_taille()
966
 * @uses extraire_attribut()
967
 * @uses inserer_attribut()
968
 * @see  _image_valeurs_trans()
969
 *
970
 * @param array $valeurs
971
 *     Description de l'image tel que retourné par `_image_valeurs_trans()`
972
 * @param array $surcharge
973
 *     Permet de surcharger certaines descriptions présentes dans `$valeurs`
974
 *     tel que 'style', 'width', 'height'
975
 * @return string
976
 *     Retourne le code HTML de l'image
977
 **/
978
function _image_ecrire_tag($valeurs, $surcharge = array()) {
979
	$valeurs = pipeline('image_ecrire_tag_preparer', $valeurs);
980
981
	// fermer les tags img pas bien fermes;
982
	$tag = str_replace(">", "/>", str_replace("/>", ">", $valeurs['tag']));
983
984
	// le style
985
	$style = $valeurs['style'];
986
	if (isset($surcharge['style'])) {
987
		$style = $surcharge['style'];
988
		unset($surcharge['style']);
989
	}
990
991
	// traiter specifiquement la largeur et la hauteur
992
	$width = $valeurs['largeur'];
993
	if (isset($surcharge['width'])) {
994
		$width = $surcharge['width'];
995
		unset($surcharge['width']);
996
	}
997
	$height = $valeurs['hauteur'];
998
	if (isset($surcharge['height'])) {
999
		$height = $surcharge['height'];
1000
		unset($surcharge['height']);
1001
	}
1002
1003
	$tag = _image_tag_changer_taille($tag, $width, $height, $style);
1004
	// traiter specifiquement le src qui peut etre repris dans un onmouseout
1005
	// on remplace toute les ref a src dans le tag
1006
	$src = extraire_attribut($tag, 'src');
1007
	if (isset($surcharge['src'])) {
1008
		$tag = str_replace($src, $surcharge['src'], $tag);
1009
		// si il y a des & dans src, alors ils peuvent provenir d'un &amp
1010
		// pas garanti comme methode, mais mieux que rien
1011
		if (strpos($src, '&') !== false) {
1012
			$tag = str_replace(str_replace("&", "&amp;", $src), $surcharge['src'], $tag);
1013
		}
1014
		$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...
1015
		unset($surcharge['src']);
1016
	}
1017
1018
	$class = $valeurs['class'];
1019
	if (isset($surcharge['class'])) {
1020
		$class = $surcharge['class'];
1021
		unset($surcharge['class']);
1022
	}
1023
	if (strlen($class)) {
1024
		$tag = inserer_attribut($tag, 'class', $class);
1025
	}
1026
1027
	if (count($surcharge)) {
1028
		foreach ($surcharge as $attribut => $valeur) {
1029
			$tag = inserer_attribut($tag, $attribut, $valeur);
1030
		}
1031
	}
1032
1033
	$tag = pipeline('image_ecrire_tag_finir',
1034
		array(
1035
			'args' => array(
1036
				'valeurs' => $valeurs,
1037
				'surcharge' => $surcharge,
1038
			),
1039
			'data' => $tag
1040
		)
1041
	);
1042
1043
	return $tag;
1044
}
1045
1046
/**
1047
 * Crée si possible une miniature d'une image
1048
 *
1049
 * @see  _image_valeurs_trans()
1050
 * @uses _image_ratio()
1051
 *
1052
 * @param array $valeurs
1053
 *     Description de l'image, telle que retournée par `_image_valeurs_trans()`
1054
 * @param int $maxWidth
1055
 *     Largeur maximum en px de la miniature à réaliser
1056
 * @param int $maxHeight
1057
 *     Hauteur maximum en px de la miniateure à réaliser
1058
 * @param string $process
1059
 *     Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
1060
 *     AUTO utilise la librairie sélectionnée dans la configuration.
1061
 * @param bool $force
1062
 * @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...
1063
 *     Description de l'image, sinon null.
1064
 **/
1065
function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process = 'AUTO', $force = false) {
1066
	// ordre de preference des formats graphiques pour creer les vignettes
1067
	// le premier format disponible, selon la methode demandee, est utilise
1068
	$image = $valeurs['fichier'];
1069
	$format = $valeurs['format_source'];
1070
	$destdir = dirname($valeurs['fichier_dest']);
1071
	$destfile = basename($valeurs['fichier_dest'], "." . $valeurs["format_dest"]);
1072
1073
	$format_sortie = $valeurs['format_dest'];
1074
1075 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...
1076
		$process = $GLOBALS['meta']['image_process'];
1077
	}
1078
1079
	// si le doc n'est pas une image, refuser
1080
	if (!$force and !in_array($format, formats_image_acceptables())) {
1081
		return;
1082
	}
1083
	$destination = "$destdir/$destfile";
1084
1085
	// calculer la taille
1086
	if (($srcWidth = $valeurs['largeur']) && ($srcHeight = $valeurs['hauteur'])) {
1087
		if (!($destWidth = $valeurs['largeur_dest']) || !($destHeight = $valeurs['hauteur_dest'])) {
1088
			list($destWidth, $destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight);
1089
		}
1090
	} elseif ($process == 'convert' or $process == 'imagick') {
1091
		$destWidth = $maxWidth;
1092
		$destHeight = $maxHeight;
1093
	} else {
1094
		spip_log("echec $process sur $image");
1095
1096
		return;
1097
	}
1098
1099
	// Si l'image est de la taille demandee (ou plus petite), simplement la retourner
1100
	if ($srcWidth and $srcWidth <= $maxWidth and $srcHeight <= $maxHeight) {
1101
		$vignette = $destination . '.' . $format;
1102
		@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...
1103
	}
1104
1105
	elseif ($valeurs["format_source"] === 'svg') {
1106
		if ($svg = svg_redimensionner($valeurs['fichier'], $destWidth, $destHeight)){
1107
			$format_sortie = 'svg';
1108
			$vignette = $destination . "." . $format_sortie;
1109
			$valeurs['fichier_dest'] = $vignette;
1110
			_image_gd_output($svg, $valeurs);
0 ignored issues
show
Bug introduced by
It seems like $svg defined by svg_redimensionner($vale...destWidth, $destHeight) on line 1106 can also be of type boolean; however, _image_gd_output() does only seem to accept resource|string, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
1111
		}
1112
	}
1113
1114
	// imagemagick en ligne de commande
1115
	elseif ($process == 'convert') {
1116
		if (!defined('_CONVERT_COMMAND')) {
1117
			define('_CONVERT_COMMAND', 'convert');
1118
		} // Securite : mes_options.php peut preciser le chemin absolu
1119
		if (!defined('_RESIZE_COMMAND')) {
1120
			define('_RESIZE_COMMAND', _CONVERT_COMMAND . ' -quality ' . _IMG_CONVERT_QUALITE . ' -resize %xx%y! %src %dest');
1121
		}
1122
		$vignette = $destination . "." . $format_sortie;
1123
		$commande = str_replace(
1124
			array('%x', '%y', '%src', '%dest'),
1125
			array(
1126
				$destWidth,
1127
				$destHeight,
1128
				escapeshellcmd($image),
1129
				escapeshellcmd($vignette)
1130
			),
1131
			_RESIZE_COMMAND);
1132
		spip_log($commande);
1133
		exec($commande);
1134
		if (!@file_exists($vignette)) {
1135
			spip_log("echec convert sur $vignette");
1136
1137
			return;  // echec commande
1138
		}
1139
	}
1140
1141
	// php5 imagemagick
1142
	elseif ($process == 'imagick') {
1143
		$vignette = "$destination." . $format_sortie;
1144
1145
		if (!class_exists('Imagick')) {
1146
			spip_log("Classe Imagick absente !", _LOG_ERREUR);
1147
1148
			return;
1149
		}
1150
		$imagick = new Imagick();
1151
		$imagick->readImage($image);
1152
		$imagick->resizeImage($destWidth, $destHeight, Imagick::FILTER_LANCZOS,
1153
			1);//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100);
1154
		$imagick->writeImage($vignette);
1155
1156
		if (!@file_exists($vignette)) {
1157
			spip_log("echec imagick sur $vignette");
1158
1159
			return;
1160
		}
1161
	}
1162
1163
	// netpbm
1164
	elseif ($process == "netpbm") {
1165
		if (!defined('_PNMSCALE_COMMAND')) {
1166
			define('_PNMSCALE_COMMAND', 'pnmscale');
1167
		} // Securite : mes_options.php peut preciser le chemin absolu
1168
		if (_PNMSCALE_COMMAND == '') {
1169
			return;
1170
		}
1171
		$vignette = $destination . "." . $format_sortie;
1172
		$pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND);
1173
		if ($format == "jpg") {
1174
1175
			$jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND);
1176
			exec("$jpegtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1177
			if (!($s = @filesize($vignette))) {
1178
				spip_unlink($vignette);
1179
			}
1180
			if (!@file_exists($vignette)) {
1181
				spip_log("echec netpbm-jpg sur $vignette");
1182
1183
				return;
1184
			}
1185
		} else {
1186
			if ($format == "gif") {
1187
				$giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND);
1188
				exec("$giftopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1189
				if (!($s = @filesize($vignette))) {
1190
					spip_unlink($vignette);
1191
				}
1192
				if (!@file_exists($vignette)) {
1193
					spip_log("echec netpbm-gif sur $vignette");
1194
1195
					return;
1196
				}
1197
			} else {
1198
				if ($format == "png") {
1199
					$pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND);
1200
					exec("$pngtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette");
1201
					if (!($s = @filesize($vignette))) {
1202
						spip_unlink($vignette);
1203
					}
1204
					if (!@file_exists($vignette)) {
1205
						spip_log("echec netpbm-png sur $vignette");
1206
1207
						return;
1208
					}
1209
				}
1210
			}
1211
		}
1212
	}
1213
1214
	// gd ou gd2
1215
	elseif ($process == 'gd1' or $process == 'gd2') {
1216
		if (!function_exists('gd_info')) {
1217
			spip_log("Librairie GD absente !", _LOG_ERREUR);
1218
1219
			return;
1220
		}
1221
		if (_IMG_GD_MAX_PIXELS && $srcWidth * $srcHeight > _IMG_GD_MAX_PIXELS) {
1222
			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...
1223
1224
			return;
1225
		}
1226
		$destFormat = $format_sortie;
1227
		if (!$destFormat) {
1228
			spip_log("pas de format pour $image");
1229
1230
			return;
1231
		}
1232
1233
		$fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
1234
		if (!function_exists($fonction_imagecreatefrom)) {
1235
			return '';
1236
		}
1237
		$srcImage = @$fonction_imagecreatefrom($image);
1238
		if (!$srcImage) {
1239
			spip_log("echec gd1/gd2");
1240
1241
			return;
1242
		}
1243
1244
		// Initialisation de l'image destination
1245
		$destImage = null;
1246
		if ($process == 'gd2' and $destFormat != "gif") {
1247
			$destImage = ImageCreateTrueColor($destWidth, $destHeight);
1248
		}
1249
		if (!$destImage) {
1250
			$destImage = ImageCreate($destWidth, $destHeight);
1251
		}
1252
1253
		// Recopie de l'image d'origine avec adaptation de la taille 
1254
		$ok = false;
1255
		if (($process == 'gd2') and function_exists('ImageCopyResampled')) {
1256
			if ($format == "gif") {
1257
				// Si un GIF est transparent, 
1258
				// fabriquer un PNG transparent  
1259
				$transp = imagecolortransparent($srcImage);
1260
				if ($transp > 0) {
1261
					$destFormat = "png";
1262
				}
1263
			}
1264
			if ($destFormat == "png") {
1265
				// Conserver la transparence 
1266
				if (function_exists("imageAntiAlias")) {
1267
					imageAntiAlias($destImage, true);
1268
				}
1269
				@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...
1270
				@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...
1271
			}
1272
			$ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
1273
		}
1274
		if (!$ok) {
1275
			$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...
1276
		}
1277
1278
		// Sauvegarde de l'image destination
1279
		$valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
1280
		$valeurs['format_dest'] = $format = $destFormat;
1281
		_image_gd_output($destImage, $valeurs);
1282
1283
		if ($srcImage) {
1284
			ImageDestroy($srcImage);
1285
		}
1286
		ImageDestroy($destImage);
1287
	}
1288
1289
	$size = @spip_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...
1290
	// Gaffe: en safe mode, pas d'acces a la vignette,
1291
	// donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
1292
	if ($size[0] < 1) {
1293
		$size[0] = $destWidth;
1294
	}
1295
	if ($size[1] < 1) {
1296
		$size[1] = $destHeight;
1297
	}
1298
1299
	$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...
1300
	$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...
1301
1302
	$retour['fichier'] = $vignette;
1303
	$retour['format'] = $format;
1304
	$retour['date'] = @filemtime($vignette);
1305
1306
	// renvoyer l'image
1307
	return $retour;
1308
}
1309
1310
/**
1311
 * Réduire des dimensions en respectant un ratio
1312
 *
1313
 * Réduit des dimensions (hauteur, largeur) pour qu'elles
1314
 * soient incluses dans une hauteur et largeur maximum fournies
1315
 * en respectant la proportion d'origine
1316
 *
1317
 * @example `image_ratio(1000, 1000, 100, 10)` donne `array(10, 10, 100)`
1318
 * @see ratio_passe_partout() Assez proche.
1319
 *
1320
 * @param int $srcWidth Largeur de l'image source
1321
 * @param int $srcHeight Hauteur de l'image source
1322
 * @param int $maxWidth Largeur maximum souhaitée
1323
 * @param int $maxHeight Hauteur maximum souhaitée
1324
 * @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...
1325
 **/
1326 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...
1327
	$ratioWidth = $srcWidth / $maxWidth;
1328
	$ratioHeight = $srcHeight / $maxHeight;
1329
1330
	if ($ratioWidth <= 1 and $ratioHeight <= 1) {
1331
		$destWidth = $srcWidth;
1332
		$destHeight = $srcHeight;
1333
	} elseif ($ratioWidth < $ratioHeight) {
1334
		$destWidth = $srcWidth / $ratioHeight;
1335
		$destHeight = $maxHeight;
1336
	} else {
1337
		$destWidth = $maxWidth;
1338
		$destHeight = $srcHeight / $ratioWidth;
1339
	}
1340
1341
	return array(
1342
		ceil($destWidth),
1343
		ceil($destHeight),
1344
		max($ratioWidth, $ratioHeight)
1345
	);
1346
}
1347
1348
/**
1349
 * Réduire des dimensions en respectant un ratio sur la plus petite dimension
1350
 *
1351
 * Réduit des dimensions (hauteur, largeur) pour qu'elles
1352
 * soient incluses dans la plus grande hauteur ou largeur maximum fournie
1353
 * en respectant la proportion d'origine
1354
 *
1355
 * @example `ratio_passe_partout(1000, 1000, 100, 10)` donne `array(100, 100, 10)`
1356
 * @see _image_ratio() Assez proche.
1357
 *
1358
 * @param int $srcWidth Largeur de l'image source
1359
 * @param int $srcHeight Hauteur de l'image source
1360
 * @param int $maxWidth Largeur maximum souhaitée
1361
 * @param int $maxHeight Hauteur maximum souhaitée
1362
 * @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...
1363
 **/
1364 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...
1365
	$ratioWidth = $srcWidth / $maxWidth;
1366
	$ratioHeight = $srcHeight / $maxHeight;
1367
1368
	if ($ratioWidth <= 1 and $ratioHeight <= 1) {
1369
		$destWidth = $srcWidth;
1370
		$destHeight = $srcHeight;
1371
	} elseif ($ratioWidth > $ratioHeight) {
1372
		$destWidth = $srcWidth / $ratioHeight;
1373
		$destHeight = $maxHeight;
1374
	} else {
1375
		$destWidth = $maxWidth;
1376
		$destHeight = $srcHeight / $ratioWidth;
1377
	}
1378
1379
	return array(
1380
		ceil($destWidth),
1381
		ceil($destHeight),
1382
		min($ratioWidth, $ratioHeight)
1383
	);
1384
}
1385
1386
1387
/**
1388
 * Fonction identite de traitement par defaut des images SVG
1389
 * (quand un filtre n'annonce pas qu'il sait traiter un SVG on applique cette fonction a la place)
1390
 *
1391
 * @param array $image
1392
 *   tableau des valeurs crees par _image_valeurs_trans
1393
 * @return string
1394
 */
1395
function process_image_svg_identite($image) {
1396
	if ($image['creer']) {
1397
		$source = $image['fichier'];
1398
		_image_gd_output($source, $image);
1399
	}
1400
1401
	return _image_ecrire_tag($image, array('src' => $image['fichier_dest']));
1402
}
1403
1404
1405
/**
1406
 * Réduit une image
1407
 *
1408
 * @uses extraire_attribut()
1409
 * @uses inserer_attribut()
1410
 * @uses _image_valeurs_trans()
1411
 * @uses _image_ratio()
1412
 * @uses _image_tag_changer_taille()
1413
 * @uses _image_ecrire_tag()
1414
 * @uses _image_creer_vignette()
1415
 *
1416
 * @param array $fonction
1417
 *     Un tableau à 2 éléments :
1418
 *     1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ;
1419
 *     2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé.
1420
 * @param string $img
1421
 *     Chemin de l'image ou texte contenant une balise img
1422
 * @param int $taille
1423
 *     Largeur désirée
1424
 * @param int $taille_y
1425
 *     Hauteur désirée
1426
 * @param bool $force
1427
 * @param string $process
1428
 *     Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
1429
 *     AUTO utilise la librairie sélectionnée dans la configuration.
1430
 * @return string
1431
 *     Code HTML de la balise img produite
1432
 **/
1433
function process_image_reduire($fonction, $img, $taille, $taille_y, $force, $process = 'AUTO') {
1434
	$image = false;
1435 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...
1436
		$process = $GLOBALS['meta']['image_process'];
1437
	}
1438
	# determiner le format de sortie
1439
	$format_sortie = false; // le choix par defaut sera bon
1440
	if ($process == "netpbm") {
1441
		$format_sortie = "jpg";
1442
	} elseif ($process == 'gd1' or $process == 'gd2') {
1443
		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1444
1445
		// on verifie que l'extension choisie est bonne (en principe oui)
1446
		$gd_formats = formats_image_acceptables(true);
1447
		if (is_array($image)
1448
			and (!in_array($image['format_dest'], $gd_formats)
1449
				or ($image['format_dest'] == 'gif' and !function_exists('ImageGif'))
1450
			)
1451
		) {
1452
			if ($image['format_source'] == 'jpg') {
1453
				$formats_sortie = array('jpg', 'png', 'gif');
1454
			} else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
1455
			{
1456
				$formats_sortie = array('png', 'jpg', 'gif');
1457
			}
1458
			// Choisir le format destination
1459
			// - on sauve de preference en JPEG (meilleure compression)
1460
			// - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
1461
			# bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
1462
			# pas *ecrire*
1463
			$format_sortie = "";
1464
			foreach ($formats_sortie as $fmt) {
1465
				if (in_array($fmt, $gd_formats)) {
1466
					if ($fmt <> "gif" or function_exists('ImageGif')) {
1467
						$format_sortie = $fmt;
1468
					}
1469
					break;
1470
				}
1471
			}
1472
			$image = false;
1473
		}
1474
	}
1475
1476
	if (!is_array($image)) {
1477
		$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED);
1478
	}
1479
1480
	if (!is_array($image) or !$image['largeur'] or !$image['hauteur']) {
1481
		spip_log("image_reduire_src:pas de version locale de $img");
1482
		// on peut resizer en mode html si on dispose des elements
1483
		if ($srcw = extraire_attribut($img, 'width')
1484
			and $srch = extraire_attribut($img, 'height')
1485
		) {
1486
			list($w, $h) = _image_ratio($srcw, $srch, $taille, $taille_y);
1487
1488
			return _image_tag_changer_taille($img, $w, $h);
1489
		}
1490
		// la on n'a pas d'infos sur l'image source... on refile le truc a css
1491
		// sous la forme style='max-width: NNpx;'
1492
		return inserer_attribut($img, 'style',
1493
			"max-width: ${taille}px; max-height: ${taille_y}px");
1494
	}
1495
1496
	// si l'image est plus petite que la cible retourner une copie cachee de l'image
1497
	if (($image['largeur'] <= $taille) && ($image['hauteur'] <= $taille_y)) {
1498
		if ($image['creer']) {
1499
			@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...
1500
		}
1501
1502
		return _image_ecrire_tag($image, array('src' => $image['fichier_dest']));
1503
	}
1504
1505
	if ($image['creer'] == false && !$force) {
1506
		return _image_ecrire_tag($image,
1507
			array('src' => $image['fichier_dest'], 'width' => $image['largeur_dest'], 'height' => $image['hauteur_dest']));
1508
	}
1509
1510
	if (in_array($image["format_source"], formats_image_acceptables())) {
1511
		$destWidth = $image['largeur_dest'];
1512
		$destHeight = $image['hauteur_dest'];
1513
		$logo = $image['fichier'];
1514
		$date = $image["date_src"];
1515
		$preview = _image_creer_vignette($image, $taille, $taille_y, $process, $force);
1516
1517
		if ($preview && $preview['fichier']) {
1518
			$logo = $preview['fichier'];
1519
			$destWidth = $preview['width'];
1520
			$destHeight = $preview['height'];
1521
			$date = $preview['date'];
1522
		}
1523
		// dans l'espace prive mettre un timestamp sur l'adresse 
1524
		// de l'image, de facon a tromper le cache du navigateur
1525
		// quand on fait supprimer/reuploader un logo
1526
		// (pas de filemtime si SAFE MODE)
1527
		$date = test_espace_prive() ? ('?' . $date) : '';
1528
1529
		return _image_ecrire_tag($image, array('src' => "$logo$date", 'width' => $destWidth, 'height' => $destHeight));
1530
	}
1531
	else {
1532
		# BMP, tiff ... les redacteurs osent tout!
1533
		return $img;
1534
	}
1535
}
1536
1537
/**
1538
 * Produire des fichiers au format .ico
1539
 *
1540
 * Avec du code récupéré de phpThumb()
1541
 *
1542
 * @author James Heinrich <[email protected]>
1543
 * @link http://phpthumb.sourceforge.net
1544
 *
1545
 * Class phpthumb_functions
1546
 */
1547
class phpthumb_functions {
1548
1549
	/**
1550
	 * Retourne la couleur d'un pixel dans une image
1551
	 *
1552
	 * @param ressource $img
1553
	 * @param int $x
1554
	 * @param int $y
1555
	 * @return array|bool
1556
	 */
1557
	public static function GetPixelColor(&$img, $x, $y) {
1558
		if (!is_resource($img)) {
1559
			return false;
1560
		}
1561
1562
		return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
1563
	}
1564
1565
	/**
1566
	 * Retourne un nombre dans une représentation en Little Endian
1567
	 *
1568
	 * @param int $number
1569
	 * @param int $minbytes
1570
	 * @return string
1571
	 */
1572
	public static function LittleEndian2String($number, $minbytes = 1) {
1573
		$intstring = '';
1574
		while ($number > 0) {
1575
			$intstring = $intstring . chr($number & 255);
1576
			$number >>= 8;
1577
		}
1578
1579
		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
1580
	}
1581
1582
	/**
1583
	 * Transforme une ressource GD en image au format ICO
1584
	 *
1585
	 * @param array $gd_image_array
1586
	 *     Tableau de ressources d'images GD
1587
	 * @return string
1588
	 *     Image au format ICO
1589
	 */
1590
	public static function GD2ICOstring(&$gd_image_array) {
1591
		foreach ($gd_image_array as $key => $gd_image) {
1592
1593
			$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...
1594
			$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...
1595
			$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...
1596
			$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...
1597
1598
			$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...
1599
			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...
1600
				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...
1601
					$argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
1602
					$a = round(255 * ((127 - $argb['alpha']) / 127));
1603
					$r = $argb['red'];
1604
					$g = $argb['green'];
1605
					$b = $argb['blue'];
1606
1607
					if ($bpp[$key] == 32) {
1608
						$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...
1609
					} 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...
1610
						$icXOR[$key] .= chr($b) . chr($g) . chr($r);
1611
					}
1612
1613
					if ($a < 128) {
1614
						@$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...
1615
					} else {
1616
						@$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...
1617
					}
1618
				}
1619
				// mask bits are 32-bit aligned per scanline
1620
				while (strlen($icANDmask[$key][$y]) % 32) {
1621
					$icANDmask[$key][$y] .= '0';
1622
				}
1623
			}
1624
			$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...
1625
			foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
1626
				for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
1627
					$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...
1628
				}
1629
			}
1630
1631
		}
1632
1633
		foreach ($gd_image_array as $key => $gd_image) {
1634
			$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
1635
1636
			// BITMAPINFOHEADER - 40 bytes
1637
			$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...
1638
			$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";                // DWORD  biSize;
1639
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);    // LONG   biWidth;
1640
			// The biHeight member specifies the combined
1641
			// height of the XOR and AND masks.
1642
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
1643
			$BitmapInfoHeader[$key] .= "\x01\x00";                    // WORD   biPlanes;
1644
			$BitmapInfoHeader[$key] .= chr($bpp[$key]) . "\x00";              // wBitCount;
1645
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biCompression;
1646
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);      // DWORD  biSizeImage;
1647
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biXPelsPerMeter;
1648
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // LONG   biYPelsPerMeter;
1649
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrUsed;
1650
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                // DWORD  biClrImportant;
1651
		}
1652
1653
1654
		$icondata = "\x00\x00";                    // idReserved;   // Reserved (must be 0)
1655
		$icondata .= "\x01\x00";                    // idType;	   // Resource Type (1 for icons)
1656
		$icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2);  // idCount;	  // How many images?
1657
1658
		$dwImageOffset = 6 + (count($gd_image_array) * 16);
1659
		foreach ($gd_image_array as $key => $gd_image) {
1660
			// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
1661
1662
			$icondata .= chr($ImageWidths[$key]);           // bWidth;		  // Width, in pixels, of the image
1663
			$icondata .= chr($ImageHeights[$key]);          // bHeight;		 // Height, in pixels, of the image
1664
			$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...
1665
			$icondata .= "\x00";                    // bReserved;	   // Reserved ( must be 0)
1666
1667
			$icondata .= "\x01\x00";                  // wPlanes;		 // Color Planes
1668
			$icondata .= chr($bpp[$key]) . "\x00";            // wBitCount;	   // Bits per pixel
1669
1670
			$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
1671
			$icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes,
1672
				4);     // dwBytesInRes;	// How many bytes in this resource?
1673
1674
			$icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset,
1675
				4);    // dwImageOffset;   // Where in the file is this image?
1676
			$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...
1677
			$dwImageOffset += strlen($icXOR[$key]);
1678
			$dwImageOffset += strlen($icAND[$key]);
1679
		}
1680
1681
		foreach ($gd_image_array as $key => $gd_image) {
1682
			$icondata .= $BitmapInfoHeader[$key];
1683
			$icondata .= $icXOR[$key];
1684
			$icondata .= $icAND[$key];
1685
		}
1686
1687
		return $icondata;
1688
	}
1689
1690
}
1691