3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 * Gestion de l'installation de SPIP
16 * @package SPIP\Core\Installation
19 if (!defined('_ECRIRE_INC_VERSION')) {
25 * Écrit un fichier PHP nécessitant SPIP
27 * Écrit le texte transmis dans un fichier PHP. Cette fonction
28 * ajoute les entêtes PHP et le test de sécurité vérifiant que SPIP
33 * install_fichier_connexion(_FILE_CONNECT_TMP, $contenu);
37 * Renommer cette fonction qui peut servir à d'autres utilisations ?
40 * Chemin du fichier à créer
41 * @param string $texte
42 * Code source du fichier (sans l'ouverture/fermeture PHP)
45 function install_fichier_connexion($nom, $texte) {
46 $texte = "<" . "?php\n"
47 . "if (!defined(\"_ECRIRE_INC_VERSION\")) return;\n"
51 ecrire_fichier($nom, $texte);
56 * Retourne le code source d'un fichier de connexion à une base de données
58 * Le code est un appel à la fonction spip_connect_db()
60 * @see spip_connect_db()
63 * Attention etape_ldap4 suppose qu'il n'y aura qu'un seul appel de fonction
64 * dans le fichier produit.
66 * @param string $adr Adresse de la base de données {@example 'localhost'}
67 * @param string $port Numéro de port
68 * @param string $login Login de connexion
69 * @param string $pass Mot de passe de connexion
70 * @param string $base Nom de la base de données
71 * @param string $type Moteur SQL {@example 'sqlite3', 'mysql'}
72 * @param string $pref Préfixe des tables {@example 'spip'}
73 * @param string $ldap Type d'authentification (cas si 'ldap')
74 * @param string $charset Charset de la connexion SQL
76 * Texte du fichier de connexion
79 function install_connexion($adr, $port, $login, $pass, $base, $type, $pref, $ldap = '', $charset = '') {
80 $adr = addcslashes($adr, "'\\");
81 $port = addcslashes($port, "'\\");
82 $login = addcslashes($login, "'\\");
83 $pass = addcslashes($pass, "'\\");
84 $base = addcslashes($base, "'\\");
85 $type = addcslashes($type, "'\\");
86 $pref = addcslashes($pref, "'\\");
87 $ldap = addcslashes($ldap, "'\\");
88 $charset = addcslashes($charset, "'\\");
90 return "\$GLOBALS['spip_connect_version'] = 0.8;\n"
92 . "'$adr','$port','$login','$pass','$base'"
93 . ",'$type', '$pref','$ldap','$charset');\n";
98 * Analyse un fichier de connexion à une base de données
100 * Le fichier contient normalement le résultat de la fonction install_connexion().
101 * L'analyse tient également compte des syntaxes des versions précédentes.
103 * @param string $file
104 * Chemin du fichier de connexion à analyser
106 * Tableau des informations sur la connexion
108 function analyse_fichier_connection($file) {
109 $s = @join
('', file($file));
110 if (preg_match("#mysql_connect\([\"'](.*)[\"'],[\"'](.*)[\"'],[\"'](.*)[\"']\)#", $s, $regs)) {
115 $ar = '\s*\'([^\']*)\'';
117 $r = "#spip_connect_db[(]$ar$r$r$r$r(?:$r(?:$r(?:$r(?:$r)?)?)?)?#";
118 if (preg_match($r, $s, $regs)) {
119 $regs[2] = $regs[1] . (!$regs[2] ?
'' : ":" . $regs[2] . ";");
126 spip_log("$file n'est pas un fichier de connexion");
132 * Liste les connecteurs aux bases SQL disponibles
134 * Dans le code SPIP ces connecteurs sont souvent appelés $connect ou $serveur
137 * $bases = bases_referencees(_FILE_CONNECT_TMP);
139 * @param string $exclu
140 * Exclure un connecteur particulier (nom du fichier)
142 * Liste des noms de connecteurs
144 function bases_referencees($exclu = '') {
146 foreach (preg_files(_DIR_CONNECT
, '.php$') as $f) {
147 if ($f != $exclu and analyse_fichier_connection($f)) {
148 $tables[] = basename($f, '.php');
156 function install_mode_appel($server_db, $tout = true) {
157 return ($server_db != 'mysql') ?
''
158 : (($tout ?
test_rappel_nom_base_mysql($server_db) : '')
159 . test_sql_mode_mysql($server_db));
163 // Verifier que l'hebergement est compatible SPIP ... ou l'inverse :-)
164 // (sert a l'etape 1 de l'installation)
165 // http://code.spip.net/@tester_compatibilite_hebergement
166 function tester_compatibilite_hebergement() {
170 if (version_compare($p, _PHP_MIN
, '<')) {
171 $err[] = _T('install_php_version', array('version' => $p, 'minimum' => _PHP_MIN
));
174 // Si on n'a pas la bonne version de PHP, c'est la fin
176 die("<div class='error'>"
177 . "<h3>" . _T('avis_attention') . '</h3><p>' . _T('install_echec_annonce') . "</p><ul class='spip'>"
178 . "<li><strong>{$err[0]}</strong></li>\n</ul></div>");
181 // Il faut une base de donnees tout de meme ...
182 $serveurs = install_select_serveur();
184 $err[] = _T('install_extension_php_obligatoire')
185 . " <a href='http://www.php.net/mysql'>MYSQL</a>"
186 . "| <a href='http://www.php.net/pgsql'>PostgreSQL</a>"
187 . "| <a href='http://www.php.net/sqlite'>SQLite</a>";
191 if (!function_exists('preg_match_all')) {
192 $err[] = _T('install_extension_php_obligatoire')
193 . " <a href='http://se.php.net/pcre'>PCRE</a>";
196 // et surtout pas ce mbstring.overload
197 if ($a = @ini_get
('mbstring.func_overload')) {
198 $err[] = _T('install_extension_mbstring')
199 . "mbstring.func_overload=$a - <a href='http://www.php.net/mb_string'>mb_string</a>.<br /><small>";
203 echo "<div class='error'>"
204 . "<h3>" . _T('avis_attention') . '</h3><p>' . _T('install_echec_annonce') . "</p><ul class='spip'>";
205 foreach ($err as $e) {
206 echo "<li><strong>$e</strong></li>\n";
209 # a priori ici on pourrait die(), mais il faut laisser la possibilite
210 # de forcer malgre tout (pour tester, ou si bug de detection)
211 echo "</ul></div>\n";
217 * Faciliter la recherche du login d'installation en fonction de certains hébergeurs connus
221 function login_hebergeur() {
222 $base_hebergeur = 'localhost'; # par defaut
225 if (preg_match(',(.*)\.free\.fr$,', $_SERVER['SERVER_NAME'], $regs)) {
226 $base_hebergeur = 'sql.free.fr';
227 $login_hebergeur = $regs[1];
229 $login_hebergeur = '';
232 return array($base_hebergeur, $login_hebergeur);
236 // http://code.spip.net/@info_etape
237 function info_etape($titre, $complement = '') {
238 return "<h2>" . $titre . "</h2>\n" .
239 ($complement ?
"" . $complement . "\n" : '');
243 * Retourne le code HTML d'un bouton `suivant>>` pour les phases d'installation
245 * @param string $code Texte du bouton
246 * @return string Code HTML du bouton
248 function bouton_suivant($code = '') {
250 $code = _T('bouton_suivant');
253 $id = 'suivant' . (($suivant > 0) ?
strval($suivant) : '');
256 return "\n<p class='boutons suivant'><input id='" . $id . "' type='submit'\nvalue=\"" .
261 // http://code.spip.net/@info_progression_etape
262 function info_progression_etape($en_cours, $phase, $dir, $erreur = false) {
263 //$en_cours = _request('etape')?_request('etape'):"";
264 $liste = find_all_in_path($dir, $phase . '(([0-9])+|fin)[.]php$');
267 $last = count($liste);
268 // $texte_etat = array('ok'=>'OK','encours'=>_T('en_cours'),'todo'=>_T('todo'));
270 $intitule_etat["etape_"][1] = typo(_T('info_connexion_base_donnee'));
271 $intitule_etat["etape_"][2] = typo(_T('menu_aide_installation_choix_base'));
272 $intitule_etat["etape_"][3] = typo(_T('info_informations_personnelles'));
273 $intitule_etat["etape_"][4] = typo(_T('info_derniere_etape'));
275 $intitule_etat["etape_ldap"][1] = typo(_T('titre_connexion_ldap'));
276 $intitule_etat["etape_ldap"][2] = typo(_T('titre_connexion_ldap'));
277 $intitule_etat["etape_ldap"][3] = typo(_T('info_chemin_acces_1'));
278 $intitule_etat["etape_ldap"][4] = typo(_T('info_reglage_ldap'));
279 $intitule_etat["etape_ldap"][5] = typo(_T('info_ldap_ok'));
281 // $aff_etapes = "<span id='etapes'>";
283 $aff_etapes = "<ul id='infos_etapes' class='infos_$phase$en_cours'>";
285 foreach ($liste as $etape => $fichier) {
286 if ($debut < $last) {
287 if ($debut == $en_cours && $erreur) {
288 $class = "on erreur";
290 if ($debut == $en_cours) {
293 if ($debut > $en_cours) {
294 $class = "prochains";
301 $aff_etapes .= "<li class='$class'><div class='fond'>";
302 $aff_etapes .= ($debut == $en_cours) ?
"<strong>" : '';
303 $aff_etapes .= "<em>" . _T('etape') . " </em><span class='numero_etape'>$debut</span><em> : </em>";
304 $aff_etapes .= $intitule_etat["$phase"][$debut];
305 $aff_etapes .= ($debut == $en_cours) ?
"</strong>" : '';
306 $aff_etapes .= "</div></li>";
310 $aff_etapes .= "</ul>";
311 $aff_etapes .= "<br class='nettoyeur' />\n";
317 // http://code.spip.net/@fieldset
318 function fieldset($legend, $champs = array(), $apres = '', $avant = '') {
319 return "<fieldset>\n" .
321 ($legend ?
"<legend>" . $legend . "</legend>\n" : '') .
322 fieldset_champs($champs) .
327 function fieldset_champs($champs = array()) {
329 foreach ($champs as $nom => $contenu) {
330 $type = isset($contenu['hidden']) ?
'hidden' : (preg_match(',^pass,', $nom) ?
'password' : 'text');
331 $class = isset($contenu['hidden']) ?
'' : "class='formo' size='40' ";
332 if (isset($contenu['alternatives'])) {
333 $fieldset .= $contenu['label'] . "\n";
334 foreach ($contenu['alternatives'] as $valeur => $label) {
335 $fieldset .= "<input type='radio' name='" . $nom .
336 "' id='$nom-$valeur' value='$valeur'"
337 . (($valeur == $contenu['valeur']) ?
"\nchecked='checked'" : '')
339 $fieldset .= "<label for='$nom-$valeur'>" . $label . "</label>\n";
341 $fieldset .= "<br />\n";
343 $fieldset .= "<label for='" . $nom . "'>" . $contenu['label'] . "</label>\n";
344 $fieldset .= "<input " . $class . "type='" . $type . "' id='" . $nom . "' name='" . $nom . "'\nvalue='" . $contenu['valeur'] . "'"
345 . (preg_match(',^(pass|login),', $nom) ?
" autocomplete='off'" : '')
346 . ((isset($contenu['required']) and $contenu['required']) ?
" required='required'" : "")
354 function install_select_serveur() {
356 $dir = _DIR_RESTREINT
. 'req/';
361 while (($f = readdir($d)) !== false) {
362 if ((preg_match('/^(.*)[.]php$/', $f, $s))
363 and is_readable($f = $dir . $f)
367 $v = 'spip_versions_' . $s;
368 if (function_exists($v) and $v()) {
369 $titre = _T("install_select_type_$s");
370 // proposer mysql par defaut si dispo
371 $checked = ($s == 'mysql' ?
" checked='checked'" : "");
372 $options[$s] = "<li><input type='radio' id='$s' value='$s' name='server_db'$checked>"
373 . "<label for='$s'>" . ($titre ?
$titre : $s) . "</label></li>";
375 spip_log("$s: portage indisponible");
384 // http://code.spip.net/@install_connexion_form
385 function install_connexion_form($db, $login, $pass, $predef, $hidden, $etape, $jquery = true) {
386 $server_db = (is_string($predef[0])) ?
$predef[0] : '';
388 return generer_form_ecrire('install', (
389 "\n<input type='hidden' name='etape' value='$etape' />"
391 . (_request('echec') ?
392 ("<p><b>" . _T('avis_connexion_echec_1') .
393 "</b></p><p>" . _T('avis_connexion_echec_2') . "</p><p style='font-size: small;'>" . _T('avis_connexion_echec_3') . "</p>")
396 . ($jquery ?
http_script('', 'jquery.js') : '')
399 $("input[type=hidden][name=server_db]").each(function(){
400 if ($(this).attr("value").match("sqlite*")){
401 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").hide();
404 if ($("input[name=server_db][checked]").attr("value").match("sqlite*"))
405 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").hide();
407 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").show();
408 $("input[name=server_db]").each(function(){
409 $(this).on("change",function(){
410 if ($(this).prop("checked") && $(this).attr("value").match("sqlite*")) {
411 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").hide();
413 if ($(this).prop("checked") && !$(this).attr("value").match("sqlite*")) {
414 $("#install_adresse_base_hebergeur,#install_login_base_hebergeur,#install_pass_base_hebergeur").show();
421 ?
'<input type="hidden" name="server_db" value="' . $server_db . '" />'
423 ?
('<h3>' . _T('install_serveur_hebergeur') . '</h3>')
425 : ('<fieldset><legend>'
426 . _T('install_select_type_db')
428 . '<p class="explication">'
429 . _T('install_types_db_connus')
430 // Passer l'avertissement SQLIte en commentaire, on pourra facilement le supprimer par la suite sans changer les traductions.
431 // . "<br /><small>(". _T('install_types_db_connus_avertissement') .')</small>'
433 . "\n<div class='p'>\n<ul>\n"
434 . join("\n", install_select_serveur())
435 . "\n</ul>\n</div></fieldset>")
437 . '<div id="install_adresse_base_hebergeur">'
438 . '<p>' . _T('texte_connexion_mysql') . '</p>'
440 ?
'<h3>' . _T('install_adresse_base_hebergeur') . '</h3>'
441 : fieldset(_T('entree_base_donnee_1'),
443 'adresse_db' => array(
452 . '<div id="install_login_base_hebergeur">'
454 ?
'<h3>' . _T('install_login_base_hebergeur') . '</h3>'
455 : fieldset(_T('entree_login_connexion_1'),
458 'label' => $login[1],
459 'valeur' => $login[0]
466 . '<div id="install_pass_base_hebergeur">'
468 ?
'<h3>' . _T('install_pass_base_hebergeur') . '</h3>'
469 : fieldset(_T('entree_mot_passe_1'),
480 . bouton_suivant()));
484 // 4 valeurs qu'on reconduit d'un script a l'autre
485 // sauf s'ils sont predefinis.
487 // http://code.spip.net/@predef_ou_cache
488 function predef_ou_cache($adresse_db, $login_db, $pass_db, $server_db) {
489 return ((defined('_INSTALL_HOST_DB'))
491 : "\n<input type='hidden' name='adresse_db' value=\"" . spip_htmlspecialchars($adresse_db) . "\" />"
493 . ((defined('_INSTALL_USER_DB'))
495 : "\n<input type='hidden' name='login_db' value=\"" . spip_htmlspecialchars($login_db) . "\" />"
497 . ((defined('_INSTALL_PASS_DB'))
499 : "\n<input type='hidden' name='pass_db' value=\"" . spip_htmlspecialchars($pass_db) . "\" />"
502 . ((defined('_INSTALL_SERVER_DB'))
504 : "\n<input type='hidden' name='server_db' value=\"" . spip_htmlspecialchars($server_db) . "\" />"
508 // presentation des bases existantes
510 // http://code.spip.net/@install_etape_liste_bases
511 function install_etape_liste_bases($server_db, $login_db, $disabled = array()) {
512 $bases = $checked = array();
513 $noms = sql_listdbs($server_db);
518 foreach ($noms as $nom) {
519 $id = spip_htmlspecialchars($nom);
520 $dis = in_array($nom, $disabled) ?
" disabled='disabled'" : '';
521 $base = " name=\"choix_db\" value=\""
525 . " type='radio' id='$id'";
526 $label = "<label for='$id'>"
527 . ($dis ?
"<i>$nom</i>" : $nom)
530 if (!$checked and !$dis and
531 (($nom == $login_db) or
532 ($GLOBALS['table_prefix'] == $nom))
534 $checked = "<input$base checked='checked' />\n$label";
536 $bases[] = "<input$base />\n$label";
540 if (!$bases && !$checked) {
545 array_unshift($bases, $checked);
549 return array($checked, $bases);
552 function install_propager($hidden) {
554 foreach ($hidden as $k) {
555 $v = spip_htmlentities(_request($k));
556 $res .= "<input type='hidden' name='$k' value='$v' />";