PageRenderTime 66ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/spip/ecrire/req/sqlite_generique.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 1905 lines | 1212 code | 282 blank | 411 comment | 255 complexity | 58633a8144888fc7b3755d4c586ac47f MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. // infos :
  13. // il ne faut pas avoir de PDO::CONSTANTE dans ce fichier sinon php4 se tue !
  14. // idem, il ne faut pas de $obj->toto()->toto sinon php4 se tue !
  15. # todo : get/set_caracteres ?
  16. /*
  17. *
  18. * regroupe le maximum de fonctions qui peuvent cohabiter
  19. * D'abord les fonctions d'abstractions de SPIP
  20. *
  21. */
  22. // http://doc.spip.org/@req_sqlite_dist
  23. function req_sqlite_dist($addr, $port, $login, $pass, $db='', $prefixe='', $sqlite_version=''){
  24. static $last_connect = array();
  25. // si provient de selectdb
  26. // un code pour etre sur que l'on vient de select_db()
  27. if (strpos($db, $code = '@selectdb@')!==false) {
  28. foreach (array('addr','port','login','pass','prefixe') as $a){
  29. $$a = $last_connect[$a];
  30. }
  31. $db = str_replace($code, '', $db);
  32. }
  33. /*
  34. * En sqlite, seule l'adresse du fichier est importante.
  35. * Ce sera $db le nom, et le path _DIR_DB
  36. */
  37. _sqlite_init();
  38. // un nom de base demande et impossible d'obtenir la base, on s'en va
  39. if ($db && !is_file($f = _DIR_DB . $db . '.sqlite') && !is_writable(_DIR_DB))
  40. return false;
  41. // charger les modules sqlite au besoin
  42. if (!_sqlite_charger_version($sqlite_version)) {
  43. spip_log("Impossible de trouver/charger le module SQLite ($sqlite_version)!");
  44. return false;
  45. }
  46. // chargement des constantes
  47. // il ne faut pas definir les constantes avant d'avoir charge les modules sqlite
  48. $define = "spip_sqlite".$sqlite_version."_constantes";
  49. $define();
  50. $ok = false;
  51. if (!$db){
  52. // si installation -> base temporaire tant qu'on ne connait pas son vrai nom
  53. if (defined('_ECRIRE_INSTALL') && _ECRIRE_INSTALL){
  54. // creation d'une base temporaire pour le debut d'install
  55. $db = "_sqlite".$sqlite_version."_install";
  56. $tmp = _DIR_DB . $db . ".sqlite";
  57. if ($sqlite_version == 3) {
  58. $ok = $link = new PDO("sqlite:$tmp");
  59. } else {
  60. $ok = $link = sqlite_open($tmp, _SQLITE_CHMOD, $err);
  61. }
  62. // sinon, on arrete finalement
  63. } else {
  64. return false;
  65. }
  66. } else {
  67. // Ouvrir (eventuellement creer la base)
  68. // si pas de version fourni, on essaie la 3, sinon la 2
  69. if ($sqlite_version == 3) {
  70. $ok = $link = new PDO("sqlite:$f");
  71. } else {
  72. $ok = $link = sqlite_open($f, _SQLITE_CHMOD, $err);
  73. }
  74. }
  75. if (!$ok){
  76. spip_log("Impossible d'ouvrir la base de donnee SQLite ($sqlite_version) : $f ");
  77. return false;
  78. }
  79. if ($link) {
  80. $last_connect = array (
  81. 'addr' => $addr,
  82. 'port' => $port,
  83. 'login' => $login,
  84. 'pass' => $pass,
  85. 'db' => $db,
  86. 'prefixe' => $prefixe,
  87. );
  88. }
  89. return array(
  90. 'db' => $db,
  91. 'prefixe' => $prefixe ? $prefixe : $db,
  92. 'link' => $link,
  93. );
  94. }
  95. // Fonction de requete generale, munie d'une trace a la demande
  96. // http://doc.spip.org/@spip_sqlite_query
  97. function spip_sqlite_query($query, $serveur='',$requeter=true) {
  98. #spip_log("spip_sqlite_query() > $query");
  99. _sqlite_init();
  100. $requete = new sqlite_traiter_requete($query, $serveur);
  101. $requete->traduire_requete(); // mysql -> sqlite
  102. if (!$requeter) return $requete->query;
  103. return $requete->executer_requete();
  104. }
  105. /* ordre alphabetique pour les autres */
  106. // http://doc.spip.org/@spip_sqlite_alter
  107. function spip_sqlite_alter($query, $serveur='',$requeter=true){
  108. $query = spip_sqlite_query("ALTER $query",$serveur,false);
  109. /*
  110. * la il faut faire les transformations
  111. * si ALTER TABLE x (DROP|CHANGE) y
  112. *
  113. * 1) recuperer "ALTER TABLE table "
  114. * 2) spliter les sous requetes (,)
  115. * 3) faire chaque requete independemment
  116. */
  117. // 1
  118. if (preg_match("/\s*(ALTER(\s*IGNORE)?\s*TABLE\s*([^\s]*))\s*(.*)?/is", $query, $regs)){
  119. $debut = $regs[1];
  120. $table = $regs[3];
  121. $suite = $regs[4];
  122. } else {
  123. spip_log("SQLite : Probleme de ALTER TABLE mal forme dans $query", 'sqlite');
  124. return false;
  125. }
  126. // 2
  127. // il faudrait une regexp pour eviter de spliter ADD PRIMARY KEY (colA, colB)
  128. // tout en cassant "ADD PRIMARY KEY (colA, colB), ADD INDEX (chose)"... en deux
  129. // ou revoir l'api de sql_alter en creant un
  130. // sql_alter_table($table,array($actions));
  131. $todo = explode(',', $suite);
  132. // on remet les morceaux dechires ensembles... que c'est laid !
  133. $todo2 = array(); $i=0;
  134. $ouverte = false;
  135. while ($do = array_shift($todo)) {
  136. $todo2[$i] = isset($todo2[$i]) ? $todo2[$i] . "," . $do : $do;
  137. $o=(false!==strpos($do,"("));
  138. $f=(false!==strpos($do,")"));
  139. if ($o AND !$f) $ouverte=true;
  140. elseif ($f) $ouverte=false;
  141. if (!$ouverte) $i++;
  142. }
  143. // 3
  144. $resultats = array();
  145. foreach ($todo2 as $do){
  146. $do = trim($do);
  147. if (!preg_match('/(DROP PRIMARY KEY|DROP INDEX|DROP COLUMN|DROP'
  148. .'|CHANGE COLUMN|CHANGE|MODIFY|RENAME TO|RENAME'
  149. .'|ADD PRIMARY KEY|ADD INDEX|ADD COLUMN|ADD'
  150. .')\s*([^\s]*)\s*(.*)?/', $do, $matches)){
  151. spip_log("SQLite : Probleme de ALTER TABLE, utilisation non reconnue dans : $do \n(requete d'origine : $query)", 'sqlite');
  152. return false;
  153. }
  154. $cle = strtoupper($matches[1]);
  155. $colonne_origine = $matches[2];
  156. $colonne_destination = '';
  157. $def = $matches[3];
  158. // eluder une eventuelle clause before|after|first inutilisable
  159. $defr = rtrim(preg_replace('/(BEFORE|AFTER|FIRST)(.*)$/is','', $def));
  160. // remplacer les definitions venant de mysql
  161. $defr = _sqlite_remplacements_definitions_table($defr);
  162. // reinjecter dans le do
  163. $do = str_replace($def,$defr,$do);
  164. $def = $defr;
  165. switch($cle){
  166. // suppression d'un index
  167. case 'DROP INDEX':
  168. $nom_index = $colonne_origine;
  169. spip_sqlite_drop_index($nom_index, $table, $serveur);
  170. break;
  171. // suppression d'une pk
  172. case 'DROP PRIMARY KEY':
  173. if (!_sqlite_modifier_table(
  174. $table,
  175. $colonne_origine,
  176. array('key'=>array('PRIMARY KEY'=>'')),
  177. $serveur)){
  178. return false;
  179. }
  180. break;
  181. // suppression d'une colonne
  182. case 'DROP COLUMN':
  183. case 'DROP':
  184. if (!_sqlite_modifier_table(
  185. $table,
  186. array($colonne_origine=>""),
  187. '',
  188. $serveur)){
  189. return false;
  190. }
  191. break;
  192. case 'CHANGE COLUMN':
  193. case 'CHANGE':
  194. // recuperer le nom de la future colonne
  195. $def = trim($def);
  196. $colonne_destination = substr($def, 0, strpos($def,' '));
  197. $def = substr($def, strlen($colonne_destination)+1);
  198. if (!_sqlite_modifier_table(
  199. $table,
  200. array($colonne_origine=>$colonne_destination),
  201. array('field'=>array($colonne_destination=>$def)),
  202. $serveur)){
  203. return false;
  204. }
  205. break;
  206. case 'MODIFY':
  207. if (!_sqlite_modifier_table(
  208. $table,
  209. $colonne_origine,
  210. array('field'=>array($colonne_origine=>$def)),
  211. $serveur)){
  212. return false;
  213. }
  214. break;
  215. // pas geres en sqlite2
  216. case 'RENAME':
  217. $do = "RENAME TO" . substr($do,6);
  218. case 'RENAME TO':
  219. if (_sqlite_is_version(3, '', $serveur)){
  220. $requete = new sqlite_traiter_requete("$debut $do", $serveur);
  221. if (!$requete->executer_requete()){
  222. spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite');
  223. return false;
  224. }
  225. // artillerie lourde pour sqlite2 !
  226. } else {
  227. $table_dest = trim(substr($do, 9));
  228. if (!_sqlite_modifier_table(array($table=>$table_dest), '', '', $serveur)){
  229. spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite');
  230. return false;
  231. }
  232. }
  233. break;
  234. // ajout d'une pk
  235. case 'ADD PRIMARY KEY':
  236. $pk = trim(substr($do,16));
  237. $pk = ($pk[0]=='(') ? substr($pk,1,-1) : $pk;
  238. if (!_sqlite_modifier_table(
  239. $table,
  240. $colonne_origine,
  241. array('key'=>array('PRIMARY KEY'=>$pk)),
  242. $serveur)){
  243. return false;
  244. }
  245. break;
  246. // ajout d'un index
  247. case 'ADD INDEX':
  248. // peut etre "(colonne)" ou "nom_index (colonnes)"
  249. // bug potentiel si qqn met "(colonne, colonne)"
  250. //
  251. // nom_index (colonnes)
  252. if ($def) {
  253. $colonnes = substr($def,1,-1);
  254. $nom_index = $colonne_origine;
  255. }
  256. else {
  257. // (colonne)
  258. if ($colonne_origine[0] == "(") {
  259. $colonnes = substr($colonne_origine,1,-1);
  260. if (false!==strpos(",",$colonnes)) {
  261. spip_log("SQLite : Erreur, impossible de creer un index sur plusieurs colonnes"
  262. ." sans qu'il ait de nom ($table, ($colonnes))", 'sqlite');
  263. break;
  264. } else {
  265. $nom_index = $colonnes;
  266. }
  267. }
  268. // nom_index
  269. else {
  270. $nom_index = $colonnes = $colonne_origine ;
  271. }
  272. }
  273. spip_sqlite_create_index($nom_index, $table, $colonnes, $serveur);
  274. break;
  275. // pas geres en sqlite2
  276. case 'ADD COLUMN':
  277. $do = "ADD".substr($do, 10);
  278. case 'ADD':
  279. default:
  280. if (_sqlite_is_version(3, '', $serveur)){
  281. $requete = new sqlite_traiter_requete("$debut $do", $serveur);
  282. if (!$requete->executer_requete()){
  283. spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite');
  284. return false;
  285. }
  286. break;
  287. // artillerie lourde pour sqlite2 !
  288. } else {
  289. $def = trim(substr($do, 3));
  290. $colonne_ajoutee = substr($def, 0, strpos($def,' '));
  291. $def = substr($def, strlen($colonne_ajoutee)+1);
  292. if (!_sqlite_modifier_table($table, array($colonne_ajoutee), array('field'=>array($colonne_ajoutee=>$def)), $serveur)){
  293. spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite');
  294. return false;
  295. }
  296. }
  297. break;
  298. }
  299. // tout est bon, ouf !
  300. spip_log("SQLite ($serveur) : Changements OK : $debut $do");
  301. }
  302. spip_log("SQLite ($serveur) : fin ALTER TABLE OK !");
  303. return true;
  304. }
  305. // Fonction de creation d'une table SQL nommee $nom
  306. // http://doc.spip.org/@spip_sqlite_create
  307. function spip_sqlite_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $serveur='',$requeter=true) {
  308. $query = _sqlite_requete_create($nom, $champs, $cles, $autoinc, $temporary, $ifnotexists=true, $serveur, $requeter);
  309. if (!$query) return false;
  310. $res = spip_sqlite_query($query, $serveur, $requeter);
  311. // SQLite ne cree pas les KEY sur les requetes CREATE TABLE
  312. // il faut donc les faire creer ensuite
  313. if (!$requeter) return $res;
  314. $ok = $res ? true : false;
  315. if ($ok) {
  316. foreach($cles as $k=>$v) {
  317. if (strpos($k, "KEY ") === 0) {
  318. $index = preg_replace("/KEY +/", '',$k);
  319. $ok &= $res = spip_sqlite_create_index($index, $nom, $v, $serveur);
  320. }
  321. }
  322. }
  323. return $ok ? true : false;
  324. }
  325. /**
  326. * Fonction pour creer une base de donnees SQLite
  327. *
  328. * @param string $nom le nom de la base (sans l'extension de fichier)
  329. * @param string $serveur le nom de la connexion
  330. * @param string $option options
  331. *
  332. * @return bool true si la base est creee.
  333. **/
  334. function spip_sqlite_create_base($nom, $serveur='', $option=true) {
  335. $f = _DIR_DB . $nom . '.sqlite';
  336. if (_sqlite_is_version(2, '', $serveur)) {
  337. $ok = sqlite_open($f, _SQLITE_CHMOD, $err);
  338. } else {
  339. $ok = new PDO("sqlite:$f");
  340. }
  341. if ($ok) {
  342. unset($ok);
  343. return true;
  344. }
  345. unset($ok);
  346. return false;
  347. }
  348. // Fonction de creation d'une vue SQL nommee $nom
  349. // http://doc.spip.org/@spip_sqlite_create_view
  350. function spip_sqlite_create_view($nom, $query_select, $serveur='',$requeter=true) {
  351. if (!$query_select) return false;
  352. // vue deja presente
  353. if (sql_showtable($nom, false, $serveur)) {
  354. spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)");
  355. return false;
  356. }
  357. $query = "CREATE VIEW $nom AS ". $query_select;
  358. return spip_sqlite_query($query, $serveur, $requeter);
  359. }
  360. /**
  361. * Fonction de creation d'un INDEX
  362. *
  363. * @param string $nom : nom de l'index
  364. * @param string $table : table sql de l'index
  365. * @param string/array $champs : liste de champs sur lesquels s'applique l'index
  366. * @param string $serveur : nom de la connexion sql utilisee
  367. * @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete
  368. *
  369. * @return bool ou requete
  370. */
  371. function spip_sqlite_create_index($nom, $table, $champs, $serveur='', $requeter=true) {
  372. if (!($nom OR $table OR $champs)) {
  373. spip_log("Champ manquant pour creer un index sqlite ($nom, $table, (".join(',',$champs)."))");
  374. return false;
  375. }
  376. // SQLite ne differentie pas noms des index en fonction des tables
  377. // il faut donc creer des noms uniques d'index pour une base sqlite
  378. $nom = $table.'_'.$nom;
  379. // enlever d'eventuelles parentheses deja presentes sur champs
  380. if (!is_array($champs)){
  381. if ($champs[0]=="(") $champs = substr($champs,1,-1);
  382. $champs = array($champs);
  383. }
  384. $query = "CREATE INDEX $nom ON $table (" . join(',',$champs) . ")";
  385. $res = spip_sqlite_query($query, $serveur, $requeter);
  386. if (!$requeter) return $res;
  387. if ($res)
  388. return true;
  389. else
  390. return false;
  391. }
  392. // en PDO/sqlite3, il faut calculer le count par une requete count(*)
  393. // pour les resultats de SELECT
  394. // cela est fait sans spip_sqlite_query()
  395. // http://doc.spip.org/@spip_sqlite_count
  396. function spip_sqlite_count($r, $serveur='',$requeter=true) {
  397. if (!$r) return 0;
  398. if (_sqlite_is_version(3, '', $serveur)){
  399. // select ou autre (insert, update,...) ?
  400. if (isset($r->spipSqliteRowCount)) {
  401. // Ce compte est faux s'il y a des limit dans la requete :(
  402. // il retourne le nombre d'enregistrements sans le limit
  403. return $r->spipSqliteRowCount;
  404. } else {
  405. return $r->rowCount();
  406. }
  407. } else {
  408. return sqlite_num_rows($r);
  409. }
  410. }
  411. // http://doc.spip.org/@spip_sqlite_countsel
  412. function spip_sqlite_countsel($from = array(), $where = array(), $groupby = '', $having = array(), $serveur='',$requeter=true) {
  413. $c = !$groupby ? '*' : ('DISTINCT ' . (is_string($groupby) ? $groupby : join(',', $groupby)));
  414. $r = spip_sqlite_select("COUNT($c)", $from, $where,'', '', '',$having, $serveur, $requeter);
  415. if ((is_resource($r) or is_object($r)) && $requeter) { // ressource : sqlite2, object : sqlite3
  416. if (_sqlite_is_version(3,'',$serveur)){
  417. list($n) = spip_sqlite_fetch($r, SPIP_SQLITE3_NUM, $serveur);
  418. } else {
  419. list($n) = spip_sqlite_fetch($r, SPIP_SQLITE2_NUM, $serveur);
  420. }
  421. spip_sqlite_free($r,$serveur);
  422. }
  423. return $n;
  424. }
  425. // http://doc.spip.org/@spip_sqlite_delete
  426. function spip_sqlite_delete($table, $where='', $serveur='',$requeter=true) {
  427. $res = spip_sqlite_query(
  428. _sqlite_calculer_expression('DELETE FROM', $table, ',')
  429. . _sqlite_calculer_expression('WHERE', $where),
  430. $serveur, $requeter);
  431. // renvoyer la requete inerte si demandee
  432. if (!$requeter) return $res;
  433. if ($res){
  434. $link = _sqlite_link($serveur);
  435. if (_sqlite_is_version(3, $link)) {
  436. return $res->rowCount();
  437. } else {
  438. return sqlite_changes($link);
  439. }
  440. }
  441. else
  442. return false;
  443. }
  444. // http://doc.spip.org/@spip_sqlite_drop_table
  445. function spip_sqlite_drop_table($table, $exist='', $serveur='',$requeter=true) {
  446. if ($exist) $exist =" IF EXISTS";
  447. /* simuler le IF EXISTS - version 2 */
  448. if ($exist && _sqlite_is_version(2, '', $serveur)){
  449. $a = spip_sqlite_showtable($table, $serveur);
  450. if (!$a) return true;
  451. $exist = '';
  452. }
  453. if (spip_sqlite_query("DROP TABLE$exist $table", $serveur, $requeter))
  454. return true;
  455. else
  456. return false;
  457. }
  458. // supprime une vue
  459. // http://doc.spip.org/@spip_sqlite_drop_view
  460. function spip_sqlite_drop_view($view, $exist='', $serveur='',$requeter=true) {
  461. if ($exist) $exist =" IF EXISTS";
  462. /* simuler le IF EXISTS - version 2 */
  463. if ($exist && _sqlite_is_version(2, '', $serveur)){
  464. $a = spip_sqlite_showtable($view, $serveur);
  465. if (!$a) return true;
  466. $exist = '';
  467. }
  468. return spip_sqlite_query("DROP VIEW$exist $view", $serveur, $requeter);
  469. }
  470. /**
  471. * Fonction de suppression d'un INDEX
  472. *
  473. * @param string $nom : nom de l'index
  474. * @param string $table : table sql de l'index
  475. * @param string $serveur : nom de la connexion sql utilisee
  476. * @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete
  477. *
  478. * @return bool ou requete
  479. */
  480. function spip_sqlite_drop_index($nom, $table, $serveur='', $requeter=true) {
  481. if (!($nom OR $table)) {
  482. spip_log("Champ manquant pour supprimer un index sqlite ($nom, $table)");
  483. return false;
  484. }
  485. // SQLite ne differentie pas noms des index en fonction des tables
  486. // il faut donc creer des noms uniques d'index pour une base sqlite
  487. $index = $table.'_'.$nom;
  488. $exist =" IF EXISTS";
  489. /* simuler le IF EXISTS - version 2 */
  490. if (_sqlite_is_version(2, '', $serveur)){
  491. $a = spip_sqlite_showtable($table, $serveur);
  492. if (!isset($a['key']['KEY '.$nom])) return true;
  493. $exist = '';
  494. }
  495. $query = "DROP INDEX$exist $index";
  496. return spip_sqlite_query($query, $serveur, $requeter);
  497. }
  498. /**
  499. * Retourne la derniere erreur generee
  500. *
  501. * @param $serveur nom de la connexion
  502. * @return string erreur eventuelle
  503. **/
  504. // http://doc.spip.org/@spip_sqlite_error
  505. function spip_sqlite_error($query='', $serveur='') {
  506. $link = _sqlite_link($serveur);
  507. if (_sqlite_is_version(3, $link)) {
  508. $errs = $link->errorInfo();
  509. $s = '';
  510. foreach($errs as $n=>$e){
  511. $s .= "\n$n : $e";
  512. }
  513. } elseif ($link) {
  514. $s = sqlite_error_string(sqlite_last_error($link));
  515. } else {
  516. $s = ": aucune ressource sqlite (link)";
  517. }
  518. if ($s) spip_log("$s - $query", 'sqlite');
  519. return $s;
  520. }
  521. /**
  522. * Retourne le numero de la derniere erreur SQL
  523. * (sauf que SQLite semble ne connaitre que 0 ou 1)
  524. *
  525. * @param $serveur nom de la connexion
  526. * @return int 0 pas d'erreur / 1 une erreur
  527. **/
  528. // http://doc.spip.org/@spip_sqlite_errno
  529. function spip_sqlite_errno($serveur='') {
  530. $link = _sqlite_link($serveur);
  531. if (_sqlite_is_version(3, $link)){
  532. $t = $link->errorInfo();
  533. $s = $t[1];
  534. } elseif ($link) {
  535. $s = sqlite_last_error($link);
  536. } else {
  537. $s = ": aucune ressource sqlite (link)";
  538. }
  539. if ($s) spip_log("Erreur sqlite $s");
  540. return $s ? 1 : 0;
  541. }
  542. // http://doc.spip.org/@spip_sqlite_explain
  543. function spip_sqlite_explain($query, $serveur='',$requeter=true){
  544. if (strpos(ltrim($query), 'SELECT') !== 0) return array();
  545. $requete = new sqlite_traiter_requete("$query", $serveur);
  546. $requete->traduire_requete(); // mysql -> sqlite
  547. $requete->query = 'EXPLAIN ' . $requete->query;
  548. if (!$requeter) return $requete;
  549. // on ne trace pas ces requetes, sinon on obtient un tracage sans fin...
  550. $requete->tracer = false;
  551. $r = $requete->executer_requete();
  552. return $r ? spip_sqlite_fetch($r, null, $serveur) : false; // hum ? etrange ca... a verifier
  553. }
  554. // http://doc.spip.org/@spip_sqlite_fetch
  555. function spip_sqlite_fetch($r, $t='', $serveur='',$requeter=true) {
  556. $link = _sqlite_link($serveur);
  557. if (!$t) {
  558. if (_sqlite_is_version(3, $link)) {
  559. $t = SPIP_SQLITE3_ASSOC;
  560. } else {
  561. $t = SPIP_SQLITE2_ASSOC;
  562. }
  563. }
  564. if (_sqlite_is_version(3, $link)){
  565. if ($r) $retour = $r->fetch($t);
  566. } elseif ($r) {
  567. $retour = sqlite_fetch_array($r, $t);
  568. }
  569. // les version 2 et 3 parfois renvoie des 'table.titre' au lieu de 'titre' tout court ! pff !
  570. // suppression de 'table.' pour toutes les cles (c'est un peu violent !)
  571. if ($retour){
  572. $new = array();
  573. foreach ($retour as $cle=>$val){
  574. if (($pos = strpos($cle, '.'))!==false){
  575. $cle = substr($cle,++$pos);
  576. }
  577. $new[$cle] = $val;
  578. }
  579. $retour = &$new;
  580. }
  581. return $retour;
  582. }
  583. function spip_sqlite_seek($r, $row_number, $serveur='',$requeter=true) {
  584. if ($r){
  585. $link = _sqlite_link($serveur);
  586. if (_sqlite_is_version(3, $link)){
  587. // encore un truc de bien fichu : PDO ne PEUT PAS faire de seek ou de rewind...
  588. // je me demande si pour sqlite 3 il ne faudrait pas mieux utiliser
  589. // les nouvelles fonctions sqlite3_xx (mais encore moins presentes...)
  590. return false;
  591. }
  592. else {
  593. return sqlite_seek($r, $row_number);
  594. }
  595. }
  596. }
  597. // http://doc.spip.org/@spip_sqlite_free
  598. function spip_sqlite_free(&$r, $serveur='',$requeter=true) {
  599. unset($r);
  600. return true;
  601. //return sqlite_free_result($r);
  602. }
  603. // http://doc.spip.org/@spip_sqlite_get_charset
  604. function spip_sqlite_get_charset($charset=array(), $serveur='',$requeter=true){
  605. //$c = !$charset ? '' : (" LIKE "._q($charset['charset']));
  606. //return spip_sqlite_fetch(sqlite_query(_sqlite_link($serveur), "SHOW CHARACTER SET$c"), NULL, $serveur);
  607. }
  608. // http://doc.spip.org/@spip_sqlite_hex
  609. function spip_sqlite_hex($v){
  610. return hexdec($v);
  611. }
  612. // http://doc.spip.org/@spip_sqlite_in
  613. function spip_sqlite_in($val, $valeurs, $not='', $serveur='',$requeter=true) {
  614. $n = $i = 0;
  615. $in_sql ="";
  616. while ($n = strpos($valeurs, ',', $n+1)) {
  617. if ((++$i) >= 255) {
  618. $in_sql .= "($val $not IN (" .
  619. substr($valeurs, 0, $n) .
  620. "))\n" .
  621. ($not ? "AND\t" : "OR\t");
  622. $valeurs = substr($valeurs, $n+1);
  623. $i = $n = 0;
  624. }
  625. }
  626. $in_sql .= "($val $not IN ($valeurs))";
  627. return "($in_sql)";
  628. }
  629. // http://doc.spip.org/@spip_sqlite_insert
  630. function spip_sqlite_insert($table, $champs, $valeurs, $desc='', $serveur='',$requeter=true) {
  631. $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0];
  632. $prefixe = $connexion['prefixe'];
  633. $sqlite = $connexion['link'];
  634. $db = $connexion['db'];
  635. if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table);
  636. if (isset($_GET['var_profile'])) {
  637. include_spip('public/tracer');
  638. $t = trace_query_start();
  639. } else $t = 0 ;
  640. $query="INSERT INTO $table ".($champs?"$champs VALUES $valeurs":"DEFAULT VALUES");
  641. if ($r = spip_sqlite_query($query, $serveur, $requeter)) {
  642. if (!$requeter) return $r;
  643. if (_sqlite_is_version(3, $sqlite)) $nb = $sqlite->lastInsertId();
  644. else $nb = sqlite_last_insert_rowid($sqlite);
  645. } else $nb = 0;
  646. $err = spip_sqlite_error($query, $serveur);
  647. return $t ? trace_query_end($query, $t, $nb, $err, $serveur) : $nb;
  648. }
  649. // http://doc.spip.org/@spip_sqlite_insertq
  650. function spip_sqlite_insertq($table, $couples=array(), $desc=array(), $serveur='',$requeter=true) {
  651. if (!$desc) $desc = description_table($table);
  652. if (!$desc) die("$table insertion sans description");
  653. $fields = isset($desc['field'])?$desc['field']:array();
  654. foreach ($couples as $champ => $val) {
  655. $couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]);
  656. }
  657. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  658. $couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
  659. // si aucun champ donne pour l'insertion, on en cherche un avec un DEFAULT
  660. // sinon sqlite3 ne veut pas inserer
  661. $cles = $valeurs = "";
  662. if (count($couples)) {
  663. $cles = "(".join(',',array_keys($couples)).")";
  664. $valeurs = "(".join(',', $couples).")";
  665. }
  666. return spip_sqlite_insert($table, $cles , $valeurs , $desc, $serveur, $requeter);
  667. }
  668. // http://doc.spip.org/@spip_sqlite_insertq_multi
  669. function spip_sqlite_insertq_multi($table, $tab_couples=array(), $desc=array(), $serveur='',$requeter=true) {
  670. foreach ($tab_couples as $couples) {
  671. $retour = spip_sqlite_insertq($table, $couples, $desc, $serveur, $requeter);
  672. }
  673. // renvoie le dernier id d'autoincrement ajoute
  674. return $retour;
  675. }
  676. // http://doc.spip.org/@spip_sqlite_listdbs
  677. function spip_sqlite_listdbs($serveur='',$requeter=true) {
  678. _sqlite_init();
  679. if (!is_dir($d = substr(_DIR_DB,0,-1))){
  680. return array();
  681. }
  682. include_spip('inc/flock');
  683. $bases = preg_files($d, $pattern = '(.*)\.sqlite$');
  684. $bds = array();
  685. foreach($bases as $b){
  686. // pas de bases commencant pas sqlite
  687. // (on s'en sert pour l'installation pour simuler la presence d'un serveur)
  688. // les bases sont de la forme _sqliteX_tmp_spip_install.sqlite
  689. if (strpos($b, '_sqlite')) continue;
  690. $bds[] = preg_replace(";.*/$pattern;iS",'$1', $b);
  691. }
  692. return $bds;
  693. }
  694. // http://doc.spip.org/@spip_sqlite_multi
  695. function spip_sqlite_multi ($objet, $lang) {
  696. $r = "PREG_REPLACE("
  697. . $objet
  698. . ",'<multi>.*[\[]"
  699. . $lang
  700. . "[\]]([^\[]*).*</multi>', '$1') AS multi";
  701. return $r;
  702. }
  703. /**
  704. * Optimise une table SQL
  705. * Note: Sqlite optimise TOUTE un fichier sinon rien.
  706. * On evite donc 2 traitements sur la meme base dans un hit.
  707. *
  708. * @param $table nom de la table a optimiser
  709. * @param $serveur nom de la connexion
  710. * @param $requeter effectuer la requete ? sinon retourner son code
  711. * @return bool|string true / false / requete
  712. **/
  713. // http://doc.spip.org/@spip_sqlite_optimize
  714. function spip_sqlite_optimize($table, $serveur='', $requeter=true) {
  715. static $do = false;
  716. if ($requeter and $do) {return true;}
  717. if ($requeter) { $do = true; }
  718. return spip_sqlite_query("VACUUM", $serveur, $requeter);
  719. }
  720. // avoir le meme comportement que _q()
  721. function spip_sqlite_quote($v, $type=''){
  722. if (is_array($v)) return join(",", array_map('spip_sqlite_quote', $v));
  723. if (is_int($v)) return strval($v);
  724. if (strncmp($v,'0x',2)==0 AND ctype_xdigit(substr($v,2))) return hexdec(substr($v,2));
  725. if ($type === 'int' AND !$v) return '0';
  726. if (function_exists('sqlite_escape_string')) {
  727. return "'" . sqlite_escape_string($v) . "'";
  728. }
  729. // trouver un link sqlite3 pour faire l'echappement
  730. foreach ($GLOBALS['connexions'] as $s) {
  731. if (_sqlite_is_version(3, $l = $s['link'])){
  732. return $l->quote($v);
  733. }
  734. }
  735. }
  736. /**
  737. * Tester si une date est proche de la valeur d'un champ
  738. *
  739. * @param string $champ le nom du champ a tester
  740. * @param int $interval valeur de l'interval : -1, 4, ...
  741. * @param string $unite utite utilisee (DAY, MONTH, YEAR, ...)
  742. * @return string expression SQL
  743. **/
  744. function spip_sqlite_date_proche($champ, $interval, $unite)
  745. {
  746. $op = $interval > 0 ? '>' : '<';
  747. return "($champ $op datetime('" . date("Y-m-d H:i:s") . "', '$interval $unite'))";
  748. }
  749. // http://doc.spip.org/@spip_sqlite_replace
  750. function spip_sqlite_replace($table, $couples, $desc=array(), $serveur='',$requeter=true) {
  751. if (!$desc) $desc = description_table($table);
  752. if (!$desc) die("$table insertion sans description");
  753. $fields = isset($desc['field'])?$desc['field']:array();
  754. foreach ($couples as $champ => $val) {
  755. $couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]);
  756. }
  757. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  758. $couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
  759. return spip_sqlite_query("REPLACE INTO $table (" . join(',',array_keys($couples)) . ') VALUES (' .join(',',$couples) . ')', $serveur);
  760. }
  761. // http://doc.spip.org/@spip_sqlite_replace_multi
  762. function spip_sqlite_replace_multi($table, $tab_couples, $desc=array(), $serveur='',$requeter=true) {
  763. // boucler pour trainter chaque requete independemment
  764. foreach ($tab_couples as $couples){
  765. $retour = spip_sqlite_replace($table, $couples, $desc, $serveur,$requeter);
  766. }
  767. // renvoie le dernier id
  768. return $retour;
  769. }
  770. // http://doc.spip.org/@spip_sqlite_select
  771. function spip_sqlite_select($select, $from, $where='', $groupby='', $orderby='', $limit='', $having='', $serveur='',$requeter=true) {
  772. // version() n'est pas connu de sqlite
  773. $select = str_replace('version()', 'sqlite_version()',$select);
  774. // recomposer from
  775. $from = (!is_array($from) ? $from : _sqlite_calculer_select_as($from));
  776. $query =
  777. _sqlite_calculer_expression('SELECT', $select, ', ')
  778. . _sqlite_calculer_expression('FROM', $from, ', ')
  779. . _sqlite_calculer_expression('WHERE', $where)
  780. . _sqlite_calculer_expression('GROUP BY', $groupby, ',')
  781. . _sqlite_calculer_expression('HAVING', $having)
  782. . ($orderby ? ("\nORDER BY " . _sqlite_calculer_order($orderby)) :'')
  783. . ($limit ? "\nLIMIT $limit" : '');
  784. return spip_sqlite_query($query, $serveur, $requeter);
  785. }
  786. // http://doc.spip.org/@spip_sqlite_selectdb
  787. function spip_sqlite_selectdb($db, $serveur='',$requeter=true) {
  788. _sqlite_init();
  789. // interdire la creation d'une nouvelle base,
  790. // sauf si on est dans l'installation
  791. if (!is_file($f = _DIR_DB . $db . '.sqlite')
  792. && (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL))
  793. return false;
  794. // se connecter a la base indiquee
  795. // avec les identifiants connus
  796. $index = $serveur ? $serveur : 0;
  797. if ($link = spip_connect_db('', '', '', '', '@selectdb@' . $db , $serveur, '', '')){
  798. if (($db==$link['db']) && $GLOBALS['connexions'][$index] = $link)
  799. return $db;
  800. } else {
  801. spip_log("Impossible de selectionner la base $db", 'sqlite');
  802. return false;
  803. }
  804. }
  805. // http://doc.spip.org/@spip_sqlite_set_charset
  806. function spip_sqlite_set_charset($charset, $serveur='',$requeter=true){
  807. #spip_log("changement de charset sql : "."SET NAMES "._q($charset));
  808. # return spip_sqlite_query("SET NAMES ". spip_sqlite_quote($charset), $serveur); //<-- Passe pas !
  809. }
  810. // http://doc.spip.org/@spip_sqlite_showbase
  811. function spip_sqlite_showbase($match, $serveur='',$requeter=true){
  812. // type est le type d'entrée : table / index / view
  813. // on ne retourne que les tables (?) et non les vues...
  814. # ESCAPE non supporte par les versions sqlite <3
  815. # return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name LIKE "._q($match)." ESCAPE '\'", $serveur, $requeter);
  816. $match = preg_quote($match);
  817. $match = str_replace("\\\_","[[TIRETBAS]]",$match);
  818. $match = str_replace("\\\%","[[POURCENT]]",$match);
  819. $match = str_replace("_",".",$match);
  820. $match = str_replace("%",".*",$match);
  821. $match = str_replace("[[TIRETBAS]]","_",$match);
  822. $match = str_replace("[[POURCENT]]","%",$match);
  823. $match = "^$match$";
  824. return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name REGEXP "._q($match), $serveur, $requeter);
  825. }
  826. // http://doc.spip.org/@spip_sqlite_showtable
  827. function spip_sqlite_showtable($nom_table, $serveur='',$requeter=true){
  828. $query =
  829. 'SELECT sql, type FROM'
  830. . ' (SELECT * FROM sqlite_master UNION ALL'
  831. . ' SELECT * FROM sqlite_temp_master)'
  832. . " WHERE tbl_name LIKE '$nom_table'"
  833. . " AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'"
  834. . ' ORDER BY substr(type,2,1), name';
  835. $a = spip_sqlite_query($query, $serveur, $requeter);
  836. if (!$a) return "";
  837. if (!$requeter) return $a;
  838. if (!($a = spip_sqlite_fetch($a, null, $serveur))) return "";
  839. $vue = ($a['type'] == 'view'); // table | vue
  840. // c'est une table
  841. // il faut parser le create
  842. if (!$vue) {
  843. if (!preg_match("/^[^(),]*\((([^()]*(\([^()]*\))?[^()]*)*)\)[^()]*$/", array_shift($a), $r))
  844. return "";
  845. else {
  846. $dec = $r[1];
  847. if (preg_match("/^(.*?),([^,]*KEY.*)$/s", $dec, $r)) {
  848. $namedkeys = $r[2];
  849. $dec = $r[1];
  850. }
  851. else
  852. $namedkeys = "";
  853. $fields = array();
  854. foreach (explode(",",$dec) as $v) {
  855. preg_match("/^\s*([^\s]+)\s+(.*)/",$v,$r);
  856. // trim car 'Sqlite Manager' (plugin Firefox) utilise des guillemets
  857. // lorsqu'on modifie une table avec cet outil.
  858. // possible que d'autres fassent de meme.
  859. $fields[ trim(strtolower($r[1]),'"') ] = $r[2];
  860. }
  861. // key inclues dans la requete
  862. $keys = array();
  863. foreach(preg_split('/\)\s*,?/',$namedkeys) as $v) {
  864. if (preg_match("/^\s*([^(]*)\((.*)$/",$v,$r)) {
  865. $k = str_replace("`", '', trim($r[1]));
  866. $t = trim(strtolower(str_replace("`", '', $r[2])), '"');
  867. if ($k && !isset($keys[$k])) $keys[$k] = $t; else $keys[] = $t;
  868. }
  869. }
  870. // sinon ajouter les key index
  871. $query =
  872. 'SELECT name,sql FROM'
  873. . ' (SELECT * FROM sqlite_master UNION ALL'
  874. . ' SELECT * FROM sqlite_temp_master)'
  875. . " WHERE tbl_name LIKE '$nom_table'"
  876. . " AND type='index' AND name NOT LIKE 'sqlite_%'"
  877. . 'ORDER BY substr(type,2,1), name';
  878. $a = spip_sqlite_query($query, $serveur, $requeter);
  879. while ($r = spip_sqlite_fetch($a, null, $serveur)) {
  880. $key = str_replace($nom_table.'_','',$r['name']); // enlever le nom de la table ajoute a l'index
  881. $colonnes = preg_replace(',.*\((.*)\).*,','$1',$r['sql']);
  882. $keys['KEY '.$key] = $colonnes;
  883. }
  884. }
  885. // c'est une vue, on liste les champs disponibles simplement
  886. } else {
  887. if ($res = sql_fetsel('*',$nom_table,'','','','1','',$serveur)){ // limit 1
  888. $fields = array();
  889. foreach($res as $c=>$v) $fields[$c]='';
  890. $keys = array();
  891. } else {
  892. return "";
  893. }
  894. }
  895. return array('field' => $fields, 'key' => $keys);
  896. }
  897. // http://doc.spip.org/@spip_sqlite_update
  898. function spip_sqlite_update($table, $champs, $where='', $desc='', $serveur='',$requeter=true) {
  899. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  900. $champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur);
  901. $set = array();
  902. foreach ($champs as $champ => $val)
  903. $set[] = $champ . "=$val";
  904. if (!empty($set))
  905. return spip_sqlite_query(
  906. _sqlite_calculer_expression('UPDATE', $table, ',')
  907. . _sqlite_calculer_expression('SET', $set, ',')
  908. . _sqlite_calculer_expression('WHERE', $where),
  909. $serveur, $requeter);
  910. }
  911. // http://doc.spip.org/@spip_sqlite_updateq
  912. function spip_sqlite_updateq($table, $champs, $where='', $desc=array(), $serveur='',$requeter=true) {
  913. if (!$champs) return;
  914. if (!$desc) $desc = description_table($table);
  915. if (!$desc) die("$table insertion sans description");
  916. $fields = $desc['field'];
  917. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  918. $champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur);
  919. $set = array();
  920. foreach ($champs as $champ => $val) {
  921. $set[] = $champ . '=' . _sqlite_calculer_cite($val, $fields[$champ]);
  922. }
  923. return spip_sqlite_query(
  924. _sqlite_calculer_expression('UPDATE', $table, ',')
  925. . _sqlite_calculer_expression('SET', $set, ',')
  926. . _sqlite_calculer_expression('WHERE', $where),
  927. $serveur, $requeter);
  928. }
  929. /*
  930. *
  931. * Ensuite les fonctions non abstraites
  932. * crees pour l'occasion de sqlite
  933. *
  934. */
  935. // fonction pour la premiere connexion a un serveur SQLite
  936. // http://doc.spip.org/@_sqlite_init
  937. function _sqlite_init(){
  938. if (!defined('_DIR_DB')) define('_DIR_DB', _DIR_ETC . 'bases/');
  939. if (!defined('_SQLITE_CHMOD')) define('_SQLITE_CHMOD', _SPIP_CHMOD);
  940. if (!is_dir($d = _DIR_DB)){
  941. include_spip('inc/flock');
  942. sous_repertoire($d);
  943. }
  944. }
  945. // teste la version sqlite du link en cours
  946. // http://doc.spip.org/@_sqlite_is_version
  947. function _sqlite_is_version($version='', $link='', $serveur='',$requeter=true){
  948. if ($link==='') $link = _sqlite_link($serveur);
  949. if (!$link) return false;
  950. if (is_a($link, 'PDO')){
  951. $v = 3;
  952. } else {
  953. $v = 2;
  954. }
  955. if (!$version) return $v;
  956. return ($version == $v);
  957. }
  958. // retrouver un link (et definir les fonctions externes sqlite->php)
  959. // $recharger devient inutile (a supprimer ?)
  960. // http://doc.spip.org/@_sqlite_link
  961. function _sqlite_link($serveur = '', $recharger = false){
  962. static $charge = array();
  963. if ($recharger) $charge[$serveur] = false;
  964. $link = &$GLOBALS['connexions'][$serveur ? $serveur : 0]['link'];
  965. if ($link && !$charge[$serveur]){
  966. include_spip('req/sqlite_fonctions');
  967. _sqlite_init_functions($link);
  968. $charge[$serveur] = true;
  969. }
  970. return $link;
  971. }
  972. /* ordre alphabetique pour les autres */
  973. // renvoie les bons echappements (pas sur les fonctions now())
  974. // http://doc.spip.org/@_sqlite_calculer_cite
  975. function _sqlite_calculer_cite($v, $type) {
  976. if (sql_test_date($type) AND preg_match('/^\w+\(/', $v))
  977. return $v;
  978. if (sql_test_int($type)) {
  979. if (is_numeric($v))
  980. return $v;
  981. if (ctype_xdigit(substr($v,2)) AND strncmp($v,'0x',2)==0)
  982. return hexdec(substr($v,2));
  983. }
  984. //else return ("'" . spip_sqlite_quote($v) . "'");
  985. return (spip_sqlite_quote($v));
  986. }
  987. // renvoie grosso modo "$expression join($join, $v)"
  988. // http://doc.spip.org/@_sqlite_calculer_expression
  989. function _sqlite_calculer_expression($expression, $v, $join = 'AND'){
  990. if (empty($v))
  991. return '';
  992. $exp = "\n$expression ";
  993. if (!is_array($v)) {
  994. return $exp . $v;
  995. } else {
  996. if (strtoupper($join) === 'AND')
  997. return $exp . join("\n\t$join ", array_map('_sqlite_calculer_where', $v));
  998. else
  999. return $exp . join($join, $v);
  1000. }
  1001. }
  1002. // pour conversion 0+x ? (pas la peine en sqlite)
  1003. // http://doc.spip.org/@_sqlite_calculer_order
  1004. function _sqlite_calculer_order($orderby) {
  1005. return (is_array($orderby)) ? join(", ", $orderby) : $orderby;
  1006. }
  1007. // renvoie des 'nom AS alias'
  1008. // http://doc.spip.org/@_sqlite_calculer_select_as
  1009. function _sqlite_calculer_select_as($args){
  1010. $res = '';
  1011. foreach($args as $k => $v) {
  1012. if (substr($k,-1)=='@') {
  1013. // c'est une jointure qui se refere au from precedent
  1014. // pas de virgule
  1015. $res .= ' ' . $v ;
  1016. }
  1017. else {
  1018. if (!is_numeric($k)) {
  1019. $p = strpos($v, " ");
  1020. if ($p)
  1021. $v = substr($v,0,$p) . " AS '$k'" . substr($v,$p);
  1022. else $v .= " AS '$k'";
  1023. }
  1024. $res .= ', ' . $v ;
  1025. }
  1026. }
  1027. return substr($res,2) . $join;
  1028. }
  1029. // renvoie les bonnes parentheses pour des where imbriquees
  1030. // http://doc.spip.org/@_sqlite_calculer_where
  1031. function _sqlite_calculer_where($v){
  1032. if (!is_array($v))
  1033. return $v ;
  1034. $op = array_shift($v);
  1035. if (!($n=count($v)))
  1036. return $op;
  1037. else {
  1038. $arg = _sqlite_calculer_where(array_shift($v));
  1039. if ($n==1) {
  1040. return "$op($arg)";
  1041. } else {
  1042. $arg2 = _sqlite_calculer_where(array_shift($v));
  1043. if ($n==2) {
  1044. return "($arg $op $arg2)";
  1045. } else return "($arg $op ($arg2) : $v[0])";
  1046. }
  1047. }
  1048. }
  1049. /*
  1050. * Charger les modules sqlite (si possible) (juste la version demandee),
  1051. * ou, si aucune version, renvoie les versions sqlite dispo
  1052. * sur ce serveur dans un array
  1053. */
  1054. // http://doc.spip.org/@_sqlite_charger_version
  1055. function _sqlite_charger_version($version=''){
  1056. $versions = array();
  1057. // version 2
  1058. if (!$version || $version == 2){
  1059. if (charger_php_extension('sqlite')) {
  1060. $versions[]=2;
  1061. }
  1062. }
  1063. // version 3
  1064. if (!$version || $version == 3){
  1065. if (charger_php_extension('pdo') && charger_php_extension('pdo_sqlite')) {
  1066. $versions[]=3;
  1067. }
  1068. }
  1069. if ($version) return in_array($version, $versions);
  1070. return $versions;
  1071. }
  1072. /**
  1073. * Gestion des requetes ALTER non reconnues de SQLite :
  1074. * ALTER TABLE table DROP column
  1075. * ALTER TABLE table CHANGE [COLUMN] columnA columnB definition
  1076. * ALTER TABLE table MODIFY column definition
  1077. * ALTER TABLE table ADD|DROP PRIMARY KEY
  1078. *
  1079. * (MODIFY transforme en CHANGE columnA columnA) par spip_sqlite_alter()
  1080. *
  1081. * 1) creer une table B avec le nouveau format souhaite
  1082. * 2) copier la table d'origine A vers B
  1083. * 3) supprimer la table A
  1084. * 4) renommer la table B en A
  1085. * 5) remettre les index (qui sont supprimes avec la table A)
  1086. *
  1087. * @param string/array $table : nom_table, array(nom_table=>nom_futur)
  1088. * @param string/array $col : nom_colonne, array(nom_colonne=>nom_futur)
  1089. * @param array $opt : options comme les tables spip, qui sera merge a la table creee : array('field'=>array('nom'=>'syntaxe', ...), 'key'=>array('KEY nom'=>'colonne', ...))
  1090. * @param string $serveur : nom de la connexion sql en cours
  1091. *
  1092. */
  1093. // http://doc.spip.org/@_sqlite_modifier_table
  1094. function _sqlite_modifier_table($table, $colonne, $opt=array(), $serveur=''){
  1095. if (is_array($table)) {
  1096. $table_origine = array_shift(array_keys($table));
  1097. $table_destination = array_shift($table);
  1098. } else {
  1099. $table_origine = $table_destination = $table;
  1100. }
  1101. // ne prend actuellement qu'un changement
  1102. // mais pourra etre adapte pour changer plus qu'une colonne a la fois
  1103. if (is_array($colonne)) {
  1104. $colonne_origine = array_shift(array_keys($colonne));
  1105. $colonne_destination = array_shift($colonne);
  1106. } else {
  1107. $colonne_origine = $colonne_destination = $colonne;
  1108. }
  1109. if (!isset($opt['field'])) $opt['field'] = array();
  1110. if (!isset($opt['key'])) $opt['key'] = array();
  1111. // si les noms de tables sont differents, pas besoin de table temporaire
  1112. // on prendra directement le nom de la future table
  1113. $meme_table = ($table_origine == $table_destination);
  1114. $def_origine = sql_showtable($table_origine, false, $serveur);
  1115. $table_tmp = $table_origine . '_tmp';
  1116. // 1) creer une table temporaire avec les modifications
  1117. // - DROP : suppression de la colonne
  1118. // - CHANGE : modification de la colonne
  1119. // (foreach pour conserver l'ordre des champs)
  1120. // field
  1121. $fields = array();
  1122. // pour le INSERT INTO plus loin
  1123. // stocker la correspondance nouvelles->anciennes colonnes
  1124. $fields_correspondances = array();
  1125. foreach ($def_origine['field'] as $c=>$d){
  1126. if ($colonne_origine && ($c == $colonne_origine)) {
  1127. // si pas DROP
  1128. if ($colonne_destination){
  1129. $fields[$colonne_destination] = $opt['field'][$colonne_destination];
  1130. $fields_correspondances[$colonne_destination] = $c;
  1131. }
  1132. } else {
  1133. $fields[$c] = $d;
  1134. $fields_correspondances[$c] = $c;
  1135. }
  1136. }
  1137. // cas de ADD sqlite2 (ajout du champ en fin de table):
  1138. if (!$colonne_origine && $colonne_destination){
  1139. $fields[$colonne_destination] = $opt['field'][$colonne_destination];
  1140. }
  1141. // key...
  1142. $keys = array();
  1143. foreach ($def_origine['key'] as $c=>$d){
  1144. $c = str_replace($colonne_origine,$colonne_destination,$c);
  1145. $d = str_replace($colonne_origine,$colonne_destination,$d);
  1146. // seulement si on ne supprime pas la colonne !
  1147. if ($d)
  1148. $keys[$c] = $d;
  1149. }
  1150. // autres keys, on merge
  1151. $keys = array_merge($keys,$opt['key']);
  1152. $queries = array();
  1153. $queries[] = 'BEGIN TRANSACTION';
  1154. // copier dans destination (si differente de origine), sinon tmp
  1155. $table_copie = ($meme_table) ? $table_tmp : $table_destination;
  1156. if ($q = _sqlite_requete_create(
  1157. $table_copie,
  1158. $fields,
  1159. $keys,
  1160. $autoinc=false,
  1161. $temporary=false,
  1162. $ifnotexists=true,
  1163. $serveur)){
  1164. $queries[] = $q;
  1165. }
  1166. // 2) y copier les champs qui vont bien
  1167. $champs_dest = join(', ', array_keys($fields_correspondances));
  1168. $champs_ori = join(', ', $fields_correspondances);
  1169. $queries[] = "INSERT INTO $table_copie ($champs_dest) SELECT $champs_ori FROM $table_origine";
  1170. // 3) supprimer la table d'origine
  1171. $queries[] = "DROP TABLE $table_origine";
  1172. // 4) renommer la table temporaire
  1173. // avec le nom de la table destination
  1174. // si necessaire
  1175. if ($meme_table){
  1176. if (_sqlite_is_version(3, '', $serveur)){
  1177. $queries[] = "ALTER TABLE $table_copie RENAME TO $table_destination";
  1178. } else {
  1179. $queries[] = _sqlite_requete_create(
  1180. $table_destination,
  1181. $fields,
  1182. $keys,
  1183. $autoinc=false,
  1184. $temporary=false,
  1185. $ifnotexists=false, // la table existe puisqu'on est dans une transaction
  1186. $serveur);
  1187. $queries[] = "INSERT INTO $table_destination SELECT * FROM $table_copie";
  1188. $queries[] = "DROP TABLE $table_copie";
  1189. }
  1190. }
  1191. // 5) remettre les index !
  1192. foreach ($keys as $k=>$v) {
  1193. if ($k=='PRIMARY KEY'){}
  1194. else {
  1195. // enlever KEY
  1196. $k = substr($k,4);
  1197. $queries[] = "CREATE INDEX $table_destination"."_$k ON $table_destination ($v)";
  1198. }
  1199. }
  1200. $queries[] = "COMMIT";
  1201. // il faut les faire une par une car $query = join('; ', $queries).";"; ne fonctionne pas
  1202. foreach ($queries as $q){
  1203. $req = new sqlite_traiter_requete($q, $serveur);
  1204. if (!$req->executer_requete()){
  1205. spip_log("SQLite : ALTER TABLE table :"
  1206. ." Erreur a l'execution de la requete : $q",'sqlite');
  1207. return false;
  1208. }
  1209. }
  1210. return true;
  1211. }
  1212. /*
  1213. * Nom des fonctions
  1214. */
  1215. // http://doc.spip.org/@_sqlite_ref_fonctions
  1216. function _sqlite_ref_fonctions(){
  1217. $fonctions = array(
  1218. 'alter' => 'spip_sqlite_alter',
  1219. 'count' => 'spip_sqlite_count',
  1220. 'countsel' => 'spip_sqlite_countsel',
  1221. 'create' => 'spip_sqlite_create',
  1222. 'create_base' => 'spip_sqlite_create_base',
  1223. 'create_view' => 'spip_sqlite_create_view',
  1224. 'date_proche' => 'spip_sqlite_date_proche',
  1225. 'delete' => 'spip_sqlite_delete',
  1226. 'drop_table' => 'spip_sqlite_drop_table',
  1227. 'drop_view' => 'spip_sqlite_drop_view',
  1228. 'errno' => 'spip_sqlite_errno',
  1229. 'error' => 'spip_sqlite_error',
  1230. 'explain' => 'spip_sqlite_explain',
  1231. 'fetch' => 'spip_sqlite_fetch',
  1232. 'seek' => 'spip_sqlite_seek',
  1233. 'free' => 'spip_sqlite_free',
  1234. 'hex' => 'spip_sqlite_hex',
  1235. 'in' => 'spip_sqlite_in',
  1236. 'insert' => 'spip_sqlite_insert',
  1237. 'insertq' => 'spip_sqlite_insertq',
  1238. 'insertq_multi' => 'spip_sqlite_insertq_multi',
  1239. 'listdbs' => 'spip_sqlite_listdbs',
  1240. 'multi' => 'spip_sqlite_multi',
  1241. 'optimize' => 'spip_sqlite_optimize',
  1242. 'query' => 'spip_sqlite_query',
  1243. 'quote' => 'spip_sqlite_quote',
  1244. 'replace' => 'spip_sqlite_replace',
  1245. 'replace_multi' => 'spip_sqlite_replace_multi',
  1246. 'select' => 'spip_sqlite_select',
  1247. 'selectdb' => 'spip_sqlite_selectdb',
  1248. 'set_charset' => 'spip_sqlite_set_charset',
  1249. 'get_charset' => 'spip_sqlite_get_charset',
  1250. 'showbase' => 'spip_sqlite_showbase',
  1251. 'showtable' => 'spip_sqlite_showtable',
  1252. 'update' => 'spip_sqlite_update',
  1253. 'updateq' => 'spip_sqlite_updateq',
  1254. );
  1255. // association de chaque nom http d'un charset aux couples sqlite
  1256. // SQLite supporte utf-8 et utf-16 uniquement.
  1257. $charsets = array(
  1258. 'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci'),
  1259. //'utf-16be'=>array('charset'=>'utf16be','collation'=>'UTF-16BE'),// aucune idee de quoi il faut remplir dans es champs la
  1260. //'utf-16le'=>array('charset'=>'utf16le','collation'=>'UTF-16LE')
  1261. );
  1262. $fonctions['charsets'] = $charsets;
  1263. return $fonctions;
  1264. }
  1265. // $query est une requete ou une liste de champs
  1266. // http://doc.spip.org/@_sqlite_remplacements_definitions_table
  1267. function _sqlite_remplacements_definitions_table($query,$autoinc=false){
  1268. // quelques remplacements
  1269. $num = "(\s*\([0-9]*\))?";
  1270. $enum = "(\s*\([^\)]*\))?";
  1271. $remplace = array(
  1272. '/enum'.$enum.'/is' => 'VARCHAR',
  1273. '/binary/is' => '',
  1274. '/COLLATE \w+_bin/is' => '',
  1275. '/auto_increment/is' => '',
  1276. '/(timestamp .* )ON .*$/is' => '\\1',
  1277. '/character set \w+/is' => '',
  1278. '/((big|small|medium|tiny)?int(eger)?)'.$num.'\s*unsigned/is' => '\\1 UNSIGNED',
  1279. '/(text\s+not\s+null)\s*$/is' => "\\1 DEFAULT ''",
  1280. );
  1281. // pour l'autoincrement, il faut des INTEGER NOT NULL PRIMARY KEY
  1282. if ($autoinc)
  1283. $remplace['/(big|small|medium|tiny)?int(eger)?'.$num.'/is'] = 'INTEGER';
  1284. return preg_replace(array_keys($remplace), $remplace, $query);
  1285. }
  1286. /*
  1287. * Creer la requete pour la creation d'une table
  1288. * retourne la requete pour utilisation par sql_create() et sql_alter()
  1289. */
  1290. // http://doc.spip.org/@_sqlite_requete_create
  1291. function _sqlite_requete_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $_ifnotexists=true, $serveur='',$requeter=true) {
  1292. $query = $keys = $s = $p = '';
  1293. // certains plugins declarent les tables (permet leur inclusion dans le dump)
  1294. // sans les renseigner (laisse le compilo recuperer la description)
  1295. if (!is_array($champs) || !is_array($cles))
  1296. return;
  1297. // sqlite ne gere pas KEY tout court dans une requete CREATE TABLE
  1298. // il faut passer par des create index
  1299. // Il gere par contre primary key !
  1300. // Soit la PK est definie dans les cles, soit dans un champs
  1301. if (!$c = $cles[$pk = "PRIMARY KEY"]) {
  1302. foreach($champs as $k => $v) {
  1303. if (false !== stripos($v,$pk)) {
  1304. $c = $k;
  1305. // on n'en a plus besoin dans field, vu que defini dans key
  1306. $champs[$k] = preg_replace("/$pk/is", '', $champs[$k]);
  1307. break;
  1308. }
  1309. }
  1310. }
  1311. if ($c) $keys = "\n\t\t$pk ($c)";
  1312. $champs = _sqlite_remplacements_definitions_table($champs, $autoinc);
  1313. foreach($champs as $k => $v) {
  1314. $query .= "$s\n\t\t$k $v";
  1315. $s = ",";
  1316. }
  1317. $ifnotexists = "";
  1318. if ($_ifnotexists) {
  1319. // simuler le IF NOT EXISTS - version 2
  1320. if (_sqlite_is_version(2, '', $serveur)){
  1321. $a = spip_sqlite_showtable($nom, $serveur);
  1322. if ($a) return false;
  1323. }
  1324. // sinon l'ajouter en version 3
  1325. else {
  1326. $ifnotexists = ' IF NOT EXISTS';
  1327. }
  1328. }
  1329. $temporary = $temporary ? ' TEMPORARY':'';
  1330. $q = "CREATE$temporary TABLE$ifnotexists $nom ($query" . ($keys ? ",$keys" : '') . ")\n";
  1331. return $q;
  1332. }
  1333. /*
  1334. * Retrouver les champs 'timestamp'
  1335. * pour les ajouter aux 'insert' ou 'replace'
  1336. * afin de simuler le fonctionnement de mysql
  1337. *
  1338. * stocke le resultat pour ne pas faire
  1339. * de requetes showtable intempestives
  1340. */
  1341. // http://doc.spip.org/@_sqlite_ajouter_champs_timestamp
  1342. function _sqlite_ajouter_champs_timestamp($table, $couples, $desc='', $serveur=''){
  1343. static $tables = array();
  1344. if (!isset($tables[$table])){
  1345. if (!$desc){
  1346. $f = charger_fonction('trouver_table', 'base');
  1347. $desc = $f($table, $serveur);
  1348. // si pas de description, on ne fait rien, ou on die() ?
  1349. if (!$desc OR !$desc['field']) return $couples;
  1350. }
  1351. // recherche des champs avec simplement 'TIMESTAMP'
  1352. // cependant, il faudra peut etre etendre
  1353. // avec la gestion de DEFAULT et ON UPDATE
  1354. // mais ceux-ci ne sont pas utilises dans le core
  1355. $tables[$table] = array();
  1356. foreach ($desc['field'] as $k=>$v){
  1357. if (strpos(strtolower(ltrim($v)), 'timestamp')===0)
  1358. $tables[$table][] = $k;
  1359. }
  1360. }
  1361. // ajout des champs type 'timestamp' absents
  1362. foreach ($tables[$table] as $maj){
  1363. if (!array_key_exists($maj, $couples))
  1364. $couples[$maj] = "datetime('now')";
  1365. }
  1366. return $couples;
  1367. }
  1368. /*
  1369. * renvoyer la liste des versions sqlite disponibles
  1370. * sur le serveur
  1371. */
  1372. // http://doc.spip.org/@spip_versions_sqlite
  1373. function spip_versions_sqlite(){
  1374. return _sqlite_charger_version();
  1375. }
  1376. /*
  1377. * Classe pour partager les lancements de requete
  1378. * - peut corriger la syntaxe des requetes pour la conformite a sqlite
  1379. * - peut tracer les requetes
  1380. *
  1381. * Cette classe est presente essentiellement pour un preg_replace_callback
  1382. * avec des parametres dans la fonction appelee que l'on souhaite incrementer
  1383. * (fonction pour proteger les textes)
  1384. *
  1385. */
  1386. class sqlite_traiter_requete{
  1387. var $query = ''; // la requete
  1388. var $queryCount = ''; // la requete pour compter
  1389. var $serveur = ''; // le serveur
  1390. var $link = ''; // le link (ressource) sqlite
  1391. var $prefixe = ''; // le prefixe des tables
  1392. var $db = ''; // le nom de la base
  1393. var $tracer = false; // doit-on tracer les requetes (var_profile)
  1394. var $sqlite_version = ''; // Version de sqlite (2 ou 3)
  1395. // Pour les corrections a effectuer sur les requetes :
  1396. var $textes = array(); // array(code=>'texte') trouvé
  1397. var $codeEchappements = "%@##@%";
  1398. // constructeur
  1399. // http://doc.spip.org/@sqlite_traiter_requete
  1400. function sqlite_traiter_requete($query, $serveur = ''){
  1401. $this->query = $query;
  1402. $this->serveur = strtolower($serveur);
  1403. if (!($this->link = _sqlite_link($this->serveur)) && (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL)){
  1404. spip_log("Aucune connexion sqlite (link)");
  1405. return false;
  1406. }
  1407. $this->sqlite_version =_sqlite_is_version('', $this->link);
  1408. $

Large files files are truncated, but you can click here to view the full file