[SPIP] v3.2.1-->v3.2.3
[lhc/web/www.git] / www / plugins-dist / urls_etendues / action / editer_url.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 if (!defined("_ECRIRE_INC_VERSION")) {
14 return;
15 }
16
17 function action_editer_url_dist() {
18
19 // Rien a faire ici pour le moment
20 #$securiser_action = charger_fonction('securiser_action', 'inc');
21 #$arg = $securiser_action();
22
23 }
24
25 /**
26 * Verifier si une langue presumee est valide
27 * - utile pour l'edition manuelle d'une URL ou pour le decodage
28 * @param string $langue
29 * @return bool
30 */
31 function url_verifier_langue($langue) {
32 include_spip('inc/lang');
33 if (!match_langue($langue)) {
34 return false;
35 }
36
37 include_spip('inc/lang_liste');
38 $all_langs = array_keys($GLOBALS['codes_langues']);
39 if (!in_array($langue, $all_langs)) {
40 return false;
41 }
42
43 return true;
44 }
45
46 /**
47 * Nettoyer une URL :
48 * supprimer le html, le rang, extraire les multi, translitterer
49 * @param string $titre
50 * @param int $longueur_maxi
51 * @param int $longueur_min
52 * @param string $separateur
53 * @param string $filtre
54 * @return string
55 */
56 function url_nettoyer($titre, $longueur_maxi, $longueur_min = 0, $separateur = '-', $filtre = '') {
57
58 $titre = supprimer_tags(supprimer_numero(extraire_multi($titre)));
59 $url = translitteration($titre);
60
61 if ($filtre) {
62 $url = $filtre($url);
63 }
64
65 // on va convertir tous les caracteres de ponctuation et espaces
66 // a l'exception de l'underscore (_), car on veut le conserver dans l'url
67 $url = str_replace('_', chr(7), $url);
68 $url = @preg_replace(',[[:punct:][:space:]]+,u', ' ', $url);
69 $url = str_replace(chr(7), '_', $url);
70
71 // S'il reste trop de caracteres non latins, les gerer comme wikipedia
72 // avec rawurlencode :
73 if (preg_match_all(",[^a-zA-Z0-9 _]+,", $url, $r, PREG_SET_ORDER)) {
74 foreach ($r as $regs) {
75 $url = substr_replace($url, rawurlencode($regs[0]),
76 strpos($url, $regs[0]), strlen($regs[0]));
77 }
78 }
79
80 // S'il reste trop peu, renvoyer vide
81 if (strlen($url) < $longueur_min) {
82 return '';
83 }
84
85 // Sinon couper les mots et les relier par des $separateur
86 $mots = preg_split(",[^a-zA-Z0-9_%]+,", $url);
87 $url = '';
88 foreach ($mots as $mot) {
89 if (!strlen($mot)) {
90 continue;
91 }
92 $url2 = $url . $separateur . $mot;
93
94 // Si on depasse $longueur_maxi caracteres, s'arreter
95 // ne pas compter 3 caracteres pour %E9 mais un seul
96 $long = preg_replace(',%.,', '', $url2);
97 if (strlen($long) > $longueur_maxi) {
98 break;
99 }
100
101 $url = $url2;
102 }
103 $url = substr($url, 1);
104
105 // On enregistre en utf-8 dans la base
106 $url = rawurldecode($url);
107
108 if (strlen($url) < $longueur_min) {
109 return '';
110 }
111
112 return $url;
113 }
114
115 /**
116 * Inserer une URL en base avec multiples controles et gestion des collisions
117 * en essayant d'eviter des problemes de race condition
118 * @param array $set
119 * @param bool $confirmer
120 * @param string $separateur
121 * @return bool
122 */
123 function url_insert(&$set, $confirmer, $separateur) {
124 $has_parent = true;
125 # assurer la coherence des champs techniques si non fournis
126 if (!isset($set['id_parent'])) {
127 $has_parent = false;
128 $set['id_parent'] = 0;
129 }
130 if (!isset($set['segments'])) {
131 $set['segments'] = count(explode('/', $set['url']));
132 }
133 if (!isset($set['langue'])) {
134 $set['langue'] = '';
135 }
136 $perma = false;
137 if (isset($set['perma']) and $set['perma']) {
138 unset($set['perma']);
139 $perma = true;
140 }
141 $redate = true;
142
143 # le separateur ne peut pas contenir de /
144 if (strpos($separateur, '/') !== false) {
145 $separateur = "-";
146 }
147
148 // Si l'insertion echoue, c'est une violation d'unicite.
149 $where_urllike = 'url LIKE ' . url_sql_quote_like($set['url']) . " AND NOT(type=" . sql_quote($set['type']) . " AND id_objet=" . intval($set['id_objet']) . ")";
150 $where_thisurl = $where_urllike . ($has_parent ? " AND id_parent=" . intval($set['id_parent']) : "");
151 if (
152 // si pas de parent defini, il faut que cette url soit unique, independamment de id_parent
153 // il faut utiliser un LIKE pour etre case unsensitive en sqlite
154 (!$has_parent and sql_countsel("spip_urls", $where_urllike))
155 or @sql_insertq('spip_urls', $set) <= 0
156 ) {
157
158 // On veut chiper une ancienne adresse ou prendre celle d'un repertoire deja present?
159 if (
160 (!is_dir(_DIR_RACINE . $set['url']) and !file_exists(_DIR_RACINE . $set['url']))
161 // un vieux url
162 and $vieux = sql_fetsel('*', 'spip_urls', $where_thisurl, '', 'perma DESC')
163 // qui n'est pas permanente
164 and !$vieux['perma']
165 // et dont l'objet a une url plus recente
166 and $courant = sql_fetsel('*', 'spip_urls',
167 'type=' . sql_quote($vieux['type']) . ' AND id_objet=' . sql_quote($vieux['id_objet'])
168 . ' AND url<>' . sql_quote($set['url'])
169 . ' AND date>' . sql_quote($vieux['date']), '', 'date DESC', 1)
170 ) {
171 if ($confirmer and !_request('ok2')) {
172 die("Vous voulez chiper l'URL de l'objet " . $courant['type'] . " "
173 . $courant['id_objet'] . " qui a maintenant l'url "
174 . $courant['url']);
175 }
176 $where_thisurl = "url=" . sql_quote($vieux['url']) . " AND id_parent=" . intval($vieux['id_parent']);
177 // si oui on le chipe
178 sql_updateq('spip_urls', $set, $where_thisurl);
179 sql_updateq('spip_urls', array('date' => date('Y-m-d H:i:s')), $where_thisurl);
180 spip_log("reattribue url " . $vieux['url']
181 . " de " . $vieux['type'] . "#" . $vieux['id_objet'] . " (parent " . $vieux['id_parent'] . ")"
182 . " A " . $set['type'] . "#" . $set['id_objet'] . " (parent " . $set['id_parent'] . ")",
183 "urls" . _LOG_INFO_IMPORTANTE);
184 } // Sinon
185 else {
186
187 // Soit c'est un Come Back d'une ancienne url propre de l'objet
188 // Soit c'est un vrai conflit. Rajouter l'ID jusqu'a ce que ca passe,
189 // mais se casser avant que ca ne casse.
190
191 // il peut etre du a un changement de casse de l'url simplement
192 // pour ce cas, on reecrit systematiquement l'url en plus d'actualiser la date
193 $where = "type=" . sql_quote($set['type'])
194 . " AND id_objet=" . intval($set['id_objet'])
195 . " AND id_parent=" . intval($set['id_parent'])
196 . " AND url LIKE ";
197 if (
198 !is_dir(_DIR_RACINE . $set['url']) and !file_exists(_DIR_RACINE . $set['url'])
199 and $existing = sql_fetsel('*','spip_urls', $where . url_sql_quote_like($set['url']))
200 ) {
201 $refresh = array(
202 'url' => $set['url'],
203 'date' => date('Y-m-d H:i:s'),
204 );
205 // si c'est une URL avec langue est qu'ici on a pas de langue, on ecrase
206 if ($existing['langue']) {
207 if (!$set['langue']){
208 $refresh['langue'] = '';
209 }
210 elseif($set['langue'] !== $existing['langue']) {
211 $set['url'] .= $separateur . $set['langue'];
212 return url_insert_replay($set, $confirmer, $separateur, $has_parent, $perma);
213 }
214 }
215 // sinon c'est une URL sans langue (generique)
216 else {
217 // si c'est pas une URL perma manuelle,
218 // on ignore la langue de cette URL, l'URL generique s'appliquera
219 if (!$perma) {
220 unset($set['langue']);
221 }
222 else {
223 $refresh['langue'] = $set['langue'];
224 }
225 }
226 sql_updateq('spip_urls', $refresh, $where . url_sql_quote_like($set['url']));
227 spip_log("refresh " . $set['type'] . " " . $set['id_objet'].' refresh:'.serialize($refresh), "urls");
228 $redate = false;
229 } else {
230 $set['url'] .= $separateur . $set['id_objet'];
231 return url_insert_replay($set, $confirmer, $separateur, $has_parent, $perma);
232 }
233 }
234 }
235
236 $reset = array();
237 // si on a fixe une langue pour cette URL mais qu'il n'y a pas d'URL generique pour cet objet (avec langue='')
238 // on retire la langue car c'est l'URL generique par defaut
239 if (!empty($set['langue'])) {
240 if (!sql_countsel('spip_urls',
241 "type=" . sql_quote($set['type'])
242 . " AND id_objet=" . intval($set['id_objet'])
243 . " AND id_parent=" . intval($set['id_parent'])
244 . " AND langue=" . sql_quote(''))){
245 $set['langue'] = $reset['langue'] = '';
246 }
247 } else {
248 $set['langue'] = '';
249 }
250 if ($redate) {
251 $reset['date'] = date('Y-m-d H:i:s');
252 }
253
254 $where_thisurl = 'url=' . sql_quote($set['url']) . " AND id_parent=" . intval($set['id_parent']); // maj
255 if ($reset) {
256 sql_updateq('spip_urls', $reset, $where_thisurl);
257 }
258
259 // si url perma, poser le flag sur la seule url qu'on vient de mettre (au sein de celles qui ont la meme langue)
260 if ($perma) {
261 sql_update('spip_urls', array('perma' => "($where_thisurl)"),
262 "type=" . sql_quote($set['type']) . " AND id_objet=" . intval($set['id_objet'])." AND langue=" . sql_quote($set['langue']));
263 }
264
265 spip_log("Creation de l'url propre '" . $set['url'] . "' pour "
266 . $set['type'] . " " . $set['id_objet']
267 . " (parent [" . $set['id_parent'] . "] langue [" . $set['langue'] . "] perma [" . ($perma ? "1" : "0") . "])", "urls");
268
269 return true;
270 }
271
272 /**
273 * Rejouer une insertion qui a echoue avec une url modifiee (rallongee)
274 * on s'assure que la longueur de l'URL n'est pas problematique, et on remet le $set comme il faut
275 * @param array $set
276 * @param bool $confirmer
277 * @param string $separateur
278 * @param bool $has_parent
279 * @param bool $perma
280 * @return bool
281 */
282 function url_insert_replay($set, $confirmer, $separateur, $has_parent, $perma) {
283 //var_dump('url_insert_replay');
284 if (strlen($set['url']) > 200) //serveur out ? retourner au mieux
285 {
286 return false;
287 }
288 else {
289 // remettre id_parent et perma comme il faut si besoin
290 if (!$has_parent) {
291 unset($set['id_parent']);
292 }
293 if ($perma) {
294 $set['perma'] = true;
295 }
296 //var_dump($set);
297 return url_insert($set, $confirmer, $separateur);
298 }
299 }
300
301 /**
302 * Faire un quote de l'URL pour une condition LIKE, donc en echapant les caracteres specifiques aux like
303 * @param $url
304 * @return string
305 */
306 function url_sql_quote_like($url) {
307 return sql_quote(str_replace(array("%", "_"), array("\\%", "\\_"), $url)) . " ESCAPE " . sql_quote('\\');
308 }
309
310 /**
311 * Verrouiller une URL
312 * poser le flag sur une unique url d'un objet
313 * (au sein de celles qui ont la meme langue : on peut avoir plusieurs URLs perma, une par langue)
314 *
315 * @param string $url
316 * @param int $id_parent
317 * @param $url
318 */
319 function url_verrouiller($url, $id_parent=0) {
320 $where_thisurl = 'url=' . sql_quote($url) . " AND id_parent=" . intval($id_parent);
321 $row = sql_fetsel('*','spip_urls',$where_thisurl);
322
323 // on fait un update unique pour changer toutes les URLs concernees d'un coup
324 if ($row) {
325 sql_update('spip_urls', array('perma' => "($where_thisurl)"),
326 "type=" . sql_quote($row['type']) . " AND id_objet=" . intval($row['id_objet'])." AND langue=" . sql_quote($row['langue']));
327 }
328 }
329
330 /**
331 * Supprimer une URL
332 * @param $objet
333 * @param $id_objet
334 * @param string $url
335 * @param int $id_parent
336 */
337 function url_delete($objet, $id_objet, $url = "", $id_parent=0) {
338 $where = "id_objet=" . intval($id_objet) . " AND type=" . sql_quote($objet);
339 if (strlen($url)) {
340 $where .= " AND url=" . sql_quote($url) . " AND id_parent=" . intval($id_parent);
341 }
342
343 sql_delete("spip_urls", $where);
344
345 // si on a supprime une seule URL, s'assurer qu'on a toujours au moins une URL avec lang=''
346 $where = "id_objet=" . intval($id_objet) . " AND type=" . sql_quote($objet);
347 if (!$nb = sql_countsel('spip_urls',$where .' AND langue=\'\'')) {
348 if ($last = sql_fetsel('*','spip_urls',$where,'','perma=1 DESC, langue=\'\' DESC, id_parent=0 DESC, date DESC','0,1')) {
349 sql_updateq('spip_urls',array('langue'=>''),'url='.sql_quote($last['url']) . ' AND id_parent='.intval($last['id_parent']));
350 }
351 }
352 }