[SPIP] ~v3.0.20-->v3.0.25
[lhc/web/clavette_www.git] / www / ecrire / inc / install.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
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 de l'installation de SPIP
15 *
16 * @package SPIP\Installation
17 **/
18
19 if (!defined('_ECRIRE_INC_VERSION')) return;
20
21
22 /**
23 * Écrit un fichier PHP nécessitant SPIP
24 *
25 * Écrit le texte transmis dans un fichier PHP. Cette fonction
26 * ajoute les entêtes PHP et le test de sécurité vérifiant que SPIP
27 * est chargé.
28 *
29 * @example
30 * install_fichier_connexion(_FILE_CONNECT_TMP, $contenu);
31 *
32 * @todo
33 * Renommer cette fonction qui peut servir à d'autres utilisations ?
34 *
35 * @param string $nom
36 * Chemin du fichier à créer
37 * @param string $texte
38 * Code source du fichier (sans l'ouverture/fermeture PHP)
39 * @return void
40 **/
41 function install_fichier_connexion($nom, $texte)
42 {
43 $texte = "<"."?php\n"
44 . "if (!defined(\"_ECRIRE_INC_VERSION\")) return;\n"
45 . $texte
46 . "?".">";
47
48 ecrire_fichier($nom, $texte);
49 }
50
51
52 /**
53 * Retourne le code source d'un fichier de connexion à une base de données
54 *
55 * Le code est un appel à la fonction spip_connect_db()
56 *
57 * @see spip_connect_db()
58 *
59 * @internal
60 * Attention etape_ldap4 suppose qu'il n'y aura qu'un seul appel de fonction
61 * dans le fichier produit.
62 *
63 * @param string $adr Adresse de la base de données {@example 'localhost'}
64 * @param string $port Numéro de port
65 * @param string $login Login de connexion
66 * @param string $pass Mot de passe de connexion
67 * @param string $base Nom de la base de données
68 * @param string $type Moteur SQL {@example 'sqlite3', 'mysql'}
69 * @param string $pref Préfixe des tables {@example 'spip'}
70 * @param string $ldap ?
71 * @return string
72 * Texte du fichier de connexion
73 *
74 **/
75 function install_connexion($adr, $port, $login, $pass, $base, $type, $pref, $ldap='')
76 {
77 $adr = addcslashes($adr,"'\\");
78 $port = addcslashes($port,"'\\");
79 $login = addcslashes($login,"'\\");
80 $pass = addcslashes($pass,"'\\");
81 $base = addcslashes($base,"'\\");
82 $type = addcslashes($type,"'\\");
83 $pref = addcslashes($pref,"'\\");
84 $ldap = addcslashes($ldap,"'\\");
85 return "\$GLOBALS['spip_connect_version'] = 0.7;\n"
86 . "spip_connect_db("
87 . "'$adr','$port','$login','$pass','$base'"
88 . ",'$type', '$pref','$ldap');\n";
89 }
90
91
92 /**
93 * Analyse un fichier de connexion à une base de données
94 *
95 * Le fichier contient normalement le resultat de la fonction install_connexion().
96 * L'analyse tient également compte des syntaxes des versions precedentes.
97 *
98 * @param $string $file
99 * Chemin du fichier de connexion à analyser
100 * @return array
101 * Tableau des informations sur la connexion
102 **/
103 function analyse_fichier_connection($file)
104 {
105 $s = @join('', file($file));
106 if (preg_match("#mysql_connect\([\"'](.*)[\"'],[\"'](.*)[\"'],[\"'](.*)[\"']\)#", $s, $regs)) {
107 array_shift($regs);
108 return $regs;
109 } else {
110 $ar = '\s*\'([^\']*)\'';
111 $r = '\s*,' . $ar;
112 $r = "#spip_connect_db[(]$ar$r$r$r$r(?:$r(?:$r(?:$r)?)?)?#";
113 if (preg_match($r, $s, $regs)) {
114 $regs[2] = $regs[1] . (!$regs[2] ? '' : ":$port_db;");
115 array_shift($regs);
116 array_shift($regs);
117 return $regs;
118 }
119 }
120 spip_log("$file n'est pas un fichier de connexion");
121 return array();
122 }
123
124 /**
125 * Liste les connecteurs aux bases SQL disponibles
126 *
127 * Dans le code SPIP ces connecteurs sont souvent appelés $connect ou $serveur
128 *
129 * @example
130 * $bases = bases_referencees(_FILE_CONNECT_TMP);
131 *
132 * @param $string $exclu
133 * Exclure un connecteur particulier (nom du fichier)
134 * @return array
135 * Liste des noms de connecteurs
136 **/
137 function bases_referencees($exclu='')
138 {
139 $tables = array();
140 foreach(preg_files(_DIR_CONNECT, '.php$') as $f) {
141 if ($f != $exclu AND analyse_fichier_connection($f))
142 $tables[]= basename($f, '.php');
143 }
144 return $tables;
145 }
146
147
148 function install_mode_appel($server_db, $tout=true)
149 {
150 return ($server_db != 'mysql') ? ''
151 : (($tout ? test_rappel_nom_base_mysql($server_db) : '')
152 . test_sql_mode_mysql($server_db) );
153 }
154
155 //
156 // Verifier que l'hebergement est compatible SPIP ... ou l'inverse :-)
157 // (sert a l'etape 1 de l'installation)
158 // http://doc.spip.org/@tester_compatibilite_hebergement
159 function tester_compatibilite_hebergement() {
160 $err = array();
161
162 $p = phpversion();
163 if (preg_match(',^([0-9]+)\.([0-9]+)\.([0-9]+),', $p, $regs)) {
164 $php = array($regs[1], $regs[2], $regs[3]);
165 $m = '5.1.0';
166 $min = explode('.', $m);
167 if ($php[0]<$min[0]
168 OR ($php[0]==$min[0] AND $php[1]<$min[1])
169 OR ($php[0]==$min[0] AND $php[1]==$min[1] AND $php[2]<$min[2]))
170 $err[] = _T('install_php_version', array('version' => $p, 'minimum' => $m));
171 }
172
173 // Si on n'a pas la bonne version de PHP, c'est la fin
174 if ($err)
175 die("<div class='error'>"
176 . "<h3>"._T('avis_attention').'</h3><p>'._T('install_echec_annonce')."</p><ul class='spip'>"
177 . "<li><strong>{$err[0]}</strong></li>\n</ul></div>");
178
179 // Il faut une base de donnees tout de meme ...
180 $serveurs = install_select_serveur();
181 if (!$serveurs)
182 $err[] = _T('install_extension_php_obligatoire')
183 . " <a href='http://www.php.net/mysql'>MYSQL</a>"
184 . "| <a href='http://www.php.net/pgsql'>PostgreSQL</a>"
185 . "| <a href='http://www.php.net/sqlite'>SQLite</a>";
186
187 // et il faut preg
188 if (!function_exists('preg_match_all'))
189 $err[] = _T('install_extension_php_obligatoire')
190 . " <a href='http://se.php.net/pcre'>PCRE</a>";
191
192 // et surtout pas ce mbstring.overload
193 if ($a = @ini_get('mbstring.func_overload'))
194 $err[] = _T('install_extension_mbstring')
195 . "mbstring.func_overload=$a - <a href='http://www.php.net/mb_string'>mb_string</a>.<br /><small>";
196
197 if ($err) {
198 echo "<div class='error'>"
199 ."<h3>"._T('avis_attention').'</h3><p>'._T('install_echec_annonce')."</p><ul class='spip'>";
200 foreach($err as $e)
201 echo "<li><strong>$e</strong></li>\n";
202
203 # a priori ici on pourrait die(), mais il faut laisser la possibilite
204 # de forcer malgre tout (pour tester, ou si bug de detection)
205 echo "</ul></div>\n";
206 }
207 }
208
209
210 // Une fonction pour faciliter la recherche du login (superflu ?)
211 // http://doc.spip.org/@login_hebergeur
212 function login_hebergeur() {
213 global $HTTP_X_HOST, $REQUEST_URI, $SERVER_NAME, $HTTP_HOST;
214
215 $base_hebergeur = 'localhost'; # par defaut
216
217 // Lycos (ex-Multimachin)
218 if ($HTTP_X_HOST == 'membres.lycos.fr') {
219 preg_match(',^/([^/]*),', $REQUEST_URI, $regs);
220 $login_hebergeur = $regs[1];
221 }
222 // Altern
223 else if (preg_match(',altern\.com$,', $SERVER_NAME)) {
224 preg_match(',([^.]*\.[^.]*)$,', $HTTP_HOST, $regs);
225 $login_hebergeur = preg_replace('[^\w\d]', '_', $regs[1]);
226 }
227 // Free
228 else if (preg_match(',(.*)\.free\.fr$,', $SERVER_NAME, $regs)) {
229 $base_hebergeur = 'sql.free.fr';
230 $login_hebergeur = $regs[1];
231 } else $login_hebergeur = '';
232
233 return array($base_hebergeur, $login_hebergeur);
234 }
235
236
237 // http://doc.spip.org/@info_etape
238 function info_etape($titre, $complement = ''){
239 return "<h2>".$titre."</h2>\n" .
240 ($complement ? "".$complement."\n":'');
241 }
242
243 // http://doc.spip.org/@bouton_suivant
244 function bouton_suivant($code = '') {
245 if($code=='') $code = _T('bouton_suivant');
246 static $suivant = 0;
247 $id = 'suivant'.(($suivant>0)?strval($suivant):'');
248 $suivant +=1;
249 return "\n<p class='boutons suivant'><input id='".$id."' type='submit'\nvalue=\"" .
250 $code .
251 " >>\" /></p>\n";
252 }
253
254 // http://doc.spip.org/@info_progression_etape
255 function info_progression_etape($en_cours,$phase,$dir, $erreur = false){
256 //$en_cours = _request('etape')?_request('etape'):"";
257 $liste = find_all_in_path($dir,$phase.'(([0-9])+|fin)[.]php$');
258 $debut = 1; $etat = "ok";
259 $last = count($liste);
260 // $texte_etat = array('ok'=>'OK','encours'=>_T('en_cours'),'todo'=>_T('todo'));
261
262 $intitule_etat["etape_"][1] = typo(_T('info_connexion_base_donnee'));
263 $intitule_etat["etape_"][2] = typo(_T('menu_aide_installation_choix_base'));
264 $intitule_etat["etape_"][3] = typo(_T('info_informations_personnelles'));
265 $intitule_etat["etape_"][4] = typo(_T('info_derniere_etape'));
266
267 $intitule_etat["etape_ldap"][1] = typo(_T('titre_connexion_ldap'));
268 $intitule_etat["etape_ldap"][2] = typo(_T('titre_connexion_ldap'));
269 $intitule_etat["etape_ldap"][3] = typo(_T('info_chemin_acces_1'));
270 $intitule_etat["etape_ldap"][4] = typo(_T('info_reglage_ldap'));
271 $intitule_etat["etape_ldap"][5] = typo(_T('info_ldap_ok'));
272
273 // $aff_etapes = "<span id='etapes'>";
274
275 $aff_etapes = "<ul id='infos_etapes' class='infos_$phase$en_cours'>";
276
277 foreach($liste as $etape=>$fichier){
278 if ($debut < $last) {
279 if ($debut == $en_cours && $erreur) $class = "on erreur";
280 else if ($debut == $en_cours) $class = "on";
281 else if ($debut > $en_cours) $class = "prochains";
282 else $class = "valides";
283
284 $aff_etapes .= "<li class='$class'><div class='fond'>";
285 $aff_etapes .= ($debut == $en_cours)?"<strong>":'';
286 $aff_etapes .= "<em>"._T('etape')." </em><span class='numero_etape'>$debut</span><em>&nbsp;: </em>";
287 $aff_etapes .= $intitule_etat["$phase"][$debut];
288 $aff_etapes .= ($debut == $en_cours)?"</strong>":'';
289 $aff_etapes .= "</div></li>";
290 }
291 $debut++;
292 }
293 $aff_etapes .= "</ul>";
294 $aff_etapes .= "<br class='nettoyeur' />\n";
295 return $aff_etapes;
296 }
297
298
299 // http://doc.spip.org/@fieldset
300 function fieldset($legend, $champs = array(), $apres='', $avant='') {
301 return "<fieldset>\n" .
302 $avant .
303 ($legend ? "<legend>".$legend."</legend>\n" : '') .
304 fieldset_champs($champs) .
305 $apres .
306 "</fieldset>\n";
307 }
308
309 function fieldset_champs($champs = array())
310 {
311 $fieldset = '';
312 foreach ($champs as $nom => $contenu) {
313 $type = isset($contenu['hidden']) ? 'hidden' : (preg_match(',^pass,', $nom) ? 'password' : 'text');
314 $class = isset($contenu['hidden']) ? '' : "class='formo' size='40' ";
315 if(isset($contenu['alternatives'])) {
316 $fieldset .= $contenu['label'] ."\n";
317 foreach($contenu['alternatives'] as $valeur => $label) {
318 $fieldset .= "<input type='radio' name='".$nom .
319 "' id='$nom-$valeur' value='$valeur'"
320 .(($valeur==$contenu['valeur'])?"\nchecked='checked'":'')
321 ."/>\n";
322 $fieldset .= "<label for='$nom-$valeur'>".$label."</label>\n";
323 }
324 $fieldset .= "<br />\n";
325 }
326 else {
327 $fieldset .= "<label for='".$nom."'>".$contenu['label']."</label>\n";
328 $fieldset .= "<input ".$class."type='".$type."' id='" . $nom . "' name='".$nom."'\nvalue='".$contenu['valeur']."'"
329 .(preg_match(',^(pass|login),', $nom)?" autocomplete='off'":'')
330 . ((isset($contenu['required']) AND $contenu['required'])?" required='required'":"")
331 . " />\n";
332 }
333 }
334 return $fieldset;
335 }
336
337 function install_select_serveur()
338 {
339 $options = array();
340 $dir = _DIR_RESTREINT . 'req/';
341 $d = @opendir($dir);
342 if (!$d) return array();
343 while ($f = readdir($d)) {
344 if ((preg_match('/^(.*)[.]php$/', $f, $s))
345 AND is_readable($f = $dir . $f)) {
346 require_once($f);
347 $s = $s[1];
348 $v = 'spip_versions_' . $s;
349 if (function_exists($v) AND $v()) {
350 $titre = _T("install_select_type_$s");
351 // proposer sqlite3 par defaut si dispo
352 $selected = ($s=='sqlite3'?" selected='selected'":"");
353 $options[$s] = "<option value='$s'$selected>"
354 . ($titre ? $titre : $s)
355 ."</option>";
356 } else spip_log("$s: portage indisponible");
357 }
358 }
359 sort($options);
360 return $options;
361 }
362
363 // http://doc.spip.org/@install_connexion_form
364 function install_connexion_form($db, $login, $pass, $predef, $hidden, $etape, $jquery=true)
365 {
366 $server_db = (is_string($predef[0])) ? $predef[0] : '';
367
368 return generer_form_ecrire('install', (
369 "\n<input type='hidden' name='etape' value='$etape' />"
370 . $hidden
371 . (_request('echec')?
372 ("<p><b>"._T('avis_connexion_echec_1').
373 "</b></p><p>"._T('avis_connexion_echec_2')."</p><p style='font-size: small;'>"._T('avis_connexion_echec_3')."</p>")
374 :"")
375
376 . ($jquery?http_script('', 'jquery.js'):'')
377 . http_script('
378 $(document).ready(function() {
379 $("input[type=hidden][name=server_db]").each(function(){
380 if ($(this).attr("value").match("sqlite*")){
381 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").hide();
382 }
383 });
384 if ($("#sql_serveur_db").length) {
385 if ($("#sql_serveur_db").attr("value").match("sqlite*"))
386 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").hide();
387 else
388 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").show();
389 $("#sql_serveur_db").change(function(){
390 if ($(this).find("option:selected").attr("value").match("sqlite*"))
391 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").hide();
392 else
393 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").show();
394 });
395 }
396 });')
397
398 . ($server_db
399 ? '<input type="hidden" name="server_db" value="'.$server_db.'" />'
400 . (($predef[0])
401 ?('<h3>'._T('install_serveur_hebergeur').'</h3>')
402 :'')
403 : ('<fieldset><legend>'
404 ._T('install_select_type_db')
405 . "</legend>"
406 .'<label for="sql_serveur_db" class="p">'
407 . _T('install_types_db_connus')
408 // Passer l'avertissement SQLIte en commentaire, on pourra facilement le supprimer par la suite sans changer les traductions.
409 . "<br /><small>(". _T('install_types_db_connus_avertissement') .')</small>'
410 .'</label>'
411 . "\n<div class='p center'><select name='server_db' id='sql_serveur_db' >\n"
412 . join("\n", install_select_serveur())
413 . "\n</select></div></fieldset>")
414 )
415 . '<div id="install_adresse_base_hebergeur">'
416 . '<p>'. _T('texte_connexion_mysql').'</p>'
417 . ($predef[1]
418 ? '<h3>'._T('install_adresse_base_hebergeur').'</h3>'
419 : fieldset(_T('entree_base_donnee_1'),
420 array(
421 'adresse_db' => array(
422 'label' => $db[1],
423 'valeur' => $db[0]
424 ),
425 )
426 )
427 )
428 . '</div>'
429
430 . '<div id="install_login_base_hebergeur">'
431 . ($predef[2]
432 ? '<h3>'._T('install_login_base_hebergeur').'</h3>'
433 : fieldset(_T('entree_login_connexion_1'),
434 array(
435 'login_db' => array(
436 'label' => $login[1],
437 'valeur' => $login[0]
438 ),
439 )
440 )
441 )
442 . '</div>'
443
444 . '<div id="install_pass_base_hebergeur">'
445 . ($predef[3]
446 ? '<h3>'._T('install_pass_base_hebergeur').'</h3>'
447 : fieldset(_T('entree_mot_passe_1'),
448 array(
449 'pass_db' => array(
450 'label' => $pass[1],
451 'valeur' => $pass[0]
452 ),
453 )
454 )
455 )
456 . '</div>'
457
458 . bouton_suivant()));
459
460 }
461
462 // 4 valeurs qu'on reconduit d'un script a l'autre
463 // sauf s'ils sont predefinis.
464
465 // http://doc.spip.org/@predef_ou_cache
466 function predef_ou_cache($adresse_db, $login_db, $pass_db, $server_db)
467 {
468 return ((defined('_INSTALL_HOST_DB'))
469 ? ''
470 : "\n<input type='hidden' name='adresse_db' value=\"".spip_htmlspecialchars($adresse_db)."\" />"
471 )
472 . ((defined('_INSTALL_USER_DB'))
473 ? ''
474 : "\n<input type='hidden' name='login_db' value=\"".spip_htmlspecialchars($login_db)."\" />"
475 )
476 . ((defined('_INSTALL_PASS_DB'))
477 ? ''
478 : "\n<input type='hidden' name='pass_db' value=\"".spip_htmlspecialchars($pass_db)."\" />"
479 )
480
481 . ((defined('_INSTALL_SERVER_DB'))
482 ? ''
483 : "\n<input type='hidden' name='server_db' value=\"".spip_htmlspecialchars($server_db)."\" />"
484 );
485 }
486
487 // presentation des bases existantes
488
489 // http://doc.spip.org/@install_etape_liste_bases
490 function install_etape_liste_bases($server_db, $login_db, $disabled=array())
491 {
492 $bases = $checked = array();
493 $noms = sql_listdbs($server_db);
494 if (!$noms) return '';
495
496 foreach ($noms as $nom){
497 $id = spip_htmlspecialchars($nom);
498 $dis = in_array($nom, $disabled) ? " disabled='disabled'" : '';
499 $base = " name=\"choix_db\" value=\""
500 . $nom
501 . '"'
502 . $dis
503 . " type='radio' id='$id'";
504 $label = "<label for='$id'>"
505 . ($dis ? "<i>$nom</i>" : $nom)
506 . "</label>";
507
508 if (!$checked AND !$dis AND
509 (($nom == $login_db) OR
510 ($GLOBALS['table_prefix'] == $nom))) {
511 $checked = "<input$base checked='checked' />\n$label";
512 } else {
513 $bases[]= "<input$base />\n$label";
514 }
515 }
516
517 if (!$bases && !$checked) return false;
518
519 if ($checked) {array_unshift($bases, $checked); $checked = true;}
520
521 return array($checked, $bases);
522 }
523
524 function install_propager($hidden)
525 {
526 $res = '';
527 foreach($hidden as $k) {
528 $v = spip_htmlentities(_request($k));
529 $res .= "<input type='hidden' name='$k' value='$v' />";
530 }
531 return $res;
532 }
533 ?>