[SPIP] ~maj SPIP v3.0.17 --> v3.0.19
[lhc/web/clavette_www.git] / www / ecrire / req / mysql.php
1 <?php
2
3 /* *************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Ce fichier contient les fonctions gerant
15 * les instructions SQL pour MySQL
16 *
17 * @package SPIP\SQL\MySQL
18 */
19
20 if (!defined('_ECRIRE_INC_VERSION')) return;
21
22 // fonction pour la premiere connexion a un serveur MySQL
23
24 // http://doc.spip.org/@req_mysql_dist
25 /**
26 * @param $host
27 * @param $port
28 * @param $login
29 * @param $pass
30 * @param string $db
31 * @param string $prefixe
32 * @return array|bool
33 */
34
35 function req_mysql_dist($host, $port, $login, $pass, $db='', $prefixe='') {
36 if (!charger_php_extension('mysql')) return false;
37 if ($port > 0) $host = "$host:$port";
38 $link = @mysql_connect($host, $login, $pass, true);
39 if (!$link) {
40 spip_log('Echec mysql_connect. Erreur : ' . mysql_error(),'mysql.'._LOG_HS);
41 return false;
42 }
43 $last = '';
44 if (!$db) {
45 $ok = $link;
46 $db = 'spip';
47 } else {
48 $ok = spip_mysql_selectdb($db);
49 if (defined('_MYSQL_SET_SQL_MODE')
50 OR defined('_MYSQL_SQL_MODE_TEXT_NOT_NULL') // compatibilite
51 )
52 mysql_query($last = "set sql_mode=''");
53 }
54 spip_log("Connexion vers $host, base $db, prefixe $prefixe " . ($ok ? "operationnelle sur $link" : 'impossible'), _LOG_DEBUG);
55
56 return !$ok ? false : array(
57 'db' => $db,
58 'last' => $last,
59 'prefixe' => $prefixe ? $prefixe : $db,
60 'link' => $GLOBALS['mysql_rappel_connexion'] ? $link : false,
61 );
62 }
63
64 $GLOBALS['spip_mysql_functions_1'] = array(
65 'alter' => 'spip_mysql_alter',
66 'count' => 'spip_mysql_count',
67 'countsel' => 'spip_mysql_countsel',
68 'create' => 'spip_mysql_create',
69 'create_base' => 'spip_mysql_create_base',
70 'create_view' => 'spip_mysql_create_view',
71 'date_proche' => 'spip_mysql_date_proche',
72 'delete' => 'spip_mysql_delete',
73 'drop_table' => 'spip_mysql_drop_table',
74 'drop_view' => 'spip_mysql_drop_view',
75 'errno' => 'spip_mysql_errno',
76 'error' => 'spip_mysql_error',
77 'explain' => 'spip_mysql_explain',
78 'fetch' => 'spip_mysql_fetch',
79 'seek' => 'spip_mysql_seek',
80 'free' => 'spip_mysql_free',
81 'hex' => 'spip_mysql_hex',
82 'in' => 'spip_mysql_in',
83 'insert' => 'spip_mysql_insert',
84 'insertq' => 'spip_mysql_insertq',
85 'insertq_multi' => 'spip_mysql_insertq_multi',
86 'listdbs' => 'spip_mysql_listdbs',
87 'multi' => 'spip_mysql_multi',
88 'optimize' => 'spip_mysql_optimize',
89 'query' => 'spip_mysql_query',
90 'quote' => 'spip_mysql_quote',
91 'replace' => 'spip_mysql_replace',
92 'replace_multi' => 'spip_mysql_replace_multi',
93 'repair' => 'spip_mysql_repair',
94 'select' => 'spip_mysql_select',
95 'selectdb' => 'spip_mysql_selectdb',
96 'set_charset' => 'spip_mysql_set_charset',
97 'get_charset' => 'spip_mysql_get_charset',
98 'showbase' => 'spip_mysql_showbase',
99 'showtable' => 'spip_mysql_showtable',
100 'update' => 'spip_mysql_update',
101 'updateq' => 'spip_mysql_updateq',
102
103 // association de chaque nom http d'un charset aux couples MySQL
104 'charsets' => array(
105 'cp1250'=>array('charset'=>'cp1250','collation'=>'cp1250_general_ci'),
106 'cp1251'=>array('charset'=>'cp1251','collation'=>'cp1251_general_ci'),
107 'cp1256'=>array('charset'=>'cp1256','collation'=>'cp1256_general_ci'),
108 'iso-8859-1'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
109 //'iso-8859-6'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
110 'iso-8859-9'=>array('charset'=>'latin5','collation'=>'latin5_turkish_ci'),
111 //'iso-8859-15'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
112 'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci'))
113 );
114
115 // http://doc.spip.org/@spip_mysql_set_charset
116 /**
117 * @param $charset
118 * @param string $serveur
119 * @param bool $requeter
120 * @param bool $requeter
121 * @return resource
122 */
123 function spip_mysql_set_charset($charset, $serveur='',$requeter=true,$requeter=true){
124 $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
125 spip_log("changement de charset sql : "."SET NAMES "._q($charset), _LOG_DEBUG);
126 return mysql_query($connexion['last'] = "SET NAMES "._q($charset));
127 }
128
129 // http://doc.spip.org/@spip_mysql_get_charset
130 /**
131
132 * @param array $charset
133 * @param string $serveur
134 * @param bool $requeter
135 * @return array
136 *
137 */
138 function spip_mysql_get_charset($charset=array(), $serveur='',$requeter=true){
139 $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
140 $connexion['last'] = $c = "SHOW CHARACTER SET"
141 . (!$charset ? '' : (" LIKE "._q($charset['charset'])));
142
143 return spip_mysql_fetch(mysql_query($c), NULL, $serveur);
144 }
145
146 // obsolete, ne plus utiliser
147 // http://doc.spip.org/@spip_query_db
148 function spip_query_db($query, $serveur='',$requeter=true) {
149 return spip_mysql_query($query, $serveur, $requeter);
150 }
151
152 // Fonction de requete generale, munie d'une trace a la demande
153
154 // http://doc.spip.org/@spip_mysql_query
155 /**
156
157 * @param $query
158 * @param string $serveur
159 * @param bool $requeter
160 * @return array|null|resource|string
161 *
162 */
163 function spip_mysql_query($query, $serveur='',$requeter=true) {
164
165 $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
166 $prefixe = $connexion['prefixe'];
167 $link = $connexion['link'];
168 $db = $connexion['db'];
169
170 $query = traite_query($query, $db, $prefixe);
171
172 // renvoyer la requete inerte si demandee
173 if (!$requeter) return $query;
174
175 if (isset($_GET['var_profile'])) {
176 include_spip('public/tracer');
177 $t = trace_query_start();
178 } else $t = 0 ;
179
180 $connexion['last'] = $query;
181
182 // ajouter un debug utile dans log/mysql-slow.log ?
183 $debug = '';
184 if (defined('_DEBUG_SLOW_QUERIES') AND _DEBUG_SLOW_QUERIES){
185 if(isset($GLOBALS['debug']['aucasou'])){
186 list(,$id,, $infos) = $GLOBALS['debug']['aucasou'];
187 $debug .= " BOUCLE$id @ ".$infos[0] ." | ";
188 }
189 $debug .= " " . $_SERVER['REQUEST_URI'].' + '.$GLOBALS['ip'];
190 $debug = ' /*'.str_replace('*/','@/',$debug).' */';
191 }
192
193 $r = $link ? mysql_query($query.$debug, $link) : mysql_query($query.$debug);
194
195 if ($e = spip_mysql_errno($serveur)) // Log de l'erreur eventuelle
196 $e .= spip_mysql_error($query, $serveur); // et du fautif
197 return $t ? trace_query_end($query, $t, $r, $e, $serveur) : $r;
198 }
199
200 // http://doc.spip.org/@spip_mysql_alter
201 /**
202 * @param $query
203 * @param string $serveur
204 * @param bool $requeter
205 * @return array|null|resource|string
206 */
207 function spip_mysql_alter($query, $serveur='',$requeter=true){
208 // ici on supprime les ` entourant le nom de table pour permettre
209 // la transposition du prefixe, compte tenu que les plugins ont la mauvaise habitude
210 // d'utiliser ceux-ci, copie-colle de phpmyadmin
211 $query = preg_replace(",^TABLE\s*`([^`]*)`,i","TABLE \\1",$query);
212 return spip_mysql_query("ALTER ".$query, $serveur, $requeter); # i.e. que PG se debrouille
213 }
214
215 // http://doc.spip.org/@spip_mysql_optimize
216 /**
217 * @param $table
218 * @param string $serveur
219 * @param bool $requeter
220 * @return bool
221 */
222 function spip_mysql_optimize($table, $serveur='',$requeter=true){
223 spip_mysql_query("OPTIMIZE TABLE ". $table);
224 return true;
225 }
226
227 // http://doc.spip.org/@spip_mysql_explain
228 /**
229 * @param $query
230 * @param string $serveur
231 * @param bool $requeter
232 * @return array
233 */
234 function spip_mysql_explain($query, $serveur='',$requeter=true){
235 if (strpos(ltrim($query), 'SELECT') !== 0) return array();
236 $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
237 $prefixe = $connexion['prefixe'];
238 $link = $connexion['link'];
239 $db = $connexion['db'];
240
241 $query = 'EXPLAIN ' . traite_query($query, $db, $prefixe);
242 $r = $link ? mysql_query($query, $link) : mysql_query($query);
243 return spip_mysql_fetch($r, NULL, $serveur);
244 }
245 // fonction instance de sql_select, voir ses specs dans abstract.php
246 // traite_query pourrait y etre fait d'avance ce serait moins cher
247 // Les \n et \t sont utiles au debusqueur.
248
249
250 // http://doc.spip.org/@spip_mysql_select
251 /**
252 * @param $select
253 * @param $from
254 * @param string $where
255 * @param string $groupby
256 * @param string $orderby
257 * @param string $limit
258 * @param string $having
259 * @param string $serveur
260 * @param bool $requeter
261 * @return array|null|resource|string
262 */
263 function spip_mysql_select($select, $from, $where='',
264 $groupby='', $orderby='', $limit='', $having='',
265 $serveur='',$requeter=true) {
266
267
268 $from = (!is_array($from) ? $from : spip_mysql_select_as($from));
269 $query =
270 calculer_mysql_expression('SELECT', $select, ', ')
271 . calculer_mysql_expression('FROM', $from, ', ')
272 . calculer_mysql_expression('WHERE', $where)
273 . calculer_mysql_expression('GROUP BY', $groupby, ',')
274 . calculer_mysql_expression('HAVING', $having)
275 . ($orderby ? ("\nORDER BY " . spip_mysql_order($orderby)) :'')
276 . ($limit ? "\nLIMIT $limit" : '');
277
278 // renvoyer la requete inerte si demandee
279 if ($requeter === false) return $query;
280 $r = spip_mysql_query($query, $serveur, $requeter);
281 return $r ? $r : $query;
282 }
283
284 // 0+x avec un champ x commencant par des chiffres est converti par MySQL
285 // en le nombre qui commence x.
286 // Pas portable malheureusement, on laisse pour le moment.
287
288 // http://doc.spip.org/@spip_mysql_order
289 /**
290 * @param $orderby
291 * @return string
292 */
293 function spip_mysql_order($orderby)
294 {
295 return (is_array($orderby)) ? join(", ", $orderby) : $orderby;
296 }
297
298
299 // http://doc.spip.org/@calculer_mysql_where
300 /**
301 * @param $v
302 * @return array|mixed|string
303 */
304 function calculer_mysql_where($v)
305 {
306 if (!is_array($v))
307 return $v ;
308
309 $op = array_shift($v);
310 if (!($n=count($v)))
311 return $op;
312 else {
313 $arg = calculer_mysql_where(array_shift($v));
314 if ($n==1) {
315 return "$op($arg)";
316 } else {
317 $arg2 = calculer_mysql_where(array_shift($v));
318 if ($n==2) {
319 return "($arg $op $arg2)";
320 } else return "($arg $op ($arg2) : $v[0])";
321 }
322 }
323 }
324
325 // http://doc.spip.org/@calculer_mysql_expression
326 /**
327 * @param $expression
328 * @param $v
329 * @param string $join
330 * @return string
331 */
332 function calculer_mysql_expression($expression, $v, $join = 'AND'){
333 if (empty($v))
334 return '';
335
336 $exp = "\n$expression ";
337
338 if (!is_array($v)) {
339 return $exp . $v;
340 } else {
341 if (strtoupper($join) === 'AND')
342 return $exp . join("\n\t$join ", array_map('calculer_mysql_where', $v));
343 else
344 return $exp . join($join, $v);
345 }
346 }
347
348 // http://doc.spip.org/@spip_mysql_select_as
349 /**
350 * @param $args
351 * @return string
352 */
353 function spip_mysql_select_as($args)
354 {
355 $res = '';
356 foreach($args as $k => $v) {
357 if (substr($k,-1)=='@') {
358 // c'est une jointure qui se refere au from precedent
359 // pas de virgule
360 $res .= ' ' . $v ;
361 }
362 else {
363 if (!is_numeric($k)) {
364 $p = strpos($v, " ");
365 if ($p)
366 $v = substr($v,0,$p) . " AS `$k`" . substr($v,$p);
367 else $v .= " AS `$k`";
368 }
369
370 $res .= ', ' . $v ;
371 }
372 }
373 return substr($res,2);
374 }
375
376 //
377 // Changer les noms des tables ($table_prefix)
378 // Quand tous les appels SQL seront abstraits on pourra l'ameliorer
379
380 define('_SQL_PREFIXE_TABLE', '/([,\s])spip_/S');
381
382 // http://doc.spip.org/@traite_query
383 /**
384 * @param $query
385 * @param string $db
386 * @param string $prefixe
387 * @return array|null|string
388 */
389 function traite_query($query, $db='', $prefixe='') {
390
391 if ($GLOBALS['mysql_rappel_nom_base'] AND $db)
392 $pref = '`'. $db.'`.';
393 else $pref = '';
394
395 if ($prefixe)
396 $pref .= $prefixe . "_";
397
398 if (!preg_match('/\s(SET|VALUES|WHERE|DATABASE)\s/i', $query, $regs)) {
399 $suite ='';
400 } else {
401 $suite = strstr($query, $regs[0]);
402 $query = substr($query, 0, -strlen($suite));
403 // propager le prefixe en cas de requete imbriquee
404 // il faut alors echapper les chaine avant de le faire, pour ne pas risquer de
405 // modifier une requete qui est en fait juste du texte dans un champ
406 if (stripos($suite,"SELECT")!==false) {
407 list($suite,$textes) = query_echappe_textes($suite);
408 if (preg_match('/^(.*?)([(]\s*SELECT\b.*)$/si', $suite, $r))
409 $suite = $r[1] . traite_query($r[2], $db, $prefixe);
410 $suite = query_reinjecte_textes($suite, $textes);
411 }
412 }
413 $r = preg_replace(_SQL_PREFIXE_TABLE, '\1'.$pref, $query) . $suite;
414
415 #spip_log("traite_query: " . substr($r,0, 50) . ".... $db, $prefixe", _LOG_DEBUG);
416 return $r;
417 }
418
419 /**
420 * Selectionne une base de donnees
421 *
422 * @param string $nom
423 * Nom de la base a utiliser
424 *
425 * @return bool
426 * True cas de success.
427 * False en cas d'erreur.
428 **/
429 function spip_mysql_selectdb($db) {
430 $ok = mysql_select_db($db);
431 if (!$ok)
432 spip_log('Echec mysql_selectdb. Erreur : ' . mysql_error(),'mysql.'._LOG_CRITIQUE);
433 return $ok;
434 }
435
436
437 /**
438 * Retourne les bases de donnees accessibles
439 *
440 * Retourne un tableau du nom de toutes les bases de donnees
441 * accessibles avec les permissions de l'utilisateur SQL
442 * de cette connexion.
443 * Attention on n'a pas toujours les droits !
444 *
445 * @param string $serveur
446 * Nom du connecteur
447 * @param bool $requeter
448 * Inutilise
449 * @return array
450 * Liste de noms de bases de donnees
451 **/
452 function spip_mysql_listdbs($serveur='',$requeter=true) {
453 $dbs = array();
454 if ($res = spip_mysql_query("SHOW DATABASES")){
455 while($row = mysql_fetch_assoc($res))
456 $dbs[] = $row['Database'];
457 }
458 return $dbs;
459 }
460
461 // Fonction de creation d'une table SQL nommee $nom
462 // a partir de 2 tableaux PHP :
463 // champs: champ => type
464 // cles: type-de-cle => champ(s)
465 // si $autoinc, c'est une auto-increment (i.e. serial) sur la Primary Key
466 // Le nom des caches doit etre inferieur a 64 caracteres
467
468 // http://doc.spip.org/@spip_mysql_create
469 /**
470 * @param $nom
471 * @param $champs
472 * @param $cles
473 * @param bool $autoinc
474 * @param bool $temporary
475 * @param string $serveur
476 * @param bool $requeter
477 * @return array|null|resource|string
478 */
479 function spip_mysql_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $serveur='',$requeter=true) {
480
481 $query = ''; $keys = ''; $s = ''; $p='';
482
483 // certains plugins declarent les tables (permet leur inclusion dans le dump)
484 // sans les renseigner (laisse le compilo recuperer la description)
485 if (!is_array($champs) || !is_array($cles))
486 return;
487
488 $res = spip_mysql_query("SELECT version() as v");
489 if (($row = mysql_fetch_array($res)) && (version_compare($row['v'],'5.0','>='))) {
490 spip_mysql_query("SET sql_mode=''", $serveur);
491 }
492
493 foreach($cles as $k => $v) {
494 $keys .= "$s\n\t\t$k ($v)";
495 if ($k == "PRIMARY KEY")
496 $p = $v;
497 $s = ",";
498 }
499 $s = '';
500
501 $character_set = "";
502 if (@$GLOBALS['meta']['charset_sql_base'])
503 $character_set .= " CHARACTER SET ".$GLOBALS['meta']['charset_sql_base'];
504 if (@$GLOBALS['meta']['charset_collation_sql_base'])
505 $character_set .= " COLLATE ".$GLOBALS['meta']['charset_collation_sql_base'];
506
507 foreach($champs as $k => $v) {
508 $v = _mysql_remplacements_definitions_table($v);
509 if (preg_match(',([a-z]*\s*(\(\s*[0-9]*\s*\))?(\s*binary)?),i',$v,$defs)){
510 if (preg_match(',(char|text),i',$defs[1])
511 AND !preg_match(',(binary|CHARACTER|COLLATE),i',$v) ){
512 $v = $defs[1] . $character_set . ' ' . substr($v,strlen($defs[1]));
513 }
514 }
515
516 $query .= "$s\n\t\t$k $v"
517 . (($autoinc && ($p == $k) && preg_match(',\b(big|small|medium)?int\b,i', $v))
518 ? " auto_increment"
519 : ''
520 );
521 $s = ",";
522 }
523 $temporary = $temporary ? 'TEMPORARY':'';
524 $q = "CREATE $temporary TABLE IF NOT EXISTS $nom ($query" . ($keys ? ",$keys" : '') . ")".
525 ($character_set?" DEFAULT $character_set":"")
526 ."\n";
527 return spip_mysql_query($q, $serveur);
528 }
529
530
531 /**
532 * Adapte pour Mysql la declaration SQL d'une colonne d'une table
533 *
534 * @param string $query
535 * Definition SQL d'un champ de table
536 * @return string
537 * Definition SQL adaptee pour MySQL d'un champ de table
538 */
539 function _mysql_remplacements_definitions_table($query){
540 // quelques remplacements
541 $num = "(\s*\([0-9]*\))?";
542 $enum = "(\s*\([^\)]*\))?";
543
544 $remplace = array(
545 '/VARCHAR(\s*[^\s\(])/is' => 'VARCHAR(255)\\1',
546 );
547
548 $query = preg_replace(array_keys($remplace), $remplace, $query);
549 return $query;
550 }
551
552 /**
553 * @param $nom
554 * @param string $serveur
555 * @param bool $requeter
556 * @return array|null|resource|string
557 */
558 function spip_mysql_create_base($nom, $serveur='',$requeter=true) {
559 return spip_mysql_query("CREATE DATABASE `$nom`", $serveur, $requeter);
560 }
561
562 // Fonction de creation d'une vue SQL nommee $nom
563 // http://doc.spip.org/@spip_mysql_create_view
564 /**
565 * @param $nom
566 * @param $query_select
567 * @param string $serveur
568 * @param bool $requeter
569 * @return array|bool|null|resource|string
570 */
571 function spip_mysql_create_view($nom, $query_select, $serveur='',$requeter=true) {
572 if (!$query_select) return false;
573 // vue deja presente
574 if (sql_showtable($nom, false, $serveur)) {
575 spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)", _LOG_ERREUR);
576 return false;
577 }
578
579 $query = "CREATE VIEW $nom AS ". $query_select;
580 return spip_mysql_query($query, $serveur, $requeter);
581 }
582
583
584 // http://doc.spip.org/@spip_mysql_drop_table
585 /**
586 * @param $table
587 * @param string $exist
588 * @param string $serveur
589 * @param bool $requeter
590 * @return array|null|resource|string
591 */
592 function spip_mysql_drop_table($table, $exist='', $serveur='',$requeter=true)
593 {
594 if ($exist) $exist =" IF EXISTS";
595 return spip_mysql_query("DROP TABLE$exist $table", $serveur, $requeter);
596 }
597
598 // supprime une vue
599 // http://doc.spip.org/@spip_mysql_drop_view
600 /**
601 * @param $view
602 * @param string $exist
603 * @param string $serveur
604 * @param bool $requeter
605 * @return array|null|resource|string
606 */
607 function spip_mysql_drop_view($view, $exist='', $serveur='',$requeter=true) {
608 if ($exist) $exist =" IF EXISTS";
609 return spip_mysql_query("DROP VIEW$exist $view", $serveur, $requeter);
610 }
611
612 /**
613 * Retourne une ressource de la liste des tables de la base de données
614 *
615 * @param string $match
616 * Filtre sur tables à récupérer
617 * @param string $serveur
618 * Connecteur de la base
619 * @param bool $requeter
620 * true pour éxecuter la requête
621 * false pour retourner le texte de la requête.
622 * @return ressource
623 * Ressource à utiliser avec sql_fetch()
624 **/
625 function spip_mysql_showbase($match, $serveur='',$requeter=true)
626 {
627 return spip_mysql_query("SHOW TABLES LIKE " . _q($match), $serveur, $requeter);
628 }
629
630 // http://doc.spip.org/@spip_mysql_repair
631 /**
632 * @param $table
633 * @param string $serveur
634 * @param bool $requeter
635 * @return array|null|resource|string
636 */
637 function spip_mysql_repair($table, $serveur='',$requeter=true)
638 {
639 return spip_mysql_query("REPAIR TABLE `$table`", $serveur, $requeter);
640 }
641
642 define('_MYSQL_RE_SHOW_TABLE', '/^[^(),]*\(((?:[^()]*\((?:[^()]*\([^()]*\))?[^()]*\)[^()]*)*[^()]*)\)[^()]*$/');
643 // Recupere la definition d'une table ou d'une vue MySQL
644 // colonnes, indexes, etc.
645 // au meme format que la definition des tables de SPIP
646 // http://doc.spip.org/@spip_mysql_showtable
647 /**
648 * @param $nom_table
649 * @param string $serveur
650 * @param bool $requeter
651 * @return array|null|resource|string
652 */
653 function spip_mysql_showtable($nom_table, $serveur='',$requeter=true)
654 {
655 $s = spip_mysql_query("SHOW CREATE TABLE `$nom_table`", $serveur, $requeter);
656 if (!$s) return '';
657 if (!$requeter) return $s;
658
659 list(,$a) = mysql_fetch_array($s ,MYSQL_NUM);
660 if (preg_match(_MYSQL_RE_SHOW_TABLE, $a, $r)){
661 $desc = $r[1];
662 // extraction d'une KEY éventuelle en prenant garde de ne pas
663 // relever un champ dont le nom contient KEY (ex. ID_WHISKEY)
664 if (preg_match("/^(.*?),([^,]*\sKEY[ (].*)$/s", $desc, $r)) {
665 $namedkeys = $r[2];
666 $desc = $r[1];
667 }
668 else
669 $namedkeys = "";
670
671 $fields = array();
672 foreach(preg_split("/,\s*`/",$desc) as $v) {
673 preg_match("/^\s*`?([^`]*)`\s*(.*)/",$v,$r);
674 $fields[strtolower($r[1])] = $r[2];
675 }
676 $keys = array();
677
678 foreach(preg_split('/\)\s*(,|$)/',$namedkeys) as $v) {
679 if (preg_match("/^\s*([^(]*)\(([^(]*(\(\d+\))?)$/",$v,$r)) {
680 $k = str_replace("`", '', trim($r[1]));
681 $t = strtolower(str_replace("`", '', $r[2]));
682 if ($k && !isset($keys[$k])) $keys[$k] = $t; else $keys[] = $t;
683 }
684 }
685 spip_mysql_free($s);
686 return array('field' => $fields, 'key' => $keys);
687 }
688
689 $res = spip_mysql_query("SHOW COLUMNS FROM `$nom_table`", $serveur);
690 if($res) {
691 $nfields = array();
692 $nkeys = array();
693 while($val = spip_mysql_fetch($res)) {
694 $nfields[$val["Field"]] = $val['Type'];
695 if($val['Null']=='NO') {
696 $nfields[$val["Field"]] .= ' NOT NULL';
697 }
698 if($val['Default'] === '0' || $val['Default']) {
699 if(preg_match('/[A-Z_]/',$val['Default'])) {
700 $nfields[$val["Field"]] .= ' DEFAULT '.$val['Default'];
701 } else {
702 $nfields[$val["Field"]] .= " DEFAULT '".$val['Default']."'";
703 }
704 }
705 if($val['Extra'])
706 $nfields[$val["Field"]] .= ' '.$val['Extra'];
707 if($val['Key'] == 'PRI') {
708 $nkeys['PRIMARY KEY'] = $val["Field"];
709 } else if($val['Key'] == 'MUL') {
710 $nkeys['KEY '.$val["Field"]] = $val["Field"];
711 } else if($val['Key'] == 'UNI') {
712 $nkeys['UNIQUE KEY '.$val["Field"]] = $val["Field"];
713 }
714 }
715 spip_mysql_free($res);
716 return array('field' => $nfields, 'key' => $nkeys);
717 }
718 return "";
719 }
720
721 //
722 // Recuperation des resultats
723 //
724
725 // http://doc.spip.org/@spip_mysql_fetch
726 /**
727 * @param $r
728 * @param string $t
729 * @param string $serveur
730 * @param bool $requeter
731 * @return array
732 */
733 function spip_mysql_fetch($r, $t='', $serveur='',$requeter=true) {
734 if (!$t) $t = MYSQL_ASSOC;
735 if ($r) return mysql_fetch_array($r, $t);
736 }
737
738 function spip_mysql_seek($r, $row_number, $serveur='',$requeter=true) {
739 if ($r and mysql_num_rows($r)) return mysql_data_seek($r,$row_number);
740 }
741
742
743 // http://doc.spip.org/@spip_mysql_countsel
744 /**
745
746 * @param array $from
747 * @param array $where
748 * @param string $groupby
749 * @param array $having
750 * @param string $serveur
751 * @param bool $requeter
752 * @return array|int|null|resource|string
753 *
754 */
755 function spip_mysql_countsel($from = array(), $where = array(),
756 $groupby = '', $having = array(), $serveur='',$requeter=true)
757 {
758 $c = !$groupby ? '*' : ('DISTINCT ' . (is_string($groupby) ? $groupby : join(',', $groupby)));
759
760 $r = spip_mysql_select("COUNT($c)", $from, $where,'', '', '', $having, $serveur, $requeter);
761
762 if (!$requeter) return $r;
763 if (!is_resource($r)) return 0;
764 list($c) = mysql_fetch_array($r, MYSQL_NUM);
765 mysql_free_result($r);
766 return $c;
767 }
768
769 // Bien specifier le serveur auquel on s'adresse,
770 // mais a l'install la globale n'est pas encore completement definie
771 // http://doc.spip.org/@spip_mysql_error
772 /**
773 * @param string $query
774 * @param string $serveur
775 * @param bool $requeter
776 * @return string
777 */
778 function spip_mysql_error($query='', $serveur='',$requeter=true) {
779 $link = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]['link'];
780 $s = $link ? mysql_error($link) : mysql_error();
781 if ($s) spip_log("$s - $query", 'mysql.'._LOG_ERREUR);
782 return $s;
783 }
784
785 // A transposer dans les portages
786 // http://doc.spip.org/@spip_mysql_errno
787 /**
788 * @param string $serveur
789 * @param bool $requeter
790 * @return int
791 */
792 function spip_mysql_errno($serveur='',$requeter=true) {
793 $link = $GLOBALS['connexions'][$serveur ? $serveur : 0]['link'];
794 $s = $link ? mysql_errno($link) : mysql_errno();
795 // 2006 MySQL server has gone away
796 // 2013 Lost connection to MySQL server during query
797 if (in_array($s, array(2006,2013)))
798 define('spip_interdire_cache', true);
799 if ($s) spip_log("Erreur mysql $s", _LOG_ERREUR);
800 return $s;
801 }
802
803 // Interface de abstract_sql
804 // http://doc.spip.org/@spip_mysql_count
805 /**
806 * @param $r
807 * @param string $serveur
808 * @param bool $requeter
809 * @return int
810 */
811 function spip_mysql_count($r, $serveur='',$requeter=true) {
812 if ($r) return mysql_num_rows($r);
813 }
814
815
816 // http://doc.spip.org/@spip_mysql_free
817 /**
818 * @param $r
819 * @param string $serveur
820 * @param bool $requeter
821 * @return bool
822 */
823 function spip_mysql_free($r, $serveur='',$requeter=true) {
824 return (is_resource($r)?mysql_free_result($r):false);
825 }
826
827 // http://doc.spip.org/@spip_mysql_insert
828 /**
829 * @param $table
830 * @param $champs
831 * @param $valeurs
832 * @param string $desc
833 * @param string $serveur
834 * @param bool $requeter
835 * @return int|string
836 */
837 function spip_mysql_insert($table, $champs, $valeurs, $desc='', $serveur='',$requeter=true) {
838
839 $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
840 $prefixe = $connexion['prefixe'];
841 $link = $connexion['link'];
842 $db = $connexion['db'];
843
844 if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table);
845
846 $query ="INSERT INTO $table $champs VALUES $valeurs";
847 if (!$requeter) return $query;
848
849 if (isset($_GET['var_profile'])) {
850 include_spip('public/tracer');
851 $t = trace_query_start();
852 } else $t = 0 ;
853
854 $connexion['last'] = $query;
855 #spip_log($query, 'mysql.'._LOG_DEBUG);
856 if (mysql_query($query, $link))
857 $r = mysql_insert_id($link);
858 else {
859 if ($e = spip_mysql_errno($serveur)) // Log de l'erreur eventuelle
860 $e .= spip_mysql_error($query, $serveur); // et du fautif
861 }
862 return $t ? trace_query_end($query, $t, $r, $e, $serveur) : $r;
863
864 // return $r ? $r : (($r===0) ? -1 : 0); pb avec le multi-base.
865 }
866
867 // http://doc.spip.org/@spip_mysql_insertq
868 /**
869 * @param $table
870 * @param array $couples
871 * @param array $desc
872 * @param string $serveur
873 * @param bool $requeter
874 * @return int|string
875 */
876 function spip_mysql_insertq($table, $couples=array(), $desc=array(), $serveur='',$requeter=true) {
877
878 if (!$desc) $desc = description_table($table, $serveur);
879 if (!$desc) $couples = array();
880 $fields = isset($desc['field'])?$desc['field']:array();
881
882 foreach ($couples as $champ => $val) {
883 $couples[$champ]= spip_mysql_cite($val, $fields[$champ]);
884 }
885
886 return spip_mysql_insert($table, "(".join(',',array_keys($couples)).")", "(".join(',', $couples).")", $desc, $serveur, $requeter);
887 }
888
889
890 // http://doc.spip.org/@spip_mysql_insertq_multi
891 /**
892 * @param $table
893 * @param array $tab_couples
894 * @param array $desc
895 * @param string $serveur
896 * @param bool $requeter
897 * @return bool|int|string
898 */
899 function spip_mysql_insertq_multi($table, $tab_couples=array(), $desc=array(), $serveur='',$requeter=true) {
900
901 if (!$desc) $desc = description_table($table, $serveur);
902 if (!$desc) $tab_couples = array();
903 $fields = isset($desc['field'])?$desc['field']:array();
904
905 $cles = "(" . join(',',array_keys(reset($tab_couples))) . ')';
906 $valeurs = array();
907 $r = false;
908
909 // Quoter et Inserer par groupes de 100 max pour eviter un debordement de pile
910 foreach ($tab_couples as $couples) {
911 foreach ($couples as $champ => $val){
912 $couples[$champ]= spip_mysql_cite($val, $fields[$champ]);
913 }
914 $valeurs[] = '(' .join(',', $couples) . ')';
915 if (count($valeurs)>=100){
916 $r = spip_mysql_insert($table, $cles, join(', ', $valeurs), $desc, $serveur, $requeter);
917 $valeurs = array();
918 }
919 }
920 if (count($valeurs))
921 $r = spip_mysql_insert($table, $cles, join(', ', $valeurs), $desc, $serveur, $requeter);
922
923 return $r; // dans le cas d'une table auto_increment, le dernier insert_id
924 }
925
926 // http://doc.spip.org/@spip_mysql_update
927 /**
928 * @param $table
929 * @param $champs
930 * @param string $where
931 * @param string $desc
932 * @param string $serveur
933 * @param bool $requeter
934 * @return array|null|resource|string
935 */
936 function spip_mysql_update($table, $champs, $where='', $desc='', $serveur='',$requeter=true) {
937 $set = array();
938 foreach ($champs as $champ => $val)
939 $set[] = $champ . "=$val";
940 if (!empty($set))
941 return spip_mysql_query(
942 calculer_mysql_expression('UPDATE', $table, ',')
943 . calculer_mysql_expression('SET', $set, ',')
944 . calculer_mysql_expression('WHERE', $where),
945 $serveur, $requeter);
946 }
947
948 // idem, mais les valeurs sont des constantes a mettre entre apostrophes
949 // sauf les expressions de date lorsqu'il s'agit de fonctions SQL (NOW etc)
950 // http://doc.spip.org/@spip_mysql_updateq
951 /**
952 * @param $table
953 * @param $champs
954 * @param string $where
955 * @param array $desc
956 * @param string $serveur
957 * @param bool $requeter
958 * @return array|null|resource|string
959 */
960 function spip_mysql_updateq($table, $champs, $where='', $desc=array(), $serveur='',$requeter=true) {
961
962 if (!$champs) return;
963 if (!$desc) $desc = description_table($table, $serveur);
964 if (!$desc) $champs = array(); else $fields = $desc['field'];
965 $set = array();
966 foreach ($champs as $champ => $val) {
967 $set[] = $champ . '=' . spip_mysql_cite($val, $fields[$champ]);
968 }
969 return spip_mysql_query(
970 calculer_mysql_expression('UPDATE', $table, ',')
971 . calculer_mysql_expression('SET', $set, ',')
972 . calculer_mysql_expression('WHERE', $where),
973 $serveur, $requeter);
974 }
975
976 // http://doc.spip.org/@spip_mysql_delete
977 /**
978 * @param $table
979 * @param string $where
980 * @param string $serveur
981 * @param bool $requeter
982 * @return array|bool|int|null|resource|string
983 */
984 function spip_mysql_delete($table, $where='', $serveur='',$requeter=true) {
985 $res = spip_mysql_query(
986 calculer_mysql_expression('DELETE FROM', $table, ',')
987 . calculer_mysql_expression('WHERE', $where),
988 $serveur, $requeter);
989 if (!$requeter) return $res;
990 if ($res){
991 $connexion = &$GLOBALS['connexions'][$serveur ? $serveur : 0];
992 $link = $connexion['link'];
993 return $link ? mysql_affected_rows($link) : mysql_affected_rows();
994 }
995 else
996 return false;
997 }
998
999 // http://doc.spip.org/@spip_mysql_replace
1000 /**
1001 * @param $table
1002 * @param $couples
1003 * @param array $desc
1004 * @param string $serveur
1005 * @param bool $requeter
1006 * @return array|null|resource|string
1007 */
1008 function spip_mysql_replace($table, $couples, $desc=array(), $serveur='',$requeter=true) {
1009 return spip_mysql_query("REPLACE $table (" . join(',',array_keys($couples)) . ') VALUES (' .join(',',array_map('_q', $couples)) . ')', $serveur, $requeter);
1010 }
1011
1012
1013 // http://doc.spip.org/@spip_mysql_replace_multi
1014 /**
1015 * @param $table
1016 * @param $tab_couples
1017 * @param array $desc
1018 * @param string $serveur
1019 * @param bool $requeter
1020 * @return array|null|resource|string
1021 */
1022 function spip_mysql_replace_multi($table, $tab_couples, $desc=array(), $serveur='',$requeter=true) {
1023 $cles = "(" . join(',',array_keys($tab_couples[0])). ')';
1024 $valeurs = array();
1025 foreach ($tab_couples as $couples) {
1026 $valeurs[] = '(' .join(',',array_map('_q', $couples)) . ')';
1027 }
1028 $valeurs = implode(', ',$valeurs);
1029 return spip_mysql_query("REPLACE $table $cles VALUES $valeurs", $serveur, $requeter);
1030 }
1031
1032
1033 // http://doc.spip.org/@spip_mysql_multi
1034 /**
1035
1036 * @param $objet
1037 * @param $lang
1038 * @return string
1039 *
1040 */
1041
1042 function spip_mysql_multi ($objet, $lang) {
1043 $lengthlang = strlen("[$lang]");
1044 $posmulti = "INSTR(".$objet.", '<multi>')";
1045 $posfinmulti = "INSTR(".$objet.", '</multi>')";
1046 $debutchaine = "LEFT(".$objet.", $posmulti-1)";
1047 $finchaine = "RIGHT(".$objet.", CHAR_LENGTH(".$objet.") -(7+$posfinmulti))";
1048 $chainemulti = "TRIM(SUBSTRING(".$objet.", $posmulti+7, $posfinmulti -(7+$posmulti)))";
1049 $poslang = "INSTR($chainemulti,'[".$lang."]')";
1050 $poslang = "IF($poslang=0,INSTR($chainemulti,']')+1,$poslang+$lengthlang)";
1051 $chainelang = "TRIM(SUBSTRING(".$objet.", $posmulti+7+$poslang-1,$posfinmulti -($posmulti+7+$poslang-1) ))";
1052 $posfinlang = "INSTR(".$chainelang.", '[')";
1053 $chainelang = "IF($posfinlang>0,LEFT($chainelang,$posfinlang-1),$chainelang)";
1054 //$chainelang = "LEFT($chainelang,$posfinlang-1)";
1055 $retour = "(TRIM(IF($posmulti = 0 , ".
1056 " TRIM(".$objet."), ".
1057 " CONCAT( ".
1058 " $debutchaine, ".
1059 " IF( ".
1060 " $poslang = 0, ".
1061 " $chainemulti, ".
1062 " $chainelang".
1063 " ), ".
1064 " $finchaine".
1065 " ) ".
1066 "))) AS multi";
1067
1068 return $retour;
1069 }
1070
1071 // http://doc.spip.org/@spip_mysql_hex
1072 /**
1073 * @param $v
1074 * @return string
1075 */
1076 function spip_mysql_hex($v)
1077 {
1078 return "0x" . $v;
1079 }
1080
1081 /**
1082 * @param $v
1083 * @param string $type
1084 * @return array|int|string
1085 */
1086 function spip_mysql_quote($v, $type='') {
1087 if ($type) {
1088 if (!is_array($v))
1089 return spip_mysql_cite($v,$type);
1090 // si c'est un tableau, le parcourir en propageant le type
1091 foreach($v as $k=>$r)
1092 $v[$k] = spip_mysql_quote($r, $type);
1093 return $v;
1094 }
1095 // si on ne connait pas le type, s'en remettre a _q :
1096 // on ne fera pas mieux
1097 else
1098 return _q($v);
1099 }
1100
1101 /**
1102 * @param $champ
1103 * @param $interval
1104 * @param $unite
1105 * @return string
1106 */
1107 function spip_mysql_date_proche($champ, $interval, $unite)
1108 {
1109 return '('
1110 . $champ
1111 . (($interval <= 0) ? '>' : '<')
1112 . (($interval <= 0) ? 'DATE_SUB' : 'DATE_ADD')
1113 . '('
1114 . sql_quote(date('Y-m-d H:i:s'))
1115 . ', INTERVAL '
1116 . (($interval > 0) ? $interval : (0-$interval))
1117 . ' '
1118 . $unite
1119 . '))';
1120 }
1121
1122 //
1123 // IN (...) est limite a 255 elements, d'ou cette fonction assistante
1124 //
1125 // http://doc.spip.org/@spip_mysql_in
1126 /**
1127 * @param $val
1128 * @param $valeurs
1129 * @param string $not
1130 * @param string $serveur
1131 * @param bool $requeter
1132 * @return string
1133 */
1134 function spip_mysql_in($val, $valeurs, $not='', $serveur='',$requeter=true) {
1135 $n = $i = 0;
1136 $in_sql ="";
1137 while ($n = strpos($valeurs, ',', $n+1)) {
1138 if ((++$i) >= 255) {
1139 $in_sql .= "($val $not IN (" .
1140 substr($valeurs, 0, $n) .
1141 "))\n" .
1142 ($not ? "AND\t" : "OR\t");
1143 $valeurs = substr($valeurs, $n+1);
1144 $i = $n = 0;
1145 }
1146 }
1147 $in_sql .= "($val $not IN ($valeurs))";
1148
1149 return "($in_sql)";
1150 }
1151
1152 // pour compatibilite. Ne plus utiliser.
1153 // http://doc.spip.org/@calcul_mysql_in
1154 /**
1155 * @param $val
1156 * @param $valeurs
1157 * @param string $not
1158 * @return string
1159 */
1160 function calcul_mysql_in($val, $valeurs, $not='') {
1161 if (is_array($valeurs))
1162 $valeurs = join(',', array_map('_q', $valeurs));
1163 elseif ($valeurs[0]===',') $valeurs = substr($valeurs,1);
1164 if (!strlen(trim($valeurs))) return ($not ? "0=0" : '0=1');
1165 return spip_mysql_in($val, $valeurs, $not);
1166 }
1167
1168 // http://doc.spip.org/@spip_mysql_cite
1169 /**
1170 * @param $v
1171 * @param $type
1172 * @return int|string
1173 */
1174 function spip_mysql_cite($v, $type) {
1175 if(is_null($v)
1176 AND stripos($type,"NOT NULL")===false) return 'NULL'; // null php se traduit en NULL SQL
1177 if (sql_test_date($type) AND preg_match('/^\w+\(/', $v))
1178 return $v;
1179 if (sql_test_int($type)) {
1180 if (is_numeric($v) OR (ctype_xdigit(substr($v,2))
1181 AND $v[0]=='0' AND $v[1]=='x'))
1182 return $v;
1183 // si pas numerique, forcer le intval
1184 else
1185 return intval($v);
1186 }
1187 return ("'" . addslashes($v) . "'");
1188 }
1189
1190 // Ces deux fonctions n'ont pas d'equivalent exact PostGres
1191 // et ne sont la que pour compatibilite avec les extensions de SPIP < 1.9.3
1192
1193 //
1194 // Poser un verrou local a un SPIP donne
1195 // Changer de nom toutes les heures en cas de blocage MySQL (ca arrive)
1196 //
1197 // http://doc.spip.org/@spip_get_lock
1198 /**
1199 * @param $nom
1200 * @param int $timeout
1201 * @return mixed
1202 */
1203 function spip_get_lock($nom, $timeout = 0) {
1204
1205 define('_LOCK_TIME', intval(time()/3600-316982));
1206
1207 $connexion = &$GLOBALS['connexions'][0];
1208 $bd = $connexion['db'];
1209 $prefixe = $connexion['prefixe'];
1210 $nom = "$bd:$prefixe:$nom" . _LOCK_TIME;
1211
1212 $connexion['last'] = $q = "SELECT GET_LOCK(" . _q($nom) . ", $timeout) AS n";
1213 $q = @sql_fetch(mysql_query($q));
1214 if (!$q) spip_log("pas de lock sql pour $nom", _LOG_ERREUR);
1215 return $q['n'];
1216 }
1217
1218 // http://doc.spip.org/@spip_release_lock
1219 /**
1220 * @param $nom
1221 */
1222 function spip_release_lock($nom) {
1223
1224 $connexion = &$GLOBALS['connexions'][0];
1225 $bd = $connexion['db'];
1226 $prefixe = $connexion['prefixe'];
1227 $nom = "$bd:$prefixe:$nom" . _LOCK_TIME;
1228
1229 $connexion['last'] = $q = "SELECT RELEASE_LOCK(" . _q($nom) . ")";
1230 @mysql_query($q);
1231 }
1232
1233 // Renvoie false si on n'a pas les fonctions mysql (pour l'install)
1234 // http://doc.spip.org/@spip_versions_mysql
1235 /**
1236 * @return bool
1237 */
1238 function spip_versions_mysql() {
1239 charger_php_extension('mysql');
1240 return function_exists('mysql_query');
1241 }
1242
1243 // Tester si mysql ne veut pas du nom de la base dans les requetes
1244
1245 // http://doc.spip.org/@test_rappel_nom_base_mysql
1246 /**
1247 * @param $server_db
1248 * @return string
1249 */
1250 function test_rappel_nom_base_mysql($server_db)
1251 {
1252 $GLOBALS['mysql_rappel_nom_base'] = true;
1253 sql_delete('spip_meta', "nom='mysql_rappel_nom_base'", $server_db);
1254 $ok = spip_query("INSERT INTO spip_meta (nom,valeur) VALUES ('mysql_rappel_nom_base', 'test')", $server_db);
1255
1256 if ($ok) {
1257 sql_delete('spip_meta', "nom='mysql_rappel_nom_base'", $server_db);
1258 return '';
1259 } else {
1260 $GLOBALS['mysql_rappel_nom_base'] = false;
1261 return "\$GLOBALS['mysql_rappel_nom_base'] = false; ".
1262 "/* echec de test_rappel_nom_base_mysql a l'installation. */\n";
1263 }
1264 }
1265
1266 // http://doc.spip.org/@test_sql_mode_mysql
1267 /**
1268 * @param $server_db
1269 * @return string
1270 */
1271 function test_sql_mode_mysql($server_db){
1272 $res = sql_select("version() as v",'','','','','','',$server_db);
1273 $row = sql_fetch($res,$server_db);
1274 if (version_compare($row['v'],'5.0.0','>=')){
1275 define('_MYSQL_SET_SQL_MODE',true);
1276 return "define('_MYSQL_SET_SQL_MODE',true);\n";
1277 }
1278 return '';
1279 }
1280
1281 ?>