[SPIP] v3.2.1-->v3.2.2
[lhc/web/www.git] / www / ecrire / inc / headers.php
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 * Gestion des headers et redirections
15 *
16 * @package SPIP\Core\Headers
17 **/
18
19 if (!defined('_ECRIRE_INC_VERSION')) {
20 return;
21 }
22
23
24 /**
25 * Envoyer le navigateur sur une nouvelle adresse
26 *
27 * Le tout en évitant les attaques par la redirection (souvent indique par un `$_GET`)
28 *
29 * @example
30 * ```
31 * $redirect = parametre_url(urldecode(_request('redirect')),'id_article=' . $id_article);
32 * include_spip('inc/headers');
33 * redirige_par_entete($redirect);
34 * ```
35 *
36 * @param string $url URL de redirection
37 * @param string $equiv ?
38 * @param int $status Code de redirection (301 ou 302)
39 **/
40 function redirige_par_entete($url, $equiv = '', $status = 302) {
41 if (!in_array($status, array(301, 302))) {
42 $status = 302;
43 }
44
45 $url = trim(strtr($url, "\n\r", " "));
46 # si l'url de redirection est relative, on la passe en absolue
47 if (!preg_match(",^(\w+:)?//,", $url)) {
48 include_spip("inc/filtres_mini");
49 $url = url_absolue($url);
50 }
51
52 if ($x = _request('transformer_xml')) {
53 $url = parametre_url($url, 'transformer_xml', $x, '&');
54 }
55
56 if (defined('_AJAX') and _AJAX) {
57 $url = parametre_url($url, 'var_ajax_redir', 1, '&');
58 }
59
60 // ne pas laisser passer n'importe quoi dans l'url
61 $url = str_replace(array('<', '"'), array('&lt;', '&quot;'), $url);
62 // interdire les url inline avec des pseudo-protocoles :
63 if (
64 (preg_match(",data:,i", $url) and preg_match("/base64\s*,/i", $url))
65 or preg_match(",(javascript|mailto):,i", $url)
66 ) {
67 $url = "./";
68 }
69
70 // Il n'y a que sous Apache que setcookie puis redirection fonctionne
71 include_spip('inc/cookie');
72 if ((!$equiv and !spip_cookie_envoye()) or (
73 (strncmp("Apache", $_SERVER['SERVER_SOFTWARE'], 6) == 0)
74 or (stripos($_SERVER['SERVER_SIGNATURE'], 'Apache') !== false)
75 or function_exists('apache_getenv')
76 or defined('_SERVER_APACHE')
77 )
78 ) {
79 @header("Location: " . $url);
80 $equiv = "";
81 } else {
82 @header("Refresh: 0; url=" . $url);
83 if (isset($GLOBALS['meta']['charset'])) {
84 @header("Content-Type: text/html; charset=" . $GLOBALS['meta']['charset']);
85 }
86 $equiv = "<meta http-equiv='Refresh' content='0; url=$url'>";
87 }
88 include_spip('inc/lang');
89 if ($status != 302) {
90 http_status($status);
91 }
92 echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">', "\n",
93 html_lang_attributes(), '
94 <head>',
95 $equiv, '
96 <title>HTTP ' . $status . '</title>
97 ' . ((isset($GLOBALS['meta']['charset'])) ? '<meta http-equiv="Content-Type" content="text/html;charset=' . $GLOBALS['meta']['charset'] . '">' : '') . '
98 </head>
99 <body>
100 <h1>HTTP ' . $status . '</h1>
101 <a href="',
102 quote_amp($url),
103 '">',
104 _T('navigateur_pas_redirige'),
105 '</a></body></html>';
106
107 spip_log("redirige $status: $url");
108
109 exit;
110 }
111
112 // http://code.spip.net/@redirige_formulaire
113 function redirige_formulaire($url, $equiv = '', $format = 'message') {
114 if (!_AJAX
115 and !headers_sent()
116 and !_request('var_ajax')
117 ) {
118 redirige_par_entete(str_replace('&amp;', '&', $url), $equiv);
119 } // si c'est une ancre, fixer simplement le window.location.hash
120 elseif ($format == 'ajaxform' and preg_match(',^#[0-9a-z\-_]+$,i', $url)) {
121 return array(
122 // on renvoie un lien masque qui sera traite par ajaxCallback.js
123 "<a href='$url' name='ajax_ancre' style='display:none;'>anchor</a>",
124 // et rien dans le message ok
125 ''
126 );
127 } else {
128 // ne pas laisser passer n'importe quoi dans l'url
129 $url = str_replace(array('<', '"'), array('&lt;', '&quot;'), $url);
130
131 $url = strtr($url, "\n\r", " ");
132 # en theorie on devrait faire ca tout le temps, mais quand la chaine
133 # commence par ? c'est imperatif, sinon l'url finale n'est pas la bonne
134 if ($url[0] == '?') {
135 $url = url_de_base() . $url;
136 }
137 $url = str_replace('&amp;', '&', $url);
138 spip_log("redirige formulaire ajax: $url");
139 include_spip('inc/filtres');
140 if ($format == 'ajaxform') {
141 return array(
142 // on renvoie un lien masque qui sera traite par ajaxCallback.js
143 '<a href="' . quote_amp($url) . '" name="ajax_redirect" style="display:none;">' . _T('navigateur_pas_redirige') . '</a>',
144 // et un message au cas ou
145 '<br /><a href="' . quote_amp($url) . '">' . _T('navigateur_pas_redirige') . '</a>'
146 );
147 } else // format message texte, tout en js inline
148 {
149 return
150 // ie poste les formulaires dans une iframe, il faut donc rediriger son parent
151 "<script type='text/javascript'>if (parent.window){parent.window.document.location.replace(\"$url\");} else {document.location.replace(\"$url\");}</script>"
152 . http_img_pack('searching.gif', '')
153 . '<br />'
154 . '<a href="' . quote_amp($url) . '">' . _T('navigateur_pas_redirige') . '</a>';
155 }
156 }
157 }
158
159 /**
160 * Effectue une redirection par header PHP vers un script de l’interface privée
161 *
162 * @uses redirige_par_entete() Qui tue le script PHP.
163 * @example
164 * ```
165 * include_spip('inc/headers');
166 * redirige_url_ecrire('rubriques','id_rubrique=' . $id_rubrique);
167 * ```
168 *
169 * @param string $script
170 * Nom de la page privée (exec)
171 * @param string $args
172 * Arguments à transmettre. Exemple `etape=1&autre=oui`
173 * @param string $equiv
174 * @return void
175 **/
176 function redirige_url_ecrire($script = '', $args = '', $equiv = '') {
177 return redirige_par_entete(generer_url_ecrire($script, $args, true), $equiv);
178 }
179
180 /**
181 * Renvoie au client le header HTTP avec le message correspondant au code indiqué.
182 *
183 * Ainsi `http_status(301)` enverra le message `301 Moved Permanently`.
184 *
185 * @link http://php.net/manual/fr/function.header.php Fonction header() de PHP utilisée ici
186 *
187 * @param int $status
188 * Code d'erreur
189 **/
190 function http_status($status) {
191
192 static $status_string = array(
193 200 => '200 OK',
194 204 => '204 No Content',
195 301 => '301 Moved Permanently',
196 302 => '302 Found',
197 304 => '304 Not Modified',
198 401 => '401 Unauthorized',
199 403 => '403 Forbidden',
200 404 => '404 Not Found',
201 503 => '503 Service Unavailable'
202 );
203
204 if (!empty($GLOBALS['REDIRECT_STATUS']) && $GLOBALS['REDIRECT_STATUS'] == $status) {
205 return;
206 }
207
208 $php_cgi = ($GLOBALS['flag_sapi_name'] and preg_match(",cgi,i", @php_sapi_name()));
209 if ($php_cgi) {
210 header("Status: " . $status_string[$status]);
211 } else {
212 header("HTTP/1.0 " . $status_string[$status]);
213 }
214 }
215
216 // Retourne ce qui va bien pour que le navigateur ne mette pas la page en cache
217 // http://code.spip.net/@http_no_cache
218 function http_no_cache() {
219 if (headers_sent()) {
220 spip_log("http_no_cache arrive trop tard");
221
222 return;
223 }
224 $charset = empty($GLOBALS['meta']['charset']) ? 'utf-8' : $GLOBALS['meta']['charset'];
225
226 // selon http://developer.apple.com/internet/safari/faq.html#anchor5
227 // il faudrait aussi pour Safari
228 // header("Cache-Control: post-check=0, pre-check=0", false)
229 // mais ca ne respecte pas
230 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
231
232 header("Content-Type: text/html; charset=$charset");
233 header("Expires: 0");
234 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
235 header("Cache-Control: no-cache, must-revalidate");
236 header("Pragma: no-cache");
237 }