From 11f99a1d8a8015e997da79f9a9d939f53f3f64c5 Mon Sep 17 00:00:00 2001 From: Matthieu Marcillaud <marcimat@rezo.net> Date: Mon, 10 Dec 2007 13:42:32 +0000 Subject: [PATCH] Avec les fichiers sqlite, c'est mieux ;) --- .gitattributes | 4 + ecrire/req/sqlite2.php | 30 + ecrire/req/sqlite3.php | 35 + ecrire/req/sqlite_fonctions.php | 224 ++++++ ecrire/req/sqlite_generique.php | 1169 +++++++++++++++++++++++++++++++ 5 files changed, 1462 insertions(+) create mode 100644 ecrire/req/sqlite2.php create mode 100644 ecrire/req/sqlite3.php create mode 100644 ecrire/req/sqlite_fonctions.php create mode 100644 ecrire/req/sqlite_generique.php diff --git a/.gitattributes b/.gitattributes index dc6507ef3f..0b0611cb9c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -721,6 +721,10 @@ ecrire/public/index.php -text ecrire/public/jointures.php -text ecrire/public/vertebrer.php -text ecrire/req/pg.php -text +ecrire/req/sqlite2.php -text +ecrire/req/sqlite3.php -text +ecrire/req/sqlite_fonctions.php -text +ecrire/req/sqlite_generique.php -text ecrire/rien.gif -text ecrire/typographie/en.php -text ecrire/typographie/fr.php -text diff --git a/ecrire/req/sqlite2.php b/ecrire/req/sqlite2.php new file mode 100644 index 0000000000..eaaac5a19f --- /dev/null +++ b/ecrire/req/sqlite2.php @@ -0,0 +1,30 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2007 * + * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * + * * + * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * + * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * +\***************************************************************************/ + +if (!defined("_ECRIRE_INC_VERSION")) return; + +include_spip('req/sqlite_generique'); + +$GLOBALS['spip_sqlite2_functions_1'] = _sqlite_ref_fonctions(); + + +function req_sqlite2_dist($addr, $port, $login, $pass, $db='', $prefixe='', $ldap='') { + return req_sqlite_dist($addr, $port, $login, $pass, $db, $prefixe, $ldap, $sqlite_version=2); +} + +function spip_sqlite2_constantes(){ + define('SPIP_SQLITE2_ASSOC', SQLITE_ASSOC); + define('SPIP_SQLITE2_NUM', SQLITE_NUM); + define('SPIP_SQLITE2_BOTH', SQLITE_BOTH); +} + +?> diff --git a/ecrire/req/sqlite3.php b/ecrire/req/sqlite3.php new file mode 100644 index 0000000000..09b7e27dda --- /dev/null +++ b/ecrire/req/sqlite3.php @@ -0,0 +1,35 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2007 * + * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * + * * + * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * + * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * +\***************************************************************************/ + +if (!defined("_ECRIRE_INC_VERSION")) return; + + + +include_spip('req/sqlite_generique'); + +$GLOBALS['spip_sqlite3_functions_1'] = _sqlite_ref_fonctions(); + + + +function req_sqlite3_dist($addr, $port, $login, $pass, $db='', $prefixe='', $ldap='') { + return req_sqlite_dist($addr, $port, $login, $pass, $db, $prefixe, $ldap, $sqlite_version=3); +} + + +function spip_sqlite3_constantes(){ + define('SPIP_SQLITE3_ASSOC', PDO::FETCH_ASSOC); + define('SPIP_SQLITE3_NUM', PDO::FETCH_NUM); + define('SPIP_SQLITE3_BOTH', PDO::FETCH_BOTH); +} + + +?> diff --git a/ecrire/req/sqlite_fonctions.php b/ecrire/req/sqlite_fonctions.php new file mode 100644 index 0000000000..6a1af2344e --- /dev/null +++ b/ecrire/req/sqlite_fonctions.php @@ -0,0 +1,224 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2007 * + * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * + * * + * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * + * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * +\***************************************************************************/ + + +/* + * Des fonctions pour les requetes SQL + * + */ +function _sqlite_init_functions(&$sqlite){ + + if (!$sqlite) return false; + + + $fonctions = array( + 'CONCAT' => array( '_sqlite_func_concat' ,2), + + 'DAYOFMONTH' => array( '_sqlite_func_dayofmonth' ,1), + + 'FIND_IN_SET' => array( '_sqlite_func_find_in_set' ,2), + + 'IF' => array( '_sqlite_func_if' ,3), + 'INSERT' => array( '_sqlite_func_insert' ,4), + 'INSTR' => array( '_sqlite_func_instr' ,2), + + 'LEAST' => array( '_sqlite_func_least' ,3), // nb d'arguments ? + 'LEFT' => array( '_sqlite_func_left' ,2), +# 'LENGTH' => array( 'strlen' ,1), // present v1.0.4 +# 'LOWER' => array( 'strtolower' ,1), // present v2.4 +# 'LTRIM' => array( 'ltrim' ,1), // present en theorie + + 'NOW' => array( '_sqlite_func_now' ,0), + + 'MD5' => array( 'md5' ,1), + 'MONTH' => array( '_sqlite_func_month' ,1), + + 'RAND' => array( '_sqlite_func_rand' ,0), // sinon random() v2.4 +# 'REGEXP' => array( '_sqlite_func_regexp' ,2), // critere REGEXP supporte a partir de v3.3.2 + 'REGEXP_REPLACE'=> array( '_sqlite_func_regexp_replace' ,3), + 'RIGHT' => array( '_sqlite_func_right' ,2), +# 'RTRIM' => array( 'rtrim' ,1), // present en theorie + + 'SETTYPE' => array( 'settype' ,2), // CAST present en v3.2.3 + + 'TO_DAYS' => array( '_sqlite_func_to_days' ,1), +# 'TRIM' => array( 'trim' ,1), // present en theorie + + 'UNIX_TIMESTAMP'=> array( '_sqlite_func_unix_timestamp' ,1), +# 'UPPER' => array( 'strtoupper' ,1), // present v2.4 + + 'VIDE' => array( '_sqlite_func_vide' ,0), // du vide pour SELECT 0 as x ... ORDER BY x -> ORDER BY vide() + + 'YEAR' => array( '_sqlite_func_year' ,1) + ); + + + foreach ($fonctions as $f=>$r){ + _sqlite_add_function($sqlite, $f, $r); + } + + #spip_log('functions sqlite chargees '); +} + +// permet au besoin de charger des fonctions ailleurs par _sqlite_init_functions(); +function _sqlite_add_function(&$sqlite, &$f, &$r){ + if (_sqlite_is_version(3, $sqlite)){ + isset($r[1]) + ?$sqlite->sqliteCreateFunction($f, $r[0], $r[1]) + :$sqlite->sqliteCreateFunction($f, $r[0]); + } else { + isset($r[1]) + ?sqlite_create_function($sqlite, $f, $r[0], $r[1]) + :sqlite_create_function($sqlite, $f, $r[0]); + } +} + +// +// SQLite : fonctions sqlite -> php +// entre autre auteurs : mlebas +// + +function _sqlite_func_concat ($a, $b) { + return $a.$b; +} + + +function _sqlite_func_dayofmonth ($d) { + if (!$d){ + $result = date("j"); + } else { + preg_match(";^([0-9]{4})-([0-9]+)-([0-9]+) .*$;", $d, $f); + $result = $f[3]; + } + #spip_log("Passage avec DAYOFMONTH : $d, $result",'debug'); + return $result; +} + + +function _sqlite_func_find_in_set($num, $set) { + $rank=0; + foreach (explode(",",$set) as $v) { + if ($v == $num) return (++$rank); + $rank++; + } + return 0; +} + + +function _sqlite_func_if ($bool, $oui, $non) { + return ($bool)?$oui:$non; +} + + +/* + * INSERT(chaine, index, longueur, chaine) MySQL + * Retourne une chaine de caracteres a partir d'une chaine dans laquelle "sschaine" + * a ete inseree a la position "index" en remplacant "longueur" caracteres. + */ +function _sqlite_func_insert ($s, $index, $longueur, $chaine) { + return + substr($s,0, $index) + . $chaine + . substr(substr($s, $index), $longueur); +} + + +function _sqlite_func_instr ($s, $search) { + return strpos($s,$search); +} + + +function _sqlite_func_least () { + $numargs = func_num_args(); + $arg_list = func_get_args(); + $least=$arg_list[0]; + for ($i = 0; $i < $numargs; $i++) { + if ($arg_list[$i] < $least) $least=$arg_list[$i]; + } + #spip_log("Passage avec LEAST : $least",'debug'); + return $least; +} + + +function _sqlite_func_left ($s, $lenght) { + return substr($s,$lenght); +} + + +function _sqlite_func_now(){ + $result = date("Y-m-d H:i:s", strtotime("now")); + #spip_log("Passage avec NOW : $result",'debug'); + return $result; +} + + +function _sqlite_func_month ($d) { + #spip_log("Passage avec MONTH : $d",'debug'); + if (!$d) return date("n"); + preg_match(";^([0-9]{4})-([0-9]+).*$;", $d, $f); + return $f[2]; +} + + +function _sqlite_func_rand() { + return rand(); +} + + +function _sqlite_func_right ($s, $lenght) { + return substr($s,0 - $lenght); +} + + +function _sqlite_func_regexp_replace($quoi, $cherche, $remplace) { + $return = preg_replace('%'.$cherche.'%', $remplace, $quoi); + #spip_log("regexp_replace : $quoi, $cherche, $remplace, $return",'debug'); + return $return; +} + + +function _sqlite_func_to_days ($d) { + $result = date("z", _sqlite_func_unix_timestamp($d)); + #spip_log("Passage avec TO_DAYS : $d, $result",'debug'); + return $result; +} + + +function _sqlite_func_unix_timestamp($d) { + //2005-12-02 20:53:53 + #spip_log("Passage avec UNIX_TIMESTAMP : $d",'debug'); + // mktime ( [int hour [, int minute [, int second [, int month [, int day [, int year [, int is_dst]]]]]]] ) + if (!$d) return mktime(); + preg_match(";^([0-9]{4})-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+).*$;", $d, $f); + return mktime($f[4],$f[5],$f[6],$f[2],$f[3],$f[1]); +} + + +function _sqlite_func_year ($d) { + if (!$d){ + $result = date("Y"); + } else { + preg_match(";^([0-9]{4}).*$;", $d, $f); + $result = $f[1]; + } + spip_log("Passage avec YEAR : $d, $result",'debug'); + return $result; +} + + +function _sqlite_func_vide(){ + return; +} + + + +?> diff --git a/ecrire/req/sqlite_generique.php b/ecrire/req/sqlite_generique.php new file mode 100644 index 0000000000..b3068efb9a --- /dev/null +++ b/ecrire/req/sqlite_generique.php @@ -0,0 +1,1169 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2007 * + * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * + * * + * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * + * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * +\***************************************************************************/ + +// infos : +// il ne faut pas avoir de PDO::CONSTANTE dans ce fichier sinon php4 se tue ! +// idem, il ne faut pas de $obj->toto()->toto sinon php4 se tue ! + +# todo : get/set_caracteres ? +# todo : REPAIR TABLE ? + + +/* + * + * regroupe le maximum de fonctions qui peuvent cohabiter + * D'abord les fonctions d'abstractions de SPIP + * + */ +function req_sqlite_dist($addr, $port, $login, $pass, $db='', $prefixe='', $ldap='', $sqlite_version=''){ + static $last_connect = array(); + + // si provient de selectdb + // un code pour etre sur que l'on vient de select_db() + if (strpos($db, $code = '@selectdb@')!==false) { + foreach (array('addr','port','login','pass','prefixe','ldap') as $a){ + $$a = $last_connect[$a]; + } + $db = str_replace($code, '', $db); + } + + /* + * En sqlite, seule l'adresse du fichier est importante. + * Ce sera $db le nom, et le path _DIR_DB + */ + _sqlite_init(); + + // un nom de base demande et impossible d'obtenir la base, on s'en va + if ($db && !is_file($f = _DIR_DB . $db . '.sqlite') && !is_writable(_DIR_DB)) + return false; + + + // charger les modules sqlite au besoin + if (!_sqlite_charger_version($sqlite_version)) { + spip_log("Impossible de trouver/charger le module SQLite ($sqlite_version)!"); + return false; + } + + // chargement des constantes + // il ne faut pas definir les constantes avant d'avoir charge les modules sqlite + $define = "spip_sqlite".$sqlite_version."_constantes"; + $define(); + + $ok = false; + if (!$db){ + // si installation -> base temporaire tant qu'on ne connait pas son vrai nom + if (_request('exec') == 'install'){ + // creation d'une base temporaire pour le debut d'install + $tmp = _DIR_DB . "_sqlite".$sqlite_version."_install.sqlite"; + if ($sqlite_version == 3) + $ok = $link = new PDO("sqlite:$tmp"); + else + $ok = $link = sqlite_open($tmp, _SQLITE_CHMOD, $err); + $db = "_sqlite".$sqlite_version."_install"; + // sinon, on arrete finalement + } else { + return false; + } + } else { + // Ouvrir (eventuellement creer la base) + // si pas de version fourni, on essaie la 3, sinon la 2 + if ($sqlite_version == 3) { + $ok = $link = new PDO("sqlite:$f"); + } else { + $ok = $link = sqlite_open($f, _SQLITE_CHMOD, $err); + } + } + + if (!$ok){ + spip_log("Impossible d'ouvrir la base de donnee SQLite ($sqlite_version) : $f "); + return false; + } + + if ($link) { + $last_connect = array ( + 'addr' => $addr, + 'port' => $port, + 'login' => $login, + 'pass' => $pass, + 'db' => $db, + 'prefixe' => $prefixe, + 'ldap' => $ldap + ); + } + + return array( + 'db' => $db, + 'prefixe' => $prefixe ? $prefixe : $db, + 'link' => $link, + 'ldap' => $ldap, + ); +} + + +// obsolete, ne plus utiliser +/* +function spip_query_db($query, $serveur='') { + return spip_sqlite_query($query, $serveur); +} +*/ + +// Fonction de requete generale, munie d'une trace a la demande +function spip_sqlite_query($query, $serveur='') { +#spip_log("spip_sqlite_query() > $query"); + _sqlite_init(); + + if (!($sqlite = _sqlite_link($serveur)) && (_request('exec')!='install')){ + spip_log("Aucune connexion sqlite (link)"); + return false; + } + + $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0]; + $prefixe = $connexion['prefixe']; + $db = $connexion['db']; + + // corriger la requete au format mysql->sqlite + // creer la requete de comptage (sqlite3) + $analyse = new sqlite_analyse_query($sqlite, $query, $db, $prefixe); + $analyse->creerLesRequetes(); + $query = $analyse->query; // pas indispensable car $query par & + $queryCount = $analyse->queryCount; + unset($analyse); + + $t = !isset($_GET['var_profile']) ? 0 : trace_query_start(); +#echo("<br /><b>spip_sqlite_query() $serveur >></b> $query"); // boum ? pourquoi ? + if ($sqlite){ + if (_sqlite_is_version(3, $sqlite)) { + $r = $sqlite->query($query); + + // comptage : oblige de compter le nombre d'entrees retournees par la requete + // aucune autre solution ne donne le nombre attendu :( ! + // particulierement s'il y a des LIMIT dans la requete. + if ($queryCount){ + if ($r) { + $l = $sqlite->query($queryCount); + $r->spipSqliteRowCount = count($l->fetchAll()); + } else { + $r->spipSqliteRowCount = 0; + } + } + } else { + $r = sqlite_query($sqlite, $query); + } + } else { + $r = false; + } + +#spip_log("spip_sqlite_query() >> $query"); // boum ? pourquoi ? + if (!$r){ + echo "<br /><small>#erreur serveur '$serveur' dans > $query</small><br />"; + echo "<br />- ".spip_sqlite_error($query, $serveur); + } + if (!$r && $e = spip_sqlite_errno($serveur)) // Log de l'erreur eventuelle + $e .= spip_sqlite_error($query, $serveur); // et du fautif + + return $t ? trace_query_end($query, $t, $r, $e) : $r; +} + + +/* ordre alphabetique pour les autres */ + +function spip_sqlite_alter($query, $serveur=''){ + return spip_sqlite_query("ALTER ".$query, $serveur); +} + + +// Fonction de creation d'une table SQL nommee $nom +function spip_sqlite_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $serveur='') { + + $query = $keys = $s = $p = ''; + + // certains plugins declarent les tables (permet leur inclusion dans le dump) + // sans les renseigner (laisse le compilo recuperer la description) + if (!is_array($champs) || !is_array($cles)) + return; + + // sqlite ne gere pas KEY tout court + foreach($cles as $k => $v) { + if ($k == "PRIMARY KEY"){ + $keys .= "$s\n\t\t$k ($v)"; + $p = $v; + } + $s = ","; + } + $s = ''; + + /* a tester ulterieurement + * je ne sais pas a quoi ca sert + * + $character_set = ""; + if (@$GLOBALS['meta']['charset_sql_base']) + $character_set .= " CHARACTER SET ".$GLOBALS['meta']['charset_sql_base']; + if (@$GLOBALS['meta']['charset_collation_sql_base']) + $character_set .= " COLLATE ".$GLOBALS['meta']['charset_collation_sql_base']; + */ + + // quelques remplacements + $num = "\s?(\([0-9]*)\)?"; + $enum = "\s?(\(.*)\)?"; + + $remplace = array( + // pour l'autoincrement, il faut des INTEGER NOT NULL PRIMARY KEY + '(big)?int(eger)?'.$num => 'INTEGER', + 'enum'.$enum => 'VARCHAR', + 'binary' => '' + ); + + $_replace = array(); + foreach ($remplace as $cle=>$val) + $_replace["/$cle/is"] = $val; + + $champs = preg_replace(array_keys($_replace), $_replace, $champs); + + foreach($champs as $k => $v) { + // je sais pas ce que c'est ca... + // puis personne rentre ici vue qe binary->'' + /* + if (preg_match(',([a-z]*\s*(\(\s*[0-9]*\s*\))?(\s*binary)?),i',$v,$defs)){ + if (preg_match(',(char|text),i',$defs[1]) AND !preg_match(',binary,i',$defs[1]) ){ + $v = $defs[1] . $character_set . ' ' . substr($v,strlen($defs[1])); + } + } + */ + + // autoincrement v3.1.3 ? + $query .= "$s\n\t\t$k $v"; + //. (($autoinc && ($p == $k) && preg_match(',\binteger\b,i', $v))? " AUTOINCREMENT": ''); + $s = ","; + } + + /* simuler le IF NOT EXISTS - version 2 */ + if (_sqlite_is_version(2, '', $serveur)){ + $a = spip_sqlite_showtable($nom, $serveur); + if ($a) return false; + } + + $temporary = $temporary ? ' TEMPORARY':''; + $ifnotexists = _sqlite_is_version(3, '', $serveur) ? ' IF NOT EXISTS':'';// IF NOT EXISTS + $q = "CREATE$temporary TABLE$ifnotexists $nom ($query" . ($keys ? ",$keys" : '') . ")" + //. ($character_set?" DEFAULT $character_set":"") + ."\n"; + + return spip_sqlite_query($q, $serveur); +} + + +// en PDO/sqlite3, il faut calculer le count par une requete count(*) +// pour les resultats de SELECT +// cela est fait sans spip_sqlite_query() +function spip_sqlite_count($r, $serveur='') { + if (!$r) return 0; + + if (_sqlite_is_version(3, '', $serveur)){ + // select ou autre (insert, update,...) ? + if (isset($r->spipSqliteRowCount)) { + // Ce compte est faux s'il y a des limit dans la requete :( + // il retourne le nombre d'enregistrements sans le limit + return $r->spipSqliteRowCount; + } else { + return $r->rowCount(); + } + } else { + return sqlite_num_rows($r); + } +} + + +function spip_sqlite_countsel($from = array(), $where = array(), $groupby = '', $limit = '', $sousrequete = '', $having = array(), $serveur='') { + $r = spip_sqlite_select('COUNT(*)', $from, $where,$groupby, '', $limit, + $having, $serveur); + + if ($r) { + if (_sqlite_is_version(3,'',$serveur)){ + list($r) = spip_sqlite_fetch($r, SPIP_SQLITE3_NUM, $serveur); + } else { + list($r) = spip_sqlite_fetch($r, SPIP_SQLITE2_NUM, $serveur); + } + + } + return $r; +} + + + +function spip_sqlite_delete($table, $where='', $serveur='') { + return spip_sqlite_query( + _sqlite_calculer_expression('DELETE FROM', $table, ',') + . _sqlite_calculer_expression('WHERE', $where), + $serveur); +} + + +function spip_sqlite_drop_table($table, $exist='', $serveur='') { + if ($exist) $exist =" IF EXISTS"; + return spip_sqlite_query("DROP TABLE$exist $table", $serveur); +} + + +function spip_sqlite_error($query='', $serveur='') { + $link = _sqlite_link($serveur); + + if (_sqlite_is_version(3, $link)){ + $errs = $link->errorInfo(); + $s = ''; + foreach($errs as $n=>$e){ + $s .= "\n$n : $e"; + } + + } elseif ($link) { + $s = sqlite_error_string(sqlite_last_error($link)); + } else { + $s = ": aucune ressource sqlite (link)"; + } + if ($s) spip_log("$s - $query", 'sqlite'); + return $s; +} + + +function spip_sqlite_errno($serveur='') { + $link = _sqlite_link($serveur); + + if (_sqlite_is_version(3, $link)){ + $s = $link->errorCode(); + } elseif ($link) { + $s = sqlite_last_error($link); + } else { + $s = ": aucune ressource sqlite (link)"; + } + if ($s) spip_log("Erreur sqlite $s"); + + return $s; +} + + +function spip_sqlite_explain($query, $serveur=''){ + if (strpos($query, 'SELECT') !== 0) return array(); + + $query = 'EXPLAIN ' . _sqlite_traite_query($query, $db, $prefixe); + $r = spip_sqlite_query($query, $serveur); + return $r ? spip_sqlite_fetch($r, null, $serveur) : false; // hum ? etrange ca... a verifier +} + + +function spip_sqlite_fetch($r, $t='', $serveur='') { + $link = _sqlite_link($serveur); + if (!$t) { + if (_sqlite_is_version(3, $link)) { + $t = SPIP_SQLITE3_ASSOC; + } else { + $t = SPIP_SQLITE2_ASSOC; + } + } + + + if (_sqlite_is_version(3, $link)){ + if ($r) $retour = $r->fetch($t); + } elseif ($r) { + $retour = sqlite_fetch_array($r, $t); + } + + // la version 2 parfois renvoie des 'table.titre' au lieu de 'titre' tout court ! pff ! + // suppression de 'table.' pour toutes les cles (c'est un peu violent !) + if ($retour && _sqlite_is_version(2, $link)){ + $new = array(); + foreach ($retour as $cle=>$val){ + if (($pos = strpos($cle, '.'))!==false){ + $cle = substr($cle,++$pos); + } + $new[$cle] = $val; + } + $retour = &$new; + } + + //print_r($retour); + return $retour; +} + + +function spip_sqlite_free($r, $serveur='') { + //return sqlite_free_result($r); +} + + +function spip_sqlite_get_charset($charset=array(), $serveur=''){ + //$c = !$charset ? '' : (" LIKE "._q($charset['charset'])); + //return spip_sqlite_fetch(sqlite_query(_sqlite_link($serveur), "SHOW CHARACTER SET$c"), NULL, $serveur); +} + + +function spip_sqlite_hex($v){ + return "0x" . $v; +} + + +function spip_sqlite_in($val, $valeurs, $not='', $serveur='') { + // limite a 255 elements aussi en sqlite ou non ? + if (is_array($valeurs)) + $valeurs = join(',', array_map('spip_sqlite_quote', $valeurs)); + if (!strlen(trim($valeurs))) return ($not ? "0=0" : '0=1'); + + $n = $i = 0; + $in_sql =""; + while ($n = strpos($valeurs, ',', $n+1)) { + if ((++$i) >= 255) { + $in_sql .= "($val $not IN (" . + substr($valeurs, 0, $n) . + "))\n" . + ($not ? "AND\t" : "OR\t"); + $valeurs = substr($valeurs, $n+1); + $i = $n = 0; + } + } + $in_sql .= "($val $not IN ($valeurs))"; + + return "($in_sql)"; +} + + +function spip_sqlite_insert($table, $champs, $valeurs, $desc='', $serveur='') { + + $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0]; + $prefixe = $connexion['prefixe']; + $sqlite = $connexion['link']; + $db = $connexion['db']; + + if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table); + + $t = !isset($_GET['var_profile']) ? 0 : trace_query_start(); + + $query="INSERT OR REPLACE INTO $table $champs VALUES $valeurs"; + + if ($r = spip_sqlite_query($query, $serveur)) { + if (_sqlite_is_version(3, $sqlite)) $nb = $sqlite->lastInsertId(); + else $nb = sqlite_last_insert_rowid($sqlite); + } else { + if ($e = spip_sqlite_errno($serveur)) // Log de l'erreur eventuelle + $e .= spip_sqlite_error($query, $serveur); // et du fautif + } + return $t ? trace_query_end($query, $t, $nb, $e) : $nb; + +} + + +function spip_sqlite_insertq($table, $couples=array(), $desc=array(), $serveur='') { + if (!$desc) $desc = description_table($table); + if (!$desc) die("$table insertion sans description"); + $fields = isset($desc['field'])?$desc['field']:array(); + + foreach ($couples as $champ => $val) { + $couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]); + } + + return spip_sqlite_insert($table, "(".join(',',array_keys($couples)).")", "(".join(',', $couples).")", $desc, $serveur); +} + + +function spip_sqlite_listdbs($serveur='') { + _sqlite_init(); + + if (!is_dir($d = substr(_DIR_DB,0,-1))){ + return array(); + } + + include_spip('inc/flock'); + $bases = preg_files($d, $pattern = '(.*)\.sqlite$'); + $bds = array(); + + foreach($bases as $b){ + // pas de bases commencant pas sqlite + // (on s'en sert pour l'installation pour simuler la presence d'un serveur) + // les bases sont de la forme _sqliteX_tmp_spip_install.sqlite + if (strpos($b, '_sqlite')) continue; + $bds[] = preg_replace(";.*/$pattern;iS",'$1', $b); + } + + return $bds; +} + + +function spip_sqlite_multi ($objet, $lang) { + $r = "REGEXP_REPLACE(" + . $objet + . ",'<multi>.*[\[]" + . $lang + . "[\]]([^\[]*).*</multi>', '$1') AS multi"; + return $r; +} + + +function spip_sqlite_optimize($table, $serveur=''){ + spip_sqlite_query("OPTIMIZE TABLE ". $table, $serveur); // <- a verifier mais ca doit pas etre ca ! + return true; +} + + +// avoir le meme comportement que _q() +function spip_sqlite_quote($v){ + if (is_int($v)) return strval($v); + if (is_array($v)) return join(",", array_map('spip_sqlite_quote', $v)); + + if (function_exists('sqlite_escape_string')) { + return "'" . sqlite_escape_string($v) . "'"; + } + + // trouver un link sqlite3 pour faire l'echappement + foreach ($GLOBALS['connexions'] as $s) { + if (_sqlite_is_version(3, $l = $s['link'])){ + return $l->quote($v); + } + } +} + + +function spip_sqlite_repair($table, $serveur=''){ + return spip_sqlite_query("REPAIR TABLE $table", $serveur); // <- ca m'ettonerait aussi ca ! +} + + +function spip_sqlite_replace($table, $values, $keys=array(), $serveur='') { + return spip_sqlite_query("REPLACE INTO $table (" . join(',',array_keys($values)) . ') VALUES (' .join(',',array_map('spip_sqlite_quote', $values)) . ')', $serveur); +} + + +function spip_sqlite_select($select, $from, $where='', $groupby='', $orderby='', $limit='', $having='', $serveur='') { + // version() n'est pas connu de sqlite + $select = str_replace('version()', 'sqlite_version()',$select); + + // recomposer from + $from = (!is_array($from) ? $from : _sqlite_calculer_select_as($from)); + + $query = + _sqlite_calculer_expression('SELECT', $select, ', ') + . _sqlite_calculer_expression('FROM', $from, ', ') + . _sqlite_calculer_expression('WHERE', $where) + . _sqlite_calculer_expression('GROUP BY', $groupby, ',') + . _sqlite_calculer_expression('HAVING', $having) + . ($orderby ? ("\nORDER BY " . _sqlite_calculer_order($orderby)) :'') + . ($limit ? "\nLIMIT $limit" : ''); + + // Erreur ? C'est du debug de squelette, ou une erreur du serveur + + if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode'] == 'debug') { + include_spip('public/debug'); + boucle_debug_requete($query); + } + + if (!($res = spip_sqlite_query($query, $serveur))) { + include_spip('public/debug'); + + erreur_requete_boucle(substr($query, 7), + spip_sqlite_errno($serveur), + spip_sqlite_error($query, $serveur) ); + } + + return $res; +} + + +function spip_sqlite_selectdb($db, $serveur='') { + _sqlite_init(); + + // interdire la creation d'une nouvelle base, + // sauf si on est dans l'installation + if (!is_file($f = _DIR_DB . $db . '.sqlite') + && _request('exec')!='install') + return false; + + // se connecter a la base indiquee + // avec les identifiants connus + $index = $serveur ? $serveur : 0; + + if ($link = spip_connect_db('', '', '', '', '@selectdb@' . $db , $serveur, '', '')){ + if (($db==$link['db']) && $GLOBALS['connexions'][$index] = $link) + return $db; + } else { + spip_log("Impossible de selectionner la base $db", 'sqlite'); + return false; + } + +} + + +function spip_sqlite_set_charset($charset, $serveur=''){ + #spip_log("changement de charset sql : "."SET NAMES "._q($charset)); + # return spip_sqlite_query("SET NAMES ". spip_sqlite_quote($charset), $serveur); //<-- Passe pas ! +} + + +function spip_sqlite_showbase($match, $serveur=''){ + return spip_sqlite_query('SELECT name FROM sqlite_master WHERE type LIKE "'.$match.'"', $serveur); +} + + +function spip_sqlite_showtable($nom_table, $serveur=''){ + + $query = + 'SELECT sql FROM' + . '(SELECT * FROM sqlite_master UNION ALL' + . ' SELECT * FROM sqlite_temp_master)' + . " WHERE tbl_name LIKE '$nom_table'" + . " AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'" + . 'ORDER BY substr(type,2,1), name'; + + $a = spip_sqlite_query($query, $serveur); + if (!$a) return ""; + if (!($a = spip_sqlite_fetch($a, null, $serveur))) return ""; + $a = array_shift($a); + if (!preg_match("/^[^(),]*\((([^()]*\([^()]*\)[^()]*)*)\)[^()]*$/", $a, $r)) + return ""; + else { + $dec = $r[1]; + if (preg_match("/^(.*?),([^,]*KEY.*)$/s", $dec, $r)) { + $namedkeys = $r[2]; + $dec = $r[1]; + } + else + $namedkeys = ""; + + $fields = array(); + foreach (explode(",",$dec) as $v) { + preg_match("/^\s*([^\s]+)\s+(.*)/",$v,$r); + $fields[strtolower($r[1])] = $r[2]; + } + $keys = array(); + + foreach(preg_split('/\)\s*,?/',$namedkeys) as $v) { + if (preg_match("/^\s*([^(]*)\((.*)$/",$v,$r)) { + $k = str_replace("`", '', trim($r[1])); + $t = strtolower(str_replace("`", '', $r[2])); + if ($k && !isset($keys[$k])) $keys[$k] = $t; else $keys[] = $t; + } + } + /* + * me demande si les cles servent au compilateur de spip + * car vu que sqlite le gere pas, je sais pas ce que ca donne ... + */ + return array('field' => $fields, 'key' => $keys); + } +} + + +function spip_sqlite_update($table, $champs, $where='', $desc='', $serveur='') { + $set = array(); + foreach ($champs as $champ => $val) + $set[] = $champ . "=$val"; + if (!empty($set)) + return spip_sqlite_query( + _sqlite_calculer_expression('UPDATE', $table, ',') + . _sqlite_calculer_expression('SET', $set, ',') + . _sqlite_calculer_expression('WHERE', $where), + $serveur); +} + + +function spip_sqlite_updateq($table, $champs, $where='', $desc=array(), $serveur='') { + + if (!$champs) return; + if (!$desc) $desc = description_table($table); + if (!$desc) die("$table insertion sans description"); + $fields = $desc['field']; + $set = array(); + foreach ($champs as $champ => $val) { + $set[] = $champ . '=' . _sqlite_calculer_cite($val, $fields[$champ]); + } + return spip_sqlite_query( + _sqlite_calculer_expression('UPDATE', $table, ',') + . _sqlite_calculer_expression('SET', $set, ',') + . _sqlite_calculer_expression('WHERE', $where), + $serveur); +} + + + +/* + * + * Ensuite les fonctions non abstraites + * crees pour l'occasion de sqlite + * + */ + + +// fonction pour la premiere connexion a un serveur SqLite +function _sqlite_init(){ + if (!defined('_DIR_DB')) define('_DIR_DB', _DIR_ETC . 'bases/'); + if (!defined('_SQLITE_CHMOD')) define('_SQLITE_CHMOD', _SPIP_CHMOD); + + if (!is_dir($d = _DIR_DB)){ + include_spip('inc/flock'); + sous_repertoire($d); + } +} + + +// teste la version sqlite du link en cours +function _sqlite_is_version($version='', $link='', $serveur=''){ + if ($link==='') $link = _sqlite_link($serveur); + if (!$link) return false; + if (is_a($link, 'PDO')){ + $v = 3; + } else { + $v = 2; + } + + if (!$version) return $v; + return ($version == $v); +} + + +// retrouver un link (et definir les fonctions externes sqlite->php) +// $recharger devient inutile (a supprimer ?) +function _sqlite_link($serveur = '', $recharger = false){ + static $charge = array(); + if ($recharger) $charge[$serveur] = false; + + $link = &$GLOBALS['connexions'][$serveur ? $serveur : 0]['link']; + + if ($link && !$charge[$serveur]){ + include_spip('req/sqlite_fonctions'); + _sqlite_init_functions($link); + $charge[$serveur] = true; + } + return $link; +} + + +/* ordre alphabetique pour les autres */ + + +// renvoie les bons echappements (pas sur les fonctions now()) +function _sqlite_calculer_cite($v, $type) { + if (sql_test_date($type) AND preg_match('/^\w+\(/', $v) + OR (sql_test_int($type) + AND (is_numeric($v) + OR (ctype_xdigit(substr($v,2)) + AND $v[0]=='0' AND $v[1]=='x')))) + return $v; + //else return ("'" . spip_sqlite_quote($v) . "'"); + else return (spip_sqlite_quote($v)); +} + + +// renvoie grosso modo "$expression join($join, $v)" +function _sqlite_calculer_expression($expression, $v, $join = 'AND'){ + if (empty($v)) + return ''; + + $exp = "\n$expression "; + + if (!is_array($v)) { + return $exp . $v; + } else { + if (strtoupper($join) === 'AND') + return $exp . join("\n\t$join ", array_map('_sqlite_calculer_where', $v)); + else + return $exp . join($join, $v); + } +} + + + + +// pour conversion 0x ? +function _sqlite_calculer_order($orderby) { + //if (!is_array($orderby)) $orderby = explode(',', $orderby); + //array_walk($orderby, '_sqlite_mettre_quote'); + //return join(", ", $orderby); + return (is_array($orderby)) ? join(", ", $orderby) : $orderby; +} + + +// renvoie des 'nom AS alias' +function _sqlite_calculer_select_as($args){ + if (isset($args[-1])) { + $join = ' ' . $args[-1]; + unset($args[-1]); + } else $join =''; + $res = ''; + foreach($args as $k => $v) { + $res .= ', ' . $v . (is_numeric($k) ? '' : " AS '$k'") . $join; + $join = ''; + } + return substr($res,2); +} + + +// renvoie les bonnes parentheses pour des where imbriquees +function _sqlite_calculer_where($v){ + if (!is_array($v)) + return $v ; + + $op = array_shift($v); + if (!($n=count($v))) + return $op; + else { + $arg = _sqlite_calculer_where(array_shift($v)); + if ($n==1) { + return "$op($arg)"; + } else { + $arg2 = _sqlite_calculer_where(array_shift($v)); + if ($n==2) { + return "($arg $op $arg2)"; + } else return "($arg $op ($arg2) : $v[0])"; + } + } +} + + + +/* + * Charger les modules sqlite (si possible) (juste la version demandee), + * ou, si aucune version, renvoie les versions sqlite dispo + * sur ce serveur dans un array + */ +function _sqlite_charger_version($version=''){ + $versions = array(); + + // version 2 + if (!$version || $version == 2){ + $ok = false; + if (extension_loaded('sqlite')){ + $ok = true; + } else { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $ok = dl('php_sqlite.dll'); + } else { + $ok = dl('sqlite.so'); + } + } + if ($ok) $versions[]=2; + } + + // version 3 + if (!$version || $version == 3){ + $ok = false; + if (extension_loaded('pdo') && extension_loaded('pdo_sqlite')){ + $ok = true; + } else { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $ok = dl('php_pdo.dll') && dl('php_pdo_sqlite.dll'); + } else { + $ok = dl('pdo.so') && dl('pdo_sqlite.so'); + } + } + if ($ok) $versions[]=3; + } + if ($version) return in_array($version, $versions); + return $versions; +} + +/* + * renvoyer la liste des versions sqlite disponibles + * sur le serveur + */ +function spip_versions_sqlite(){ + return _sqlite_charger_version(); +} + + + + +/* + * Nom des fonctions + */ +function _sqlite_ref_fonctions(){ + $fonctions = array( + // tests + 'begin' => 'spip_sqlite_begin', + 'commit' => 'spip_sqlite_commit', + + 'alter' => 'spip_sqlite_alter', + 'count' => 'spip_sqlite_count', + 'countsel' => 'spip_sqlite_countsel', + 'create' => 'spip_sqlite_create', + 'delete' => 'spip_sqlite_delete', + 'drop_table' => 'spip_sqlite_drop_table', + 'errno' => 'spip_sqlite_errno', + 'error' => 'spip_sqlite_error', + 'explain' => 'spip_sqlite_explain', + 'fetch' => 'spip_sqlite_fetch', + 'free' => 'spip_sqlite_free', + 'hex' => 'spip_sqlite_hex', + 'in' => 'spip_sqlite_in', + 'insert' => 'spip_sqlite_insert', + 'insertq' => 'spip_sqlite_insertq', + 'listdbs' => 'spip_sqlite_listdbs', + 'multi' => 'spip_sqlite_multi', + 'optimize' => 'spip_sqlite_optimize', + 'query' => 'spip_sqlite_query', + 'quote' => 'spip_sqlite_quote', + 'replace' => 'spip_sqlite_replace', + 'repair' => 'spip_sqlite_repair', + 'select' => 'spip_sqlite_select', + 'selectdb' => 'spip_sqlite_selectdb', + 'set_charset' => 'spip_sqlite_set_charset', + 'get_charset' => 'spip_sqlite_get_charset', + 'showbase' => 'spip_sqlite_showbase', + 'showtable' => 'spip_sqlite_showtable', + 'update' => 'spip_sqlite_update', + 'updateq' => 'spip_sqlite_updateq', + ); + + // association de chaque nom http d'un charset aux couples sqlite + + $charsets = array( + 'iso-8859-1'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),// non supporte ? + 'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci'), + //'utf-16be'=>array('charset'=>'utf16be','collation'=>'UTF-16BE'),// aucune idee de quoi il faut remplir dans es champs la + //'utf-16le'=>array('charset'=>'utf16le','collation'=>'UTF-16LE') + ); + + $fonctions['charsets'] = $charsets; + + return $fonctions; +} + + + + + + +/* + * Un classe simplement pour un preg_replace_callback avec des parametres + * dans la fonction appelee que l'on souhaite incrementer (fonction pour proteger les textes) + * + * Du coup, je mets aussi les traitements a faire dedans + * + */ +class sqlite_analyse_query { + var $sqlite = ''; // la ressource link (ou objet pdo) + var $query = ''; // la requete + var $queryCount = ''; // la requete pour comptage des lignes select (sqlite3/PDO) + var $db = ''; // le nom de la bdd + var $prefixe = ''; // le prefixe des tables + var $debug = false; // spip_logguer les actions + var $crier = false; // echo des actions + var $textes = array(); // array(code=>'texte') trouvé + + var $codeEchappements = "%@##@%"; + + + function sqlite_analyse_query(&$link, &$query, $db, $prefixe){ + $this->sqlite = $link; + $this->query = $query; + $this->db = $db; + $this->prefixe = $prefixe; + $this->queryCount = ""; + + $this->sqlite_version = _sqlite_is_version('', $this->sqlite); + } + + + function debug($texte='', $afficherQuery = true){ + if ($afficherQuery){ + if ($this->debug) spip_log("sqlite_analyse_query > $texte >" . $this->query); + if ($this->crier) echo "<b>sqlite_analyse_query > $texte ></b> " . $this->query . "<br/>\n"; + } else { + if ($this->debug) spip_log("sqlite_analyse_query > $texte"); + if ($this->crier) echo "<b>sqlite_analyse_query > $texte </b><br/>\n"; + } + } + + + function creerLesRequetes(){ + #$analyse->debug = $analyse->crier = true; + $this->cacherLesTextes(); + // traitements + $this->corrigerTout(); + // hop, on remet les 'textes' + $this->afficherLesTextes(); + // requete pour comptage + if ($this->sqlite_version == 3){ + $this->creerRequeteCount(); + } + } + + + // enlever le contenu 'texte' des requetes + function cacherLesTextes(){ + $this->debug("protegerLesTextes 1"); + + // enlever les echappements '' + $this->query = str_replace("''", $this->codeEchappements, $this->query); + $this->debug("protegerLesTextes 2"); + + // enlever les 'textes' + $this->textes = array(); // vider + $this->query = preg_replace_callback("/('[^']*')/", array(&$this, '_remplacerTexteParCode'), $this->query); + $this->debug("protegerLesTextes 3"); + } + + + // remettre le contenu 'texte' des requetes + function afficherLesTextes(){ + $this->debug("afficherLesTextes 1"); + + // remettre les 'textes' + foreach ($this->textes as $cle=>$val){ + $this->query = str_replace($cle, $val, $this->query); + } + $this->debug("afficherLesTextes 2"); + + // remettre les echappements '' + $this->query = str_replace($this->codeEchappements,"''",$this->query); + $this->debug("afficherLesTextes 3"); + } + + + // les corrections + + function corrigerTout(){ + $this->corrigerCreateDatabase(); + $this->corrigerInsertIgnore(); + $this->corrigerDate(); + $this->corrigerUsing(); + $this->corrigerField(); + $this->corrigerTablesFrom(); + $this->corrigerZeroAsX(); + } + + + // Create Database -> ignore + function corrigerCreateDatabase(){ + if (strpos($this->query, 'CREATE DATABASE')===0){ + spip_log("Sqlite : requete non executee -> $this->query","sqlite"); + $this->query = "SELECT 1"; + } + } + + + // corriger les dates avec INTERVAL + function corrigerDate() { + if (strpos($this->query, 'INTERVAL')!==false){ + $this->debug("corrigerDate 1"); + $this->query = preg_replace_callback("/DATE_(ADD|SUB).*INTERVAL\s+(\d+)\s+([a-zA-Z]+)\)/U", + array(&$this, '_remplacerDateParTime'), + $this->query); + $this->debug("corrigerDate 2"); + } + } + + + // FIELD (issu de pg) a tester ! + function corrigerField(){ + if (strpos($this->query, 'FIELD')!==false){ + $this->debug("corrigerField 1"); + $this->query = preg_replace_callback('/FIELD\s*\(([^\)]*)\)/', + array(&$this, '_remplacerFieldParCase'), + $this->query); + $this->debug("corrigerField 2"); + } + } + + + // INSERT IGNORE -> insert (tout court et pas 'insert or replace') + function corrigerInsertIgnore(){ + if (strpos($this->query, 'INSERT IGNORE')===0){ + #spip_log("Sqlite : requete transformee -> $this->query","sqlite"); + $this->query = 'INSERT ' . substr($this->query,'13'); + } + } + + + // mettre les bons noms de table dans from, update, insert, replace... + function corrigerTablesFrom(){ + if (preg_match('/\s(SET|VALUES|WHERE)\s/i', $this->query, $regs)) { + $suite = strstr($this->query, $regs[0]); + $this->query = substr($this->query, 0, -strlen($suite)); + } else $suite =''; + + $pref = ($this->prefixe) ? $this->prefixe . "_": ""; + $this->query = preg_replace('/([,\s])spip_/', '\1'.$pref, $this->query) . $suite; + #spip_log("_sqlite_traite_query: " . substr($this->query,0, 50) . ".... $this->db, $this->prefixe"); + } + + + // USING (inutile et non reconnu en sqlite2) + function corrigerUsing(){ + if (($this->sqlite_version == 2) && (strpos($this->query, "USING")!==false)) { + $this->query = preg_replace('/USING\s*\([^\)]*\)/', '', $this->query); + } + } + + + // pg n'aime pas 0+x AS alias, sqlite, dans le meme style, + // sqlite n'apprecie pas du tout SELECT 0 as x ... ORDER BY x + // il dit que x ne doit pas être un integer dans le orger by ! + // on remplace du coup x par vide() dans ce cas uniquement + // + // rien que pour public/vertebrer.php ? + function corrigerZeroAsX(){ + if ((strpos($this->query, "0 AS")!==false)){ + // on ne remplace que dans ORDER BY ou GROUP BY + if (preg_match('/\s(ORDER|GROUP) BY\s/i', $this->query, $regs)) { + $suite = strstr($this->query, $regs[0]); + $this->query = substr($this->query, 0, -strlen($suite)); + + // on cherche les noms des x dans 0 AS x + // on remplace dans $suite le nom par vide() + preg_match_all('/\b0 AS\s*([^\s,]+)/', $this->query, $matches, PREG_PATTERN_ORDER); + foreach ($matches[1] as $m){ + $suite = str_replace($m, 'VIDE()', $suite); + } + $this->query .= $suite; + } + } + #$this->debug("Analyse > corrigerZeroAsX() > "); + } + + + // les creations ! + + function creerRequeteCount(){ + if (strpos($this->query,'SELECT')!==false){ + $this->queryCount = $this->query; + //preg_replace('/SELECT(\s*)(DISTINCT)?(\s*)/s','SELECT$1$2$3COUNT(*) AS sqlite_count, ', $this->query, 1); // 1 seul ! + } + } + + // les callbacks + + // remplacer DATE_ / INTERVAL par DATE...strtotime + function _remplacerDateParTime($matches){ + $op = strtoupper($matches[1] == 'ADD')?'+':'-'; + return "'".date("Y-m-d H:i:s", strtotime(" $op$matches[2] ".strtolower($matches[3])))."'"; + } + + + // callback ou l'on remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END + function _remplacerFieldParCase($matches){ + $fields = substr($matches[0],6,-1); // ne recuperer que l'interieur X de field(X) + $t = explode(',', $fields); + $index = array_shift($t); + + $res = ''; + $n=0; + foreach($t as $v) { + $n++; + $res .= "\nWHEN $index=$v THEN $n"; + } + return "CASE $res ELSE 0 END "; + } + + + // callback ou l'on sauve le texte qui est cache dans un tableau $this->textes + function _remplacerTexteParCode($matches){ + #$this->debug("Matches ". $matches[1], false); + $this->textes[$code = "%@##".count($this->textes)."##@%"] = $matches[1]; + return $code; + } + +} +?> -- GitLab