Completed
Push — master ( 1c0099...508762 )
by cam
05:21
created

assembler.php ➔ arguments_balise_dyn_depuis_modele()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 2
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
/***************************************************************************\
4
 *  SPIP, Système de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright © avec tendresse depuis 2001                                 *
7
 *  Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James  *
8
 *                                                                         *
9
 *  Ce programme est un logiciel libre distribué sous licence GNU/GPL.     *
10
 *  Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne.   *
11
\***************************************************************************/
12
13
/**
14
 * Ce fichier regroupe les fonctions permettant de calculer la page et les entêtes
15
 *
16
 * Determine le contexte donne par l'URL (en tenant compte des reecritures)
17
 * grace a la fonction de passage d'URL a id (reciproque dans urls/*php)
18
 *
19
 * @package SPIP\Core\Compilateur\Assembler
20
 **/
21
22
if (!defined('_ECRIRE_INC_VERSION')) {
23
	return;
24
}
25
26
// En cas de modification, il faut aussi actualiser la regexp de nettoyer_uri_var() dans inc/utils.php
27
if (!defined('_CONTEXTE_IGNORE_VARIABLES')) {
28
	define('_CONTEXTE_IGNORE_VARIABLES', "/(^var_|^PHPSESSID$|^fbclid$|^utm_)/");
29
}
30
31
// https://code.spip.net/@assembler
32
function assembler($fond, $connect = '') {
33
34
	// flag_preserver est modifie ici, et utilise en globale
35
	// use_cache sert a informer le bouton d'admin pr savoir s'il met un *
36
	// contexte est utilise en globale dans le formulaire d'admin
37
38
	$GLOBALS['contexte'] = calculer_contexte();
39
	$page = array('contexte_implicite' => calculer_contexte_implicite());
40
	$page['contexte_implicite']['cache'] = $fond . preg_replace(',\.[a-zA-Z0-9]*$,', '',
41
			preg_replace('/[?].*$/', '', $GLOBALS['REQUEST_URI']));
42
	// Cette fonction est utilisee deux fois
43
	$cacher = charger_fonction('cacher', 'public', true);
44
	// Les quatre derniers parametres sont modifies par la fonction:
45
	// emplacement, validite, et, s'il est valide, contenu & age
46
	if ($cacher) {
47
		$res = $cacher($GLOBALS['contexte'], $GLOBALS['use_cache'], $chemin_cache, $page, $lastmodified);
0 ignored issues
show
Bug introduced by
The variable $chemin_cache 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...
Bug introduced by
The variable $lastmodified seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
48
	} else {
49
		$GLOBALS['use_cache'] = -1;
50
	}
51
	// Si un resultat est retourne, c'est un message d'impossibilite
52
	if ($res) {
53
		return array('texte' => $res);
0 ignored issues
show
Bug introduced by
The variable $res 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...
54
	}
55
56
	if (!$chemin_cache || !$lastmodified) {
0 ignored issues
show
Bug introduced by
The variable $lastmodified seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
57
		$lastmodified = time();
58
	}
59
60
	$headers_only = ($_SERVER['REQUEST_METHOD'] == 'HEAD');
61
	$calculer_page = true;
62
63
	// Pour les pages non-dynamiques (indiquees par #CACHE{duree,cache-client})
64
	// une perennite valide a meme reponse qu'une requete HEAD (par defaut les
65
	// pages sont dynamiques)
66
	if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
67
		and (!defined('_VAR_MODE') or !_VAR_MODE)
68
		and $chemin_cache
69
		and isset($page['entetes'])
70
		and isset($page['entetes']['Cache-Control'])
71
		and strstr($page['entetes']['Cache-Control'], 'max-age=')
72
		and !strstr($_SERVER['SERVER_SOFTWARE'], 'IIS/')
73
	) {
74
		$since = preg_replace('/;.*/', '',
75
			$_SERVER['HTTP_IF_MODIFIED_SINCE']);
76
		$since = str_replace('GMT', '', $since);
77
		if (trim($since) == gmdate("D, d M Y H:i:s", $lastmodified)) {
0 ignored issues
show
Bug introduced by
The variable $lastmodified 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...
78
			$page['status'] = 304;
79
			$headers_only = true;
80
			$calculer_page = false;
81
		}
82
	}
83
84
	// Si requete HEAD ou Last-modified compatible, ignorer le texte
85
	// et pas de content-type (pour contrer le bouton admin de inc-public)
86
	if (!$calculer_page) {
87
		$page['texte'] = "";
88
	} else {
89
		// si la page est prise dans le cache
90
		if (!$GLOBALS['use_cache']) {
91
			// Informer les boutons d'admin du contexte
92
			// (fourni par urls_decoder_url ci-dessous lors de la mise en cache)
93
			$GLOBALS['contexte'] = $page['contexte'];
94
95
			// vider les globales url propres qui ne doivent plus etre utilisees en cas
96
			// d'inversion url => objet
97
			// plus necessaire si on utilise bien la fonction urls_decoder_url
98
			#unset($_SERVER['REDIRECT_url_propre']);
99
			#unset($_ENV['url_propre']);
100
		} else {
101
			// Compat ascendante :
102
			// 1. $contexte est global
103
			// (a evacuer car urls_decoder_url gere ce probleme ?)
104
			// et calculer la page
105
			if (!test_espace_prive()) {
106
				include_spip('inc/urls');
107
				list($fond, $GLOBALS['contexte'], $url_redirect) = urls_decoder_url(nettoyer_uri(), $fond, $GLOBALS['contexte'],
0 ignored issues
show
Bug introduced by
It seems like $GLOBALS['contexte'] can also be of type integer; however, urls_decoder_url() does only seem to accept array, 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...
Unused Code introduced by
The assignment to $url_redirect is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
108
					true);
109
			}
110
			// squelette par defaut
111
			if (!strlen($fond)) {
112
				$fond = 'sommaire';
113
			}
114
115
			// produire la page : peut mettre a jour $lastmodified
116
			$produire_page = charger_fonction('produire_page', 'public');
117
			$page = $produire_page($fond, $GLOBALS['contexte'], $GLOBALS['use_cache'], $chemin_cache, null, $page,
118
				$lastmodified, $connect);
119
			if ($page === '') {
120
				$erreur = _T('info_erreur_squelette2',
121
					array('fichier' => spip_htmlspecialchars($fond) . '.' . _EXTENSION_SQUELETTES));
122
				erreur_squelette($erreur);
123
				// eviter des erreurs strictes ensuite sur $page['cle'] en PHP >= 5.4
124
				$page = array('texte' => '', 'erreur' => $erreur);
125
			}
126
		}
127
128
		if ($page and $chemin_cache) {
129
			$page['cache'] = $chemin_cache;
130
		}
131
132
		auto_content_type($page);
133
134
		$GLOBALS['flag_preserver'] |= headers_sent();
135
136
		// Definir les entetes si ce n'est fait 
137
		if (!$GLOBALS['flag_preserver']) {
138
			if ($GLOBALS['flag_ob']) {
139
				// Si la page est vide, produire l'erreur 404 ou message d'erreur pour les inclusions
140
				if (trim($page['texte']) === ''
141
					and _VAR_MODE != 'debug'
142
					and !isset($page['entetes']['Location']) // cette page realise une redirection, donc pas d'erreur
143
				) {
144
					$GLOBALS['contexte']['fond_erreur'] = $fond;
145
					$page = message_page_indisponible($page, $GLOBALS['contexte']);
146
				}
147
				// pas de cache client en mode 'observation'
148
				if (defined('_VAR_MODE') and _VAR_MODE) {
149
					$page['entetes']["Cache-Control"] = "no-cache,must-revalidate";
150
					$page['entetes']["Pragma"] = "no-cache";
151
				}
152
			}
153
		}
154
	}
155
156
	// Entete Last-Modified:
157
	// eviter d'etre incoherent en envoyant un lastmodified identique
158
	// a celui qu'on a refuse d'honorer plus haut (cf. #655)
159
	if ($lastmodified
160
		and !isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
161
		and !isset($page['entetes']["Last-Modified"])
162
	) {
163
		$page['entetes']["Last-Modified"] = gmdate("D, d M Y H:i:s", $lastmodified) . " GMT";
164
	}
165
166
	// fermer la connexion apres les headers si requete HEAD
167
	if ($headers_only) {
168
		$page['entetes']["Connection"] = "close";
169
	}
170
171
	return $page;
172
}
173
174
/**
175
 * Calcul le contexte de la page
176
 *
177
 * lors du calcul d'une page spip etablit le contexte a partir
178
 * des variables $_GET et $_POST, purgees des fausses variables var_*
179
 *
180
 * Note : pour hacker le contexte depuis le fichier d'appel (page.php),
181
 * il est recommande de modifier $_GET['toto'] (meme si la page est
182
 * appelee avec la methode POST).
183
 *
184
 * https://code.spip.net/@calculer_contexte
185
 *
186
 * @return array Un tableau du contexte de la page
187
 */
188
function calculer_contexte() {
189
190
	$contexte = array();
191 View Code Duplication
	foreach ($_GET as $var => $val) {
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...
192
		if (!preg_match(_CONTEXTE_IGNORE_VARIABLES, $var)) {
193
			$contexte[$var] = $val;
194
		}
195
	}
196 View Code Duplication
	foreach ($_POST as $var => $val) {
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...
197
		if (!preg_match(_CONTEXTE_IGNORE_VARIABLES, $var)) {
198
			$contexte[$var] = $val;
199
		}
200
	}
201
202
	return $contexte;
203
}
204
205
/**
206
 * Calculer le contexte implicite, qui n'apparait pas dans le ENV d'un cache
207
 * mais est utilise pour distinguer deux caches differents
208
 *
209
 * @staticvar string $notes
210
 * @return array
211
 */
212
function calculer_contexte_implicite() {
213
	static $notes = null;
214
	if (is_null($notes)) {
215
		$notes = charger_fonction('notes', 'inc', true);
216
	}
217
	$contexte_implicite = array(
218
		'squelettes' => $GLOBALS['dossier_squelettes'], // devrait etre 'chemin' => $GLOBALS['path_sig'], ?
219
		'host' => (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null),
220
		'https' => (isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : ''),
221
		'espace' => test_espace_prive(),
222
		'marqueur' => (isset($GLOBALS['marqueur']) ? $GLOBALS['marqueur'] : ''),
223
		'marqueur_skel' => (isset($GLOBALS['marqueur_skel']) ? $GLOBALS['marqueur_skel'] : ''),
224
		'notes' => $notes ? $notes('', 'contexter_cache') : '',
225
		'spip_version_code' => $GLOBALS['spip_version_code'],
226
	);
227
	if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
228
		$contexte_implicite['host'] .= "|" . $_SERVER['HTTP_X_FORWARDED_HOST'];
229
	}
230
231
	return $contexte_implicite;
232
}
233
234
//
235
// fonction pour compatibilite arriere, probablement superflue
236
//
237
238
// https://code.spip.net/@auto_content_type
239
function auto_content_type($page) {
240
241
	if (!isset($GLOBALS['flag_preserver'])) {
242
		$GLOBALS['flag_preserver'] = ($page && preg_match("/header\s*\(\s*.content\-type:/isx",
243
				$page['texte']) || (isset($page['entetes']['Content-Type'])));
244
	}
245
}
246
247
// https://code.spip.net/@inclure_page
248
function inclure_page($fond, $contexte, $connect = '') {
249
	static $cacher, $produire_page;
250
251
	// enlever le fond de contexte inclus car sinon il prend la main
252
	// dans les sous inclusions -> boucle infinie d'inclusion identique
253
	// (cette precaution n'est probablement plus utile)
254
	unset($contexte['fond']);
255
	$page = array('contexte_implicite' => calculer_contexte_implicite());
256
	$page['contexte_implicite']['cache'] = $fond;
257
	if (is_null($cacher)) {
258
		$cacher = charger_fonction('cacher', 'public', true);
259
	}
260
	// Les quatre derniers parametres sont modifies par la fonction:
261
	// emplacement, validite, et, s'il est valide, contenu & age
262
	if ($cacher) {
263
		$res = $cacher($contexte, $use_cache, $chemin_cache, $page, $lastinclude);
0 ignored issues
show
Bug introduced by
The variable $use_cache seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $chemin_cache 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...
Bug introduced by
The variable $lastinclude 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...
264
	} else {
265
		$use_cache = -1;
266
	}
267
	// $res = message d'erreur : on sort de la
268
	if ($res) {
269
		return array('texte' => $res);
0 ignored issues
show
Bug introduced by
The variable $res 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...
270
	}
271
272
	// Si use_cache ne vaut pas 0, la page doit etre calculee
273
	// produire la page : peut mettre a jour $lastinclude
274
	// le contexte_cache envoye a cacher() a ete conserve et est passe a produire
275
	if ($use_cache) {
276
		if (is_null($produire_page)) {
277
			$produire_page = charger_fonction('produire_page', 'public');
278
		}
279
		$page = $produire_page($fond, $contexte, $use_cache, $chemin_cache, $contexte, $page, $lastinclude, $connect);
0 ignored issues
show
Bug introduced by
The variable $use_cache 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...
280
	}
281
	// dans tous les cas, mettre a jour $GLOBALS['lastmodified']
282
	$GLOBALS['lastmodified'] = max((isset($GLOBALS['lastmodified']) ? $GLOBALS['lastmodified'] : 0), $lastinclude);
283
284
	return $page;
285
}
286
287
/**
288
 * Produire la page et la mettre en cache
289
 * lorsque c'est necessaire
290
 *
291
 * @param string $fond
292
 * @param array $contexte
293
 * @param int $use_cache
294
 * @param string $chemin_cache
295
 * @param array $contexte_cache
296
 * @param array $page
297
 * @param int $lastinclude
298
 * @param string $connect
299
 * @return array
300
 */
301
function public_produire_page_dist(
302
	$fond,
303
	$contexte,
304
	$use_cache,
305
	$chemin_cache,
306
	$contexte_cache,
307
	&$page,
308
	&$lastinclude,
309
	$connect = ''
310
) {
311
	static $parametrer, $cacher;
312
	if (!$parametrer) {
313
		$parametrer = charger_fonction('parametrer', 'public');
314
	}
315
	$page = $parametrer($fond, $contexte, $chemin_cache, $connect);
316
	// et on l'enregistre sur le disque
317
	if ($chemin_cache
318
		and $use_cache > -1
319
		and is_array($page)
320
		and count($page)
321
		and isset($page['entetes']['X-Spip-Cache'])
322
		and $page['entetes']['X-Spip-Cache'] > 0
323
	) {
324
		if (is_null($cacher)) {
325
			$cacher = charger_fonction('cacher', 'public', true);
326
		}
327
		$lastinclude = time();
328
		if ($cacher) {
329
			$cacher($contexte_cache, $use_cache, $chemin_cache, $page, $lastinclude);
330
		} else {
331
			$use_cache = -1;
0 ignored issues
show
Unused Code introduced by
$use_cache 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...
332
		}
333
	}
334
335
	return $page;
336
}
337
338
// Fonction inseree par le compilateur dans le code compile.
339
// Elle recoit un contexte pour inclure un squelette, 
340
// et les valeurs du contexte de compil prepare par memoriser_contexte_compil
341
// elle-meme appelee par calculer_balise_dynamique dans references.php:
342
// 0: sourcefile
343
// 1: codefile
344
// 2: id_boucle
345
// 3: ligne
346
// 4: langue
347
348
function inserer_balise_dynamique($contexte_exec, $contexte_compil) {
349
	arguments_balise_dyn_depuis_modele(null, 'reset');
0 ignored issues
show
Unused Code introduced by
The call to the function arguments_balise_dyn_depuis_modele() seems unnecessary as the function has no side-effects.
Loading history...
350
351
	if (!is_array($contexte_exec)) {
352
		echo $contexte_exec;
353
	} // message d'erreur etc
354
	else {
355
		inclure_balise_dynamique($contexte_exec, true, $contexte_compil);
356
	}
357
}
358
359
/**
360
 * Inclusion de balise dynamique
361
 * Attention, un appel explicite a cette fonction suppose certains include
362
 *
363
 * https://code.spip.net/@inclure_balise_dynamique
364
 *
365
 * @param string|array $texte
366
 * @param bool $echo Faut-il faire echo ou return
367
 * @param array $contexte_compil Contexte de la compilation
368
 * @return string
369
 */
370
function inclure_balise_dynamique($texte, $echo = true, $contexte_compil = array()) {
371
	if (is_array($texte)) {
372
373
		list($fond, $delainc, $contexte_inclus) = $texte;
374
375
		// delais a l'ancienne, c'est pratiquement mort
376
		$d = isset($GLOBALS['delais']) ? $GLOBALS['delais'] : null;
377
		$GLOBALS['delais'] = $delainc;
378
379
		$page = recuperer_fond($fond, $contexte_inclus,
380
			array('trim' => false, 'raw' => true, 'compil' => $contexte_compil));
381
382
		$texte = $page['texte'];
383
384
		$GLOBALS['delais'] = $d;
385
		// Faire remonter les entetes
386
		if (is_array($page['entetes'])) {
387
			// mais pas toutes
388
			unset($page['entetes']['X-Spip-Cache']);
389
			unset($page['entetes']['Content-Type']);
390
			if (isset($GLOBALS['page']) and is_array($GLOBALS['page'])) {
391
				if (!is_array($GLOBALS['page']['entetes'])) {
392
					$GLOBALS['page']['entetes'] = array();
393
				}
394
				$GLOBALS['page']['entetes'] =
395
					array_merge($GLOBALS['page']['entetes'], $page['entetes']);
396
			}
397
		}
398
		// _pipelines au pluriel array('nom_pipeline' => $args...) avec une syntaxe permettant plusieurs pipelines
399
		if (isset($page['contexte']['_pipelines'])
400
			and is_array($page['contexte']['_pipelines'])
401
			and count($page['contexte']['_pipelines'])
402
		) {
403
			foreach ($page['contexte']['_pipelines'] as $pipe => $args) {
404
				$args['contexte'] = $page['contexte'];
405
				unset($args['contexte']['_pipelines']); // par precaution, meme si le risque de boucle infinie est a priori nul
406
				$texte = pipeline(
407
					$pipe,
408
					array(
409
						'data' => $texte,
410
						'args' => $args
411
					),
412
					false
0 ignored issues
show
Unused Code introduced by
The call to pipeline() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
413
				);
414
			}
415
		}
416
	}
417
418
	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
419
		// compatibilite : avant on donnait le numero de ligne ou rien.
420
		$ligne = intval(isset($contexte_compil[3]) ? $contexte_compil[3] : $contexte_compil);
421
		$GLOBALS['debug_objets']['resultat'][$ligne] = $texte;
422
	}
423
	if ($echo) {
424
		echo $texte;
425
	} else {
426
		return $texte;
427
	}
428
}
429
430
// https://code.spip.net/@message_page_indisponible
431
function message_page_indisponible($page, $contexte) {
432
	static $deja = false;
433
	if ($deja) {
434
		return "erreur";
435
	}
436
	$codes = array(
437
		'404' => '404 Not Found',
438
		'503' => '503 Service Unavailable',
439
	);
440
441
	$contexte['status'] = ($page !== false) ? '404' : '503';
442
	$contexte['code'] = $codes[$contexte['status']];
443
	$contexte['fond'] = '404'; // gere les 2 erreurs
444
	if (!isset($contexte['lang'])) {
445
		include_spip('inc/lang');
446
		$contexte['lang'] = $GLOBALS['spip_lang'];
447
	}
448
449
	$deja = true;
450
	// passer aux plugins qui peuvent decider d'une page d'erreur plus pertinent
451
	// ex restriction d'acces => 401
452
	$contexte = pipeline('page_indisponible', $contexte);
453
454
	// produire la page d'erreur
455
	$page = inclure_page($contexte['fond'], $contexte);
456
	if (!$page) {
457
		$page = inclure_page('404', $contexte);
458
	}
459
	$page['status'] = $contexte['status'];
460
461
	return $page;
462
}
463
464
/**
465
 * gerer le flag qui permet de reperer qu'une balise dynamique a ete inseree depuis un modele
466
 * utilisee dans les #FORMULAIRE_xx
467
 *
468
 * @param string|null $arg
469
 * @param string $operation
470
 * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|string.

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

Loading history...
471
 */
472
function arguments_balise_dyn_depuis_modele($arg, $operation = 'set') {
473
	static $balise_dyn_appellee_par_modele = null;
474
	switch ($operation) {
475
		case 'read':
476
			return $balise_dyn_appellee_par_modele;
477
		case 'reset':
478
			$balise_dyn_appellee_par_modele = null;
479
			return null;
480
		case 'set':
481
		default:
482
			$balise_dyn_appellee_par_modele = $arg;
483
			return $arg;
484
	}
485
}
486
487
// temporairement ici : a mettre dans le futur inc/modeles
488
// creer_contexte_de_modele('left', 'autostart=true', ...) renvoie un array()
489
// https://code.spip.net/@creer_contexte_de_modele
490
function creer_contexte_de_modele($args) {
491
	$contexte = array();
492
	foreach ($args as $var => $val) {
493
		if (is_int($var)) { // argument pas formate
494
			if (in_array($val, array('left', 'right', 'center'))) {
495
				$var = 'align';
496
				$contexte[$var] = $val;
497
			} else {
498
				$args = explode('=', $val);
499
				if (count($args) >= 2) // Flashvars=arg1=machin&arg2=truc genere plus de deux args
500
				{
501
					$contexte[trim($args[0])] = substr($val, strlen($args[0]) + 1);
502
				} else // notation abregee
503
				{
504
					$contexte[trim($val)] = trim($val);
505
				}
506
			}
507
		} else {
508
			$contexte[$var] = $val;
509
		}
510
	}
511
512
	return $contexte;
513
}
514
515
/**
516
 * Router eventuellement un modele vers un autre
517
 *   * le modele doit etre declare dans la liste 'modeles' d'une table objet
518
 *   * il faut avoir un routeur de modele declare pour le meme objet
519
 * @param string $modele
520
 * @param int $id
521
 * @param null|array $contexte
522
 *   contexte eventuel : attention sa presence n'est pas garantie
523
 *   et il ne doit etre utilise que pour trouver le id_xx si pas de $id fourni (cas appel depuis styliser)
524
 * @return string
525
 */
526
function styliser_modele($modele, $id, $contexte=null) {
527
	static $styliseurs = null;
528
	if (is_null($styliseurs)) {
529
		$tables_objet = lister_tables_objets_sql();
530
		foreach ($tables_objet as $table => $desc) {
0 ignored issues
show
Bug introduced by
The expression $tables_objet of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
531
			if (isset($desc['modeles']) and $desc['modeles']
532
				and isset($desc['modeles_styliser']) and $desc['modeles_styliser']
533
				and function_exists($desc['modeles_styliser'])) {
534
				$primary = id_table_objet($table);
535
				foreach ($desc['modeles'] as $m) {
536
					$styliseurs[$m] = ['primary' => $primary, 'callback' => $desc['modeles_styliser']];
537
				}
538
			}
539
		}
540
	}
541
542
	if (isset($styliseurs[$modele])) {
543
		$styliseur = $styliseurs[$modele]['callback'];
544
		if (is_null($id) and $contexte) {
545
			if (isset($contexte['id'])) {
546
				$id = $contexte['id'];
547
			} elseif (isset($contexte[$primary])) {
548
				$id = $contexte[$primary];
0 ignored issues
show
Bug introduced by
The variable $primary 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...
549
			}
550
		}
551
		if (is_null($id)) {
552
			$msg = "modeles/$modele : " . _T('zbug_parametres_inclus_incorrects', array('param' => "id/$primary"));
553
			erreur_squelette($msg);
554
			// on passe id=0 au routeur pour tomber sur le modele par defaut et eviter une seconde erreur sur un modele inexistant
555
			$id = 0;
556
		}
557
		$modele = $styliseur($modele, $id);
558
	}
559
560
	return $modele;
561
}
562
563
/**
564
 * Calcule le modele et retourne la mini-page ainsi calculee
565
 *
566
 * https://code.spip.net/@inclure_modele
567
 *
568
 * @param $type string Nom du modele
569
 * @param $id int
570
 * @param $params array Paramètres du modèle
571
 * @param $lien array Informations du lien entourant l'appel du modèle en base de données
572
 * @param $connect string
573
 * @param $env array
574
 * @staticvar string $compteur
575
 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false|array? Also, consider making the array more specific, something like array<String>, or String[].

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.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
576
 */
577
function inclure_modele($type, $id, $params, $lien, $connect = '', $env = array()) {
578
579
	static $compteur;
580
	if (++$compteur > 10) {
581
		return '';
582
	} # ne pas boucler indefiniment
583
584
	$type = strtolower($type);
585
	$type = styliser_modele($type, $id);
586
587
	$fond = $class = '';
588
589
	$params = array_filter(explode('|', $params));
590
	if ($params) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $params of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
591
		$soustype = current($params);
592
		$soustype = strtolower(trim($soustype));
593
		if (in_array($soustype, array('left', 'right', 'center', 'ajax'))) {
594
			$soustype = next($params);
595
			$soustype = strtolower($soustype);
596
		}
597
598
		if (preg_match(',^[a-z0-9_]+$,', $soustype)) {
599
			if (!trouve_modele($fond = ($type . '_' . $soustype))) {
600
				$fond = '';
601
				$class = $soustype;
602
			}
603
			// enlever le sous type des params
604
			$params = array_diff($params, array($soustype));
605
		}
606
	}
607
608
	// Si ca marche pas en precisant le sous-type, prendre le type
609
	if (!$fond and !trouve_modele($fond = $type)) {
610
		spip_log("Modele $type introuvable", _LOG_INFO_IMPORTANTE);
611
612
		return false;
613
	}
614
	$fond = 'modeles/' . $fond;
615
	// Creer le contexte
616
	$contexte = $env;
617
	$contexte['dir_racine'] = _DIR_RACINE; # eviter de mixer un cache racine et un cache ecrire (meme si pour l'instant les modeles ne sont pas caches, le resultat etant different il faut que le contexte en tienne compte
618
619
	// Le numero du modele est mis dans l'environnement
620
	// d'une part sous l'identifiant "id"
621
	// et d'autre part sous l'identifiant de la cle primaire
622
	// par la fonction id_table_objet,
623
	// (<article1> =>> article =>> id_article =>> id_article=1)
624
	$_id = id_table_objet($type);
625
	$contexte['id'] = $contexte[$_id] = $id;
626
627
	if (isset($class)) {
628
		$contexte['class'] = $class;
629
	}
630
631
	// Si un lien a ete passe en parametre, ex: [<modele1>->url] ou [<modele1|title_du_lien{hreflang}->url]
632
	if ($lien) {
633
		# un eventuel guillemet (") sera reechappe par #ENV
634
		$contexte['lien'] = str_replace("&quot;", '"', $lien['href']);
635
		$contexte['lien_class'] = $lien['class'];
636
		$contexte['lien_mime'] = $lien['mime'];
637
		$contexte['lien_title'] = $lien['title'];
638
		$contexte['lien_hreflang'] = $lien['hreflang'];
639
	}
640
641
	// Traiter les parametres
642
	// par exemple : <img1|center>, <emb12|autostart=true> ou <doc1|lang=en>
643
	$arg_list = creer_contexte_de_modele($params);
644
	$contexte['args'] = $arg_list; // on passe la liste des arguments du modeles dans une variable args
645
	$contexte = array_merge($contexte, $arg_list);
646
647
	// Appliquer le modele avec le contexte
648
	$retour = recuperer_fond($fond, $contexte, array(), $connect);
649
650
	// Regarder si le modele tient compte des liens (il *doit* alors indiquer
651
	// spip_lien_ok dans les classes de son conteneur de premier niveau ;
652
	// sinon, s'il y a un lien, on l'ajoute classiquement
653
	if (strstr(' ' . ($classes = extraire_attribut($retour, 'class')) . ' ',
654
		'spip_lien_ok')) {
655
		$retour = inserer_attribut($retour, 'class',
0 ignored issues
show
Bug introduced by
It seems like $retour can also be of type array; 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...
656
			trim(str_replace(' spip_lien_ok ', ' ', " $classes ")));
657
	} else {
658
		if ($lien) {
659
			$retour = "<a href='" . $lien['href'] . "' class='" . $lien['class'] . "'>" . $retour . "</a>";
660
		}
661
	}
662
663
	$compteur--;
664
665
	return (isset($arg_list['ajax']) and $arg_list['ajax'] == 'ajax')
666
		? encoder_contexte_ajax($contexte, '', $retour)
0 ignored issues
show
Bug introduced by
It seems like $retour defined by recuperer_fond($fond, $c...xte, array(), $connect) on line 648 can also be of type array; however, encoder_contexte_ajax() does only seem to accept string|null, 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...
667
		: $retour;
668
}
669
670
// Un inclure_page qui marche aussi pour l'espace prive
671
// fonction interne a spip, ne pas appeler directement
672
// pour recuperer $page complet, utiliser:
673
// 	recuperer_fond($fond,$contexte,array('raw'=>true))
674
// https://code.spip.net/@evaluer_fond
675
function evaluer_fond($fond, $contexte = array(), $connect = null) {
676
677
	$page = inclure_page($fond, $contexte, $connect);
678
679
	if (!$page) {
680
		return $page;
681
	}
682
	// eval $page et affecte $res
683
	include _ROOT_RESTREINT . "public/evaluer_page.php";
684
685
	// Lever un drapeau (global) si le fond utilise #SESSION
686
	// a destination de public/parametrer
687
	// pour remonter vers les inclusions appelantes
688
	// il faut bien lever ce drapeau apres avoir evalue le fond
689
	// pour ne pas faire descendre le flag vers les inclusions appelees
690 View Code Duplication
	if (isset($page['invalideurs'])
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...
691
		and isset($page['invalideurs']['session'])
692
	) {
693
		$GLOBALS['cache_utilise_session'] = $page['invalideurs']['session'];
694
	}
695
696
	return $page;
697
}
698
699
700
// https://code.spip.net/@page_base_href
701
function page_base_href(&$texte) {
702
	static $set_html_base = null;
703
	if (is_null($set_html_base)) {
704
		if (!defined('_SET_HTML_BASE'))
705
			// si la profondeur est superieure a 1
706
			// est que ce n'est pas une url page ni une url action
707
			// activer par defaut
708
		{
709
			$set_html_base = ((
710
				$GLOBALS['profondeur_url'] >= (_DIR_RESTREINT ? 1 : 2)
711
				and _request(_SPIP_PAGE) !== 'login'
712
				and !_request('action')) ? true : false);
713
		} else {
714
			$set_html_base = _SET_HTML_BASE;
715
		}
716
	}
717
718
	if ($set_html_base
719
		and isset($GLOBALS['html']) and $GLOBALS['html']
720
		and $GLOBALS['profondeur_url'] > 0
721
		and ($poshead = strpos($texte, '</head>')) !== false
722
	) {
723
		$head = substr($texte, 0, $poshead);
724
		$insert = false;
0 ignored issues
show
Unused Code introduced by
$insert 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...
725
		if (strpos($head, '<base') === false) {
726
			$insert = true;
727
		} else {
728
			// si aucun <base ...> n'a de href c'est bon quand meme !
729
			$insert = true;
730
			include_spip('inc/filtres');
731
			$bases = extraire_balises($head, 'base');
732
			foreach ($bases as $base) {
733
				if (extraire_attribut($base, 'href')) {
734
					$insert = false;
735
				}
736
			}
737
		}
738
		if ($insert) {
739
			include_spip('inc/filtres_mini');
740
			// ajouter un base qui reglera tous les liens relatifs
741
			$base = url_absolue('./');
742
			$bbase = "\n<base href=\"$base\" />";
743
			if (($pos = strpos($head, '<head>')) !== false) {
744
				$head = substr_replace($head, $bbase, $pos + 6, 0);
745
			} elseif (preg_match(",<head[^>]*>,i", $head, $r)) {
746
				$head = str_replace($r[0], $r[0] . $bbase, $head);
747
			}
748
			$texte = $head . substr($texte, $poshead);
749
			// gerer les ancres
750
			$base = $_SERVER['REQUEST_URI'];
751
			// pas de guillemets ni < dans l'URL qu'on insere dans le HTML
752
			if (strpos($base,"'") or strpos($base,'"') or strpos($base,'<')) {
753
				$base = str_replace(array("'",'"','<'),array("%27",'%22','%3C'), $base);
754
			}
755 View Code Duplication
			if (strpos($texte, "href='#") !== 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...
756
				$texte = str_replace("href='#", "href='$base#", $texte);
757
			}
758 View Code Duplication
			if (strpos($texte, "href=\"#") !== 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...
759
				$texte = str_replace("href=\"#", "href=\"$base#", $texte);
760
			}
761
		}
762
	}
763
}
764
765
766
// Envoyer les entetes, en retenant ceux qui sont a usage interne
767
// et demarrent par X-Spip-...
768
// https://code.spip.net/@envoyer_entetes
769
function envoyer_entetes($entetes) {
770
	foreach ($entetes as $k => $v) #	if (strncmp($k, 'X-Spip-', 7))
771
	{
772
		@header(strlen($v) ? "$k: $v" : $k);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
773
	}
774
}
775