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