503)); exit; } /** * Fonction appelée par le fichier connecteur de base de données * crée dans `config/` à l'installation. * * Il contient un appel direct à cette fonction avec comme arguments * les identifants de connexion. * * Si la connexion reussit, la globale `db_ok` mémorise sa description. * C'est un tableau également retourné en valeur, pour les appels * lors de l'installation. * * @param string $host Adresse du serveur de base de données * @param string $port Port utilisé pour la connexion * @param string $login Identifiant de connexion à la base de données * @param string $pass Mot de passe pour cet identifiant * @param string $db Nom de la base de données à utiliser * @param string $type Type de base de données tel que 'mysql', 'sqlite3' (cf ecrire/req/) * @param string $prefixe Préfixe des tables SPIP * @param string $auth Type d'authentification (cas si 'ldap') * @param string $charset Charset de la connexion SQL (optionnel) * @return array Description de la connexion */ function spip_connect_db( $host, $port, $login, $pass, $db = '', $type = 'mysql', $prefixe = '', $auth = '', $charset = '' ) { // temps avant nouvelle tentative de connexion // suite a une connection echouee if (!defined('_CONNECT_RETRY_DELAY')) { define('_CONNECT_RETRY_DELAY', 30); } $f = ""; // un fichier de identifiant par combinaison (type,host,port,db) // pour ne pas declarer tout indisponible d'un coup // si en cours d'installation ou si db=@test@ on ne pose rien // car c'est un test de connexion if (!defined('_ECRIRE_INSTALL') and $db !== "@test@") { $f = _DIR_TMP . $type . '.' . substr(md5($host . $port . $db), 0, 8) . '.out'; } elseif ($db == '@test@') { $db = ''; } if ($f and @file_exists($f) and (time() - @filemtime($f) < _CONNECT_RETRY_DELAY) ) { spip_log("Echec : $f recent. Pas de tentative de connexion", _LOG_HS); return; } if (!$prefixe) { $prefixe = isset($GLOBALS['table_prefix']) ? $GLOBALS['table_prefix'] : $db; } $h = charger_fonction($type, 'req', true); if (!$h) { spip_log("les requetes $type ne sont pas fournies", _LOG_HS); return; } if ($g = $h($host, $port, $login, $pass, $db, $prefixe)) { if (!is_array($auth)) { // compatibilite version 0.7 initiale $g['ldap'] = $auth; $auth = array('ldap' => $auth); } $g['authentification'] = $auth; $g['type'] = $type; $g['charset'] = $charset; return $GLOBALS['db_ok'] = $g; } // En cas d'indisponibilite du serveur, eviter de le bombarder if ($f) { @touch($f); spip_log("Echec connexion serveur $type : host[$host] port[$port] login[$login] base[$db]", $type . '.' . _LOG_HS); } } /** * Première connexion au serveur principal de base de données * * Retourner le charset donnée par la table principale * mais vérifier que le fichier de connexion n'est pas trop vieux * * @note * Version courante = 0.8 * * - La version 0.8 indique un charset de connexion comme 9e arg * - La version 0.7 indique un serveur d'authentification comme 8e arg * - La version 0.6 indique le prefixe comme 7e arg * - La version 0.5 indique le serveur comme 6e arg * * La version 0.0 (non numerotée) doit être refaite par un admin. * Les autres fonctionnent toujours, même si : * * - la version 0.1 est moins performante que la 0.2 * - la 0.2 fait un include_ecrire('inc_db_mysql.php3'). * * @param array $connexion Description de la connexion * @param string $charset_sql_connexion charset de connexion fourni dans l'appal a spip_connect_db * @return string|bool|int * - false si pas de charset connu pour la connexion * - -1 charset non renseigné * - nom du charset sinon **/ function spip_connect_main($connexion, $charset_sql_connexion = '') { if ($GLOBALS['spip_connect_version'] < 0.1 and _DIR_RESTREINT) { include_spip('inc/headers'); redirige_url_ecrire('upgrade', 'reinstall=oui'); } if (!($f = $connexion['select'])) { return false; } // si le charset est fourni, l'utiliser if ($charset_sql_connexion) { return $charset_sql_connexion; } // sinon on regarde la table spip_meta // en cas d'erreur select retourne la requette (is_string=true donc) if (!$r = $f('valeur', 'spip_meta', "nom='charset_sql_connexion'") or is_string($r) ) { return false; } if (!($f = $connexion['fetch'])) { return false; } $r = $f($r); return ($r['valeur'] ? $r['valeur'] : -1); } /** * Connection à LDAP * * Fonction présente pour compatibilité * * @deprecated Utiliser l'authentification LDAP de auth/ldap * @uses auth_ldap_connect() * * @param string $serveur Nom du connecteur * @return array */ function spip_connect_ldap($serveur = '') { include_spip('auth/ldap'); return auth_ldap_connect($serveur); } /** * Échappement d'une valeur sous forme de chaîne PHP * * Échappe une valeur (num, string, array) pour en faire une chaîne pour PHP. * Un `array(1,'a',"a'")` renvoie la chaine `"'1','a','a\''"` * * @note * L'usage comme échappement SQL est déprécié, à remplacer par sql_quote(). * * @param num|string|array $a Valeur à échapper * @return string Valeur échappée. **/ function _q($a) { return (is_numeric($a)) ? strval($a) : (!is_array($a) ? ("'" . addslashes($a) . "'") : join(",", array_map('_q', $a))); } /** * Récupérer le nom de la table de jointure `xxxx` sur l'objet `yyyy` * * @deprecated * Utiliser l'API editer_liens ou les tables de liaisons spip_xx_liens * ou spip_yy_liens selon. * * @param string $x Table de destination * @param string $y Objet source * @return array|string * - array : Description de la table de jointure si connue * - chaîne vide si non trouvé. **/ function table_jointure($x, $y) { $trouver_table = charger_fonction('trouver_table', 'base'); $xdesc = $trouver_table(table_objet($x)); $ydesc = $trouver_table(table_objet($y)); $ix = @$xdesc['key']["PRIMARY KEY"]; $iy = @$ydesc['key']["PRIMARY KEY"]; if ($table = $ydesc['tables_jointures'][$ix]) { return $table; } if ($table = $xdesc['tables_jointures'][$iy]) { return $table; } return ''; } /** * Echapper les textes entre ' ' ou " " d'une requête SQL * avant son pre-traitement * * On renvoi la query sans textes et les textes séparés, dans * leur ordre d'apparition dans la query * * @see query_reinjecte_textes() * * @param string $query * @return array */ function query_echappe_textes($query, $uniqid=null) { static $codeEchappements = null; if (is_null($codeEchappements)) { if (is_null($uniqid)) { $uniqid = uniqid(); } $uniqid = substr(md5($uniqid), 0, 4); $codeEchappements = ['\\\\' => "\x1@#{$uniqid}#@\x1", "\\'" => "\x2@#{$uniqid}#@\x2", '\\"' => "\x3@#{$uniqid}#@\x3", '%' => "\x4@#{$uniqid}#@\x4"]; } if ($query === null) { return $codeEchappements; } // si la query contient deja des codes d'echappement on va s'emmeler les pinceaux et donc on ne touche a rien // ce n'est pas un cas legitime foreach ($codeEchappements as $codeEchappement) { if (strpos($query, $codeEchappement) !== false) { return [$query, []]; } } $query_echappees = str_replace(array_keys($codeEchappements), array_values($codeEchappements), $query); if (preg_match_all("/('[^']*')|(\"[^\"]*\")/S", $query_echappees, $textes)) { $textes = reset($textes); $parts = array(); $currentpos = 0; $k = 0; while(count($textes)) { $part = array_shift($textes); $nextpos = strpos($query_echappees, $part, $currentpos); // si besoin recoller ensemble les doubles '' de sqlite (echappement des ') while (count($textes) and substr($part, -1) === "'") { $next = reset($textes); if (strpos($next, "'") === 0 and strpos($query_echappees, $part . $next, $currentpos) === $nextpos) { $part .= array_shift($textes); } else { break; } } $k++; $parts[$k] = array( 'texte' => $part, 'position' => $nextpos, 'placeholder' => '%'.$k.'$s', ); $currentpos = $nextpos + strlen($part); } // et on replace les parts une par une en commencant par la fin while ($k>0) { $query_echappees = substr_replace($query_echappees, $parts[$k]['placeholder'], $parts[$k]['position'], strlen($parts[$k]['texte'])); $k--; } $textes = array_column($parts, 'texte'); } else { $textes = array(); } // si il reste des quotes simples ou doubles, c'est qu'on s'est emmelle les pinceaux // dans le doute on ne touche a rien if (strpbrk($query_echappees, "'\"") !== false) { return [$query, []]; } return [$query_echappees, $textes]; } /** * Réinjecter les textes d'une requete SQL à leur place initiale, * après traitement de la requête * * @see query_echappe_textes() * * @param string $query * @param array $textes * @return string */ function query_reinjecte_textes($query, $textes) { // recuperer les codes echappements $codeEchappements = query_echappe_textes(null); switch (count($textes)) { case 0: break; case 1: $query = sprintf($query, $textes[0]); break; case 2: $query = sprintf($query, $textes[0], $textes[1]); break; case 3: $query = sprintf($query, $textes[0], $textes[1], $textes[2]); break; case 4: $query = sprintf($query, $textes[0], $textes[1], $textes[2], $textes[3]); break; case 5: $query = sprintf($query, $textes[0], $textes[1], $textes[2], $textes[3], $textes[4]); break; default: array_unshift($textes, $query); $query = call_user_func_array('sprintf', $textes); break; } $query = str_replace(array_values($codeEchappements), array_keys($codeEchappements), $query); return $query; } /** * Exécute une requête sur le serveur SQL * * @see sql_query() * @deprecated Pour compatibilité. Utiliser `sql_query()` ou l'API `sql_*`. * * @param string $query Texte de la requête * @param string $serveur Nom du connecteur pour la base de données * @return bool|mixed * - false si on ne peut pas exécuter la requête * - indéfini sinon. **/ function spip_query($query, $serveur = '') { $f = spip_connect_sql($GLOBALS['spip_sql_version'], 'query', $serveur, true); return function_exists($f) ? $f($query, $serveur) : false; }