Completed
Push — master ( 1a3b2f...b50fb4 )
by cam
09:59
created

abstract_sql.php ➔ sql_showtable()   B

Complexity

Conditions 9
Paths 13

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 13
nop 4
dl 0
loc 27
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
/* *************************************************************************\
4
 *  SPIP, Systeme de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright (c) 2001-2018                                                *
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
 * Definition de l'API SQL
15
 *
16
 * Ce fichier definit la couche d'abstraction entre SPIP et ses serveurs SQL.
17
 * Cette version 1 est un ensemble de fonctions ecrites rapidement
18
 * pour generaliser le code strictement MySQL de SPIP <= 1.9.2
19
 * Des retouches sont a prevoir apres l'experience des premiers portages.
20
 * Les symboles sql_* (constantes et nom de fonctions) sont reserves
21
 * a cette interface, sans quoi le gestionnaire de version dysfonctionnera.
22
 *
23
 * @package SPIP\Core\SQL\API
24
 * @version 1
25
 */
26
27
if (!defined('_ECRIRE_INC_VERSION')) {
28
	return;
29
}
30
31
/** Version de l'API SQL */
32
define('sql_ABSTRACT_VERSION', 1);
33
include_spip('base/connect_sql');
34
35
/**
36
 * Retourne la pile de fonctions utilisée lors de la précence d'une erreur SQL
37
 *
38
 * @note
39
 *     Ignore les fonctions `include_once`, `include_spip`, `find_in_path`
40
 * @param bool $compil_info
41
 *      - false : Retourne un texte présentant les fonctions utilisées
42
 *      - true : retourne un tableau indiquant un contexte de compilation à l'origine de la requête,
43
 *               utile pour présenter une erreur au débuggueur via `erreur_squelette()`
44
 * @return array|string
45
 *     contexte de l'erreur
46
 **/
47
function sql_error_backtrace($compil_info = false) {
48
	$trace = debug_backtrace();
49
	$caller = array_shift($trace);
50
	while (count($trace) and (empty($trace[0]['file']) or $trace[0]['file'] === $caller['file'] or $trace[0]['file'] === __FILE__)) {
51
		array_shift($trace);
52
	}
53
54
	if ($compil_info) {
55
		$contexte_compil = array(
56
			$trace[0]['file'],// sourcefile
57
			'', //nom
58
			(isset($trace[1]) ? $trace[1]['function'] . "(){\n" : '')
59
			. $trace[0]['function'] . "();"
60
			. (isset($trace[1]) ? "\n}" : ''), //id_boucle
61
			$trace[0]['line'], // ligne
62
			$GLOBALS['spip_lang'], // lang
63
		);
64
65
		return $contexte_compil;
66
	}
67
68
	$message = count($trace) ? $trace[0]['file'] . " L" . $trace[0]['line'] : "";
69
	$f = array();
70
	while (count($trace) and $t = array_shift($trace)) {
71
		if (in_array($t['function'], array('include_once', 'include_spip', 'find_in_path'))) {
72
			break;
73
		}
74
		$f[] = $t['function'];
75
	}
76
	if (count($f)) {
77
		$message .= " [" . implode("(),", $f) . "()]";
78
	}
79
80
	return $message;
81
}
82
83
84
/**
85
 * Charge le serveur de base de donnees
86
 *
87
 * Fonction principale. Elle charge l'interface au serveur de base de donnees
88
 * via la fonction spip_connect_version qui etablira la connexion au besoin.
89
 * Elle retourne la fonction produisant la requete SQL demandee
90
 * Erreur fatale si la fonctionnalite est absente sauf si le 3e arg <> false
91
 *
92
 * @internal Cette fonction de base est appelee par les autres fonctions sql_*
93
 * @param string $ins_sql
94
 *    Instruction de l'API SQL demandee (insertq, update, select...)
95
 * @param string $serveur
96
 *    Nom du connecteur ('' pour celui par defaut a l'installation de SPIP)
97
 * @param bool $continue
98
 *    true pour ne pas generer d'erreur si le serveur SQL ne dispose pas de la fonction demandee
99
 * @return string|array
100
 *    Nom de la fonction a appeler pour l'instruction demandee pour le type de serveur SQL correspondant au fichier de connexion.
101
 *    Si l'instruction demandee n'existe pas, retourne la liste de toutes les instructions du serveur SQL avec $continue a true.
102
 *
103
 **/
104
function sql_serveur($ins_sql = '', $serveur = '', $continue = false) {
105
	static $sql_serveur = array();
106
	if (!isset($sql_serveur[$serveur][$ins_sql])) {
107
		$f = spip_connect_sql(sql_ABSTRACT_VERSION, $ins_sql, $serveur, $continue);
108
		if (!is_string($f) or !$f) {
109
			return $f;
110
		}
111
		$sql_serveur[$serveur][$ins_sql] = $f;
112
	}
113
114
	return $sql_serveur[$serveur][$ins_sql];
115
}
116
117
/**
118
 * Demande si un charset est disponible
119
 *
120
 * Demande si un charset (tel que utf-8) est disponible
121
 * sur le gestionnaire de base de données de la connexion utilisée
122
 *
123
 * @api
124
 * @see sql_set_charset() pour utiliser un charset
125
 *
126
 * @param string $charset
127
 *     Le charset souhaité
128
 * @param string $serveur
129
 *     Le nom du connecteur
130
 * @param bool $option
131
 *     Inutilise
132
 * @return string|bool
133
 *     Retourne le nom du charset si effectivement trouvé, sinon false.
134
 **/
135
function sql_get_charset($charset, $serveur = '', $option = true) {
136
	// le nom http du charset differe parfois du nom SQL utf-8 ==> utf8 etc.
137
	$desc = sql_serveur('', $serveur, true, true);
0 ignored issues
show
Unused Code introduced by
The call to sql_serveur() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
138
	$desc = $desc[sql_ABSTRACT_VERSION];
139
	$c = $desc['charsets'][$charset];
140
	if ($c) {
141
		if (function_exists($f = @$desc['get_charset'])) {
142
			if ($f($c, $serveur, $option !== false)) {
143
				return $c;
144
			}
145
		}
146
	}
147
	spip_log("SPIP ne connait pas les Charsets disponibles sur le serveur $serveur. Le serveur choisira seul.",
148
		_LOG_AVERTISSEMENT);
149
150
	return false;
151
}
152
153
154
/**
155
 * Regler le codage de connexion
156
 *
157
 * Affecte un charset (tel que utf-8) sur la connexion utilisee
158
 * avec le gestionnaire de base de donnees
159
 *
160
 * @api
161
 * @see sql_get_charset() pour tester l'utilisation d'un charset
162
 *
163
 * @param string $charset
164
 *    Le charset souhaite
165
 * @param string $serveur
166
 *    Le nom du connecteur
167
 * @param bool|string $option
168
 *    Peut avoir 2 valeurs :
169
 *    - true pour executer la requete.
170
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
171
 *
172
 * @return bool
173
 *    Retourne true si elle reussie.
174
 **/
175
function sql_set_charset($charset, $serveur = '', $option = true) {
176
	$f = sql_serveur('set_charset', $serveur, $option === 'continue' or $option === false);
177
	if (!is_string($f) or !$f) {
178
		return false;
179
	}
180
181
	return $f($charset, $serveur, $option !== false);
182
}
183
184
185
/**
186
 * Effectue une requête de selection
187
 *
188
 * Fonction de selection (SELECT), retournant la ressource interrogeable par sql_fetch.
189
 *
190
 * @api
191
 * @see sql_fetch()      Pour boucler sur les resultats de cette fonction
192
 *
193
 * @param array|string $select
194
 *     Liste des champs a recuperer (Select)
195
 * @param array|string $from
196
 *     Tables a consulter (From)
197
 * @param array|string $where
198
 *     Conditions a remplir (Where)
199
 * @param array|string $groupby
200
 *     Critere de regroupement (Group by)
201
 * @param array|string $orderby
202
 *     Tableau de classement (Order By)
203
 * @param string $limit
204
 *     Critere de limite (Limit)
205
 * @param array $having
206
 *     Tableau des des post-conditions a remplir (Having)
207
 * @param string $serveur
208
 *     Le serveur sollicite (pour retrouver la connexion)
209
 * @param bool|string $option
210
 *     Peut avoir 3 valeurs :
211
 *
212
 *     - false -> ne pas l'exécuter mais la retourner,
213
 *     - continue -> ne pas echouer en cas de serveur sql indisponible,
214
 *     - true|array -> executer la requête.
215
 *     Le cas array est, pour une requete produite par le compilateur,
216
 *     un tableau donnnant le contexte afin d'indiquer le lieu de l'erreur au besoin
217
 *
218
 *
219
 * @return mixed
220
 *     Ressource SQL
221
 *
222
 *     - Ressource SQL pour sql_fetch, si la requete est correcte
223
 *     - false en cas d'erreur
224
 *     - Chaine contenant la requete avec $option=false
225
 *
226
 * Retourne false en cas d'erreur, apres l'avoir denoncee.
227
 * Les portages doivent retourner la requete elle-meme en cas d'erreur,
228
 * afin de disposer du texte brut.
229
 *
230
 **/
231
function sql_select(
232
	$select = array(),
233
	$from = array(),
234
	$where = array(),
235
	$groupby = array(),
236
	$orderby = array(),
237
	$limit = '',
238
	$having = array(),
239
	$serveur = '',
240
	$option = true
241
) {
242
	$f = sql_serveur('select', $serveur, $option === 'continue' or $option === false);
243
	if (!is_string($f) or !$f) {
244
		return false;
245
	}
246
247
	$debug = (defined('_VAR_MODE') and _VAR_MODE == 'debug');
248
	if (($option !== false) and !$debug) {
249
		$res = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur,
250
			is_array($option) ? true : $option);
251
	} else {
252
		$query = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, false);
253
		if (!$option) {
254
			return $query;
255
		}
256
		// le debug, c'est pour ce qui a ete produit par le compilateur
257
		if (isset($GLOBALS['debug']['aucasou'])) {
258
			list($table, $id, ) = $GLOBALS['debug']['aucasou'];
0 ignored issues
show
Unused Code introduced by
The assignment to $table is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
259
			$nom = $GLOBALS['debug_objets']['courant'] . $id;
260
			$GLOBALS['debug_objets']['requete'][$nom] = $query;
261
		}
262
		$res = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, true);
263
	}
264
265
	// en cas d'erreur
266
	if (!is_string($res)) {
267
		return $res;
268
	}
269
	// denoncer l'erreur SQL dans sa version brute
270
	spip_sql_erreur($serveur);
271
	// idem dans sa version squelette (prefixe des tables non substitue)
272
	$contexte_compil = sql_error_backtrace(true);
273
	erreur_squelette(array(sql_errno($serveur), sql_error($serveur), $res), $contexte_compil);
274
275
	return false;
276
}
277
278
279
/**
280
 * Recupere la syntaxe de la requete select sans l'executer
281
 *
282
 * Passe simplement $option a false au lieu de true
283
 * sans obliger a renseigner tous les arguments de sql_select.
284
 * Les autres parametres sont identiques.
285
 *
286
 * @api
287
 * @uses sql_select()
288
 *
289
 * @param array|string $select
290
 *    Liste des champs a recuperer (Select)
291
 * @param array|string $from
292
 *    Tables a consulter (From)
293
 * @param array|string $where
294
 *    Conditions a remplir (Where)
295
 * @param array|string $groupby
296
 *    Critere de regroupement (Group by)
297
 * @param array|string $orderby
298
 *    Tableau de classement (Order By)
299
 * @param string $limit
300
 *    Critere de limite (Limit)
301
 * @param array $having
302
 *    Tableau des des post-conditions a remplir (Having)
303
 * @param string $serveur
304
 *    Le serveur sollicite (pour retrouver la connexion)
305
 *
306
 * @return mixed
307
 *    Chaine contenant la requete
308
 *    ou false en cas d'erreur
309
 *
310
 **/
311
function sql_get_select(
312
	$select = array(),
313
	$from = array(),
314
	$where = array(),
315
	$groupby = array(),
316
	$orderby = array(),
317
	$limit = '',
318
	$having = array(),
319
	$serveur = ''
320
) {
321
	return sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, false);
322
}
323
324
325
/**
326
 * Retourne le nombre de lignes d'une sélection
327
 *
328
 * Ramène seulement et tout de suite le nombre de lignes
329
 * Pas de colonne ni de tri à donner donc.
330
 *
331
 * @api
332
 * @see sql_count()
333
 * @example
334
 *     ```
335
 *     if (sql_countsel('spip_mots_liens', array(
336
 *         "objet=".sql_quote('article'),
337
 *         "id_article=".sql_quote($id_article)) > 0) {
338
 *             // ...
339
 *     }
340
 *     ```
341
 *
342
 * @param array|string $from
343
 *    Tables a consulter (From)
344
 * @param array|string $where
345
 *    Conditions a remplir (Where)
346
 * @param array|string $groupby
347
 *    Critere de regroupement (Group by)
348
 * @param array $having
349
 *    Tableau des des post-conditions a remplir (Having)
350
 * @param string $serveur
351
 *    Le serveur sollicite (pour retrouver la connexion)
352
 * @param bool|string $option
353
 *    Peut avoir 3 valeurs :
354
 *
355
 *    - false -> ne pas l'executer mais la retourner,
356
 *    - continue -> ne pas echouer en cas de serveur sql indisponible,
357
 *    - true -> executer la requete.
358
 *
359
 * @return int|bool
360
 *     - Nombre de lignes de resultat
361
 *     - ou false en cas d'erreur
362
 *
363
 **/
364
function sql_countsel(
365
	$from = array(),
366
	$where = array(),
367
	$groupby = array(),
368
	$having = array(),
369
	$serveur = '',
370
	$option = true
371
) {
372
	$f = sql_serveur('countsel', $serveur, $option === 'continue' or $option === false);
373
	if (!is_string($f) or !$f) {
374
		return false;
375
	}
376
	$r = $f($from, $where, $groupby, $having, $serveur, $option !== false);
377
	if ($r === false) {
378
		spip_sql_erreur($serveur);
379
	}
380
381
	return $r;
382
}
383
384
/**
385
 * Modifie la structure de la base de données
386
 *
387
 * Effectue une opération ALTER.
388
 *
389
 * @example
390
 *     ```
391
 *     sql_alter('DROP COLUMN supprimer');
392
 *     ```
393
 *
394
 * @api
395
 * @param string $q
396
 *     La requête à exécuter (sans la préceder de 'ALTER ')
397
 * @param string $serveur
398
 *     Le serveur sollicite (pour retrouver la connexion)
399
 * @param bool|string $option
400
 *     Peut avoir 2 valeurs :
401
 *
402
 *     - true : exécuter la requete
403
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
404
 * @return mixed
405
 *     2 possibilités :
406
 *
407
 *     - Incertain en cas d'exécution correcte de la requête
408
 *     - false en cas de serveur indiponible ou d'erreur
409
 *
410
 *     Ce retour n'est pas pertinent pour savoir si l'opération est correctement réalisée.
411
 **/
412
function sql_alter($q, $serveur = '', $option = true) {
413
	$f = sql_serveur('alter', $serveur, $option === 'continue' or $option === false);
414
	if (!is_string($f) or !$f) {
415
		return false;
416
	}
417
	$r = $f($q, $serveur, $option !== false);
418
	if ($r === false) {
419
		spip_sql_erreur($serveur);
420
	}
421
422
	return $r;
423
}
424
425
/**
426
 * Retourne un enregistrement d'une selection
427
 *
428
 * Retourne un resultat d'une ressource obtenue avec sql_select()
429
 *
430
 * @api
431
 * @param mixed $res
432
 *    Ressource retournee par sql_select()
433
 * @param string $serveur
434
 *    Le nom du connecteur
435
 * @param bool|string $option
436
 *    Peut avoir 2 valeurs :
437
 *    - true -> executer la requete
438
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
439
 *
440
 * @return array
441
 *    Tableau de cles (colonnes SQL ou alias) / valeurs (valeurs dans la colonne de la table ou calculee)
442
 *    presentant une ligne de resultat d'une selection
443
 */
444
function sql_fetch($res, $serveur = '', $option = true) {
445
	$f = sql_serveur('fetch', $serveur, $option === 'continue' or $option === false);
446
	if (!is_string($f) or !$f) {
447
		return false;
448
	}
449
450
	return $f($res, null, $serveur, $option !== false);
451
}
452
453
454
/**
455
 * Retourne tous les enregistrements d'une selection
456
 *
457
 * Retourne tous les resultats d'une ressource obtenue avec sql_select()
458
 * dans un tableau
459
 *
460
 * @api
461
 * @param mixed $res
462
 *    Ressource retournee par sql_select()
463
 * @param string $serveur
464
 *    Le nom du connecteur
465
 * @param bool|string $option
466
 *    Peut avoir 2 valeurs :
467
 *    - true -> executer la requete
468
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
469
 *
470
 * @return array
471
 *    Tableau contenant les enregistrements.
472
 *    Chaque entree du tableau est un autre tableau
473
 *    de cles (colonnes SQL ou alias) / valeurs (valeurs dans la colonne de la table ou calculee)
474
 *    presentant une ligne de resultat d'une selection
475
 */
476
function sql_fetch_all($res, $serveur = '', $option = true) {
477
	$rows = array();
478
	if (!$res) {
479
		return $rows;
480
	}
481
	$f = sql_serveur('fetch', $serveur, $option === 'continue' or $option === false);
482
	if (!is_string($f) or !$f) {
483
		return array();
484
	}
485
	while ($r = $f($res, null, $serveur, $option !== false)) {
486
		$rows[] = $r;
487
	}
488
	sql_free($res, $serveur);
489
490
	return $rows;
491
}
492
493
/**
494
 * Déplace le pointeur d'une ressource de sélection
495
 *
496
 * Deplace le pointeur sur un numéro de ligne précisé
497
 * sur une ressource issue de sql_select, afin que
498
 * le prochain sql_fetch récupère cette ligne.
499
 *
500
 * @api
501
 * @see sql_skip() Pour sauter des enregistrements
502
 *
503
 * @param mixed $res
504
 *    Ressource issue de sql_select
505
 * @param int $row_number
506
 *    Numero de ligne sur laquelle placer le pointeur
507
 * @param string $serveur
508
 *    Le nom du connecteur
509
 * @param bool|string $option
510
 *    Peut avoir 2 valeurs :
511
 *    - true -> executer la requete
512
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
513
 *
514
 * @return bool
515
 *    Operation effectuée (true), sinon false.
516
 **/
517 View Code Duplication
function sql_seek($res, $row_number, $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
518
	$f = sql_serveur('seek', $serveur, $option === 'continue' or $option === false);
519
	if (!is_string($f) or !$f) {
520
		return false;
521
	}
522
	$r = $f($res, $row_number, $serveur, $option !== false);
523
	if ($r === false) {
524
		spip_sql_erreur($serveur);
525
	}
526
527
	return $r;
528
}
529
530
531
/**
532
 * Liste des bases de donnees accessibles
533
 *
534
 * Retourne un tableau du nom de toutes les bases de donnees
535
 * accessibles avec les permissions de l'utilisateur SQL
536
 * de cette connexion.
537
 * Attention on n'a pas toujours les droits !
538
 *
539
 * @api
540
 * @param string $serveur
541
 *    Nom du connecteur
542
 * @param bool|string $option
543
 *    Peut avoir 2 valeurs :
544
 *    - true -> executer la requete
545
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
546
 *
547
 * @return array|bool
548
 *    Tableau contenant chaque nom de base de donnees.
549
 *    False en cas d'erreur.
550
 **/
551 View Code Duplication
function sql_listdbs($serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
552
	$f = sql_serveur('listdbs', $serveur, $option === 'continue' or $option === false);
553
	if (!is_string($f) or !$f) {
554
		return false;
555
	}
556
	$r = $f($serveur);
557
	if ($r === false) {
558
		spip_sql_erreur($serveur);
559
	}
560
561
	return $r;
562
}
563
564
565
/**
566
 * Demande d'utiliser d'une base de donnees
567
 *
568
 * @api
569
 * @param string $nom
570
 *     Nom de la base a utiliser
571
 * @param string $serveur
572
 *     Nom du connecteur
573
 * @param bool|string $option
574
 *     Peut avoir 2 valeurs :
575
 *
576
 *     - true -> executer la requete
577
 *     - continue -> ne pas echouer en cas de serveur sql indisponible
578
 *
579
 * @return bool|string
580
 *     - True ou nom de la base en cas de success.
581
 *     - False en cas d'erreur.
582
 **/
583
function sql_selectdb($nom, $serveur = '', $option = true) {
584
	$f = sql_serveur('selectdb', $serveur, $option === 'continue' or $option === false);
585
	if (!is_string($f) or !$f) {
586
		return false;
587
	}
588
	$r = $f($nom, $serveur, $option !== false);
589
	if ($r === false) {
590
		spip_sql_erreur($serveur);
591
	}
592
593
	return $r;
594
}
595
596
/**
597
 * Retourne le nombre de lignes d’une ressource de sélection obtenue
598
 * avec `sql_select()`
599
 *
600
 * @api
601
 * @see sql_select()
602
 * @see sql_countsel()
603
 *
604
 * @param Ressource $res
605
 *     Ressource SQL
606
 * @param string $serveur
607
 *     Nom du connecteur
608
 * @param bool|string $option
609
 *     Peut avoir 2 valeurs :
610
 *
611
 *     - true -> executer la requete
612
 *     - continue -> ne pas echouer en cas de serveur sql indisponible
613
 * @return bool|string
614
 *     - int Nombre de lignes,
615
 *     - false en cas d'erreur.
616
 **/
617
function sql_count($res, $serveur = '', $option = true) {
618
	$f = sql_serveur('count', $serveur, $option === 'continue' or $option === false);
619
	if (!is_string($f) or !$f) {
620
		return false;
621
	}
622
	$r = $f($res, $serveur, $option !== false);
623
	if ($r === false) {
624
		spip_sql_erreur($serveur);
625
	}
626
627
	return $r;
628
}
629
630
/**
631
 * Libère une ressource de résultat
632
 *
633
 * Indique au gestionnaire SQL de libérer de sa mémoire la ressoucre de
634
 * résultat indiquée car on n'a plus besoin de l'utiliser.
635
 *
636
 * @param Ressource|Object $res
637
 *     Ressource de résultat
638
 * @param string $serveur
639
 *     Nom de la connexion
640
 * @param bool|string $option
641
 *     Peut avoir 2 valeurs :
642
 *
643
 *     - true -> exécuter la requete
644
 *     - continue -> ne pas échouer en cas de serveur SQL indisponible
645
 * @return bool
646
 *     True si réussi
647
 */
648
function sql_free($res, $serveur = '', $option = true) {
649
	$f = sql_serveur('free', $serveur, $option === 'continue' or $option === false);
650
	if (!is_string($f) or !$f) {
651
		return false;
652
	}
653
654
	return $f($res);
655
}
656
657
658
/**
659
 * Insère une ligne dans une table
660
 *
661
 * @see sql_insertq()
662
 * @see sql_quote()
663
 * @note
664
 *   Cette fonction ne garantit pas une portabilité totale,
665
 *   et n'est là que pour faciliter des migrations de vieux scripts.
666
 *   Préférer sql_insertq.
667
 *
668
 * @param string $table
669
 *     Nom de la table SQL
670
 * @param string $noms
671
 *     Liste des colonnes impactées,
672
 * @param string $valeurs
673
 *     Liste des valeurs,
674
 * @param array $desc
675
 *     Tableau de description des colonnes de la table SQL utilisée
676
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
677
 * @param string $serveur
678
 *     Nom du connecteur
679
 * @param bool|string $option
680
 *     Peut avoir 3 valeurs :
681
 *
682
 *     - false : ne pas l'exécuter mais la retourner,
683
 *     - true : exécuter la requête
684
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
685
 *
686
 * @return bool|string
687
 *     - int|true identifiant de l'élément inséré (si possible), ou true, si réussite
688
 *     - Texte de la requête si demandé,
689
 *     - False en cas d'erreur.
690
 **/
691 View Code Duplication
function sql_insert($table, $noms, $valeurs, $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
692
	$f = sql_serveur('insert', $serveur, $option === 'continue' or $option === false);
693
	if (!is_string($f) or !$f) {
694
		return false;
695
	}
696
	$r = $f($table, $noms, $valeurs, $desc, $serveur, $option !== false);
697
	if ($r === false or $r === null) {
698
		spip_sql_erreur($serveur);
699
		$r = false;
700
	}
701
702
	return $r;
703
}
704
705
/**
706
 * Insère une ligne dans une table
707
 *
708
 * Protègera chaque valeur comme sql_quote.
709
 *
710
 * @api
711
 * @see sql_insert()
712
 * @see sql_insertq_multi()
713
 * @see sql_quote()
714
 * @see objet_inserer()
715
 * @example
716
 *     ```
717
 *     $titre = _request('titre');
718
 *     $id = sql_insertq('spip_rubriques', array('titre' => $titre));
719
 *     ```
720
 *
721
 * @param string $table
722
 *     Nom de la table SQL
723
 * @param array $couples
724
 *     Tableau (nom => valeur)
725
 * @param array $desc
726
 *     Tableau de description des colonnes de la table SQL utilisée
727
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
728
 * @param string $serveur
729
 *     Nom du connecteur
730
 * @param bool|string $option
731
 *     Peut avoir 3 valeurs :
732
 *
733
 *     - false : ne pas l'exécuter mais la retourner,
734
 *     - true : exécuter la requête
735
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
736
 *
737
 * @return bool|string
738
 *     - int|true identifiant de l'élément inséré (si possible), ou true, si réussite
739
 *     - Texte de la requête si demandé,
740
 *     - False en cas d'erreur.
741
 **/
742 View Code Duplication
function sql_insertq($table, $couples = array(), $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
743
	$f = sql_serveur('insertq', $serveur, $option === 'continue' or $option === false);
744
	if (!is_string($f) or !$f) {
745
		return false;
746
	}
747
	$r = $f($table, $couples, $desc, $serveur, $option !== false);
748
	if ($r === false or $r === null) {
749
		spip_sql_erreur($serveur);
750
		$r = false;
751
	}
752
753
	return $r;
754
}
755
756
/**
757
 * Insère plusieurs lignes d'un coup dans une table
758
 *
759
 * Insère en une opération plusieurs éléments au schéma identique
760
 * dans une table de la base de données. Lorsque les portages le permettent,
761
 * ils utilisent une seule requête SQL pour réaliser l’ajout.
762
 *
763
 * @api
764
 * @see sql_insertq()
765
 *
766
 * @param string $table
767
 *     Nom de la table SQL
768
 * @param array $couples
769
 *     Tableau de tableaux associatifs (nom => valeur)
770
 * @param array $desc
771
 *     Tableau de description des colonnes de la table SQL utilisée
772
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
773
 * @param string $serveur
774
 *     Nom du connecteur
775
 * @param bool|string $option
776
 *     Peut avoir 3 valeurs :
777
 *
778
 *     - false : ne pas l'exécuter mais la retourner,
779
 *     - true : exécuter la requête
780
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
781
 *
782
 * @return bool|string
783
 *     - True en cas de succès,
784
 *     - Texte de la requête si demandé,
785
 *     - False en cas d'erreur.
786
 **/
787 View Code Duplication
function sql_insertq_multi($table, $couples = array(), $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
788
	$f = sql_serveur('insertq_multi', $serveur, $option === 'continue' or $option === false);
789
	if (!is_string($f) or !$f) {
790
		return false;
791
	}
792
	$r = $f($table, $couples, $desc, $serveur, $option !== false);
793
	if ($r === false or $r === null) {
794
		spip_sql_erreur($serveur);
795
		$r = false;
796
	}
797
798
	return $r;
799
}
800
801
/**
802
 * Met à jour des enregistrements d'une table SQL
803
 *
804
 * Les valeurs ne sont pas échappées, ce qui permet de modifier une colonne
805
 * en utilisant la valeur d'une autre colonne ou une expression SQL.
806
 *
807
 * Il faut alors protéger avec sql_quote() manuellement les valeurs qui
808
 * en ont besoin.
809
 *
810
 * Dans les autres cas, préférer sql_updateq().
811
 *
812
 * @api
813
 * @see sql_updateq()
814
 *
815
 * @param string $table
816
 *     Nom de la table
817
 * @param array $exp
818
 *     Couples (colonne => valeur)
819
 * @param string|array $where
820
 *     Conditions a remplir (Where)
821
 * @param array $desc
822
 *     Tableau de description des colonnes de la table SQL utilisée
823
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
824
 * @param string $serveur
825
 *     Nom de la connexion
826
 * @param bool|string $option
827
 *     Peut avoir 3 valeurs :
828
 *
829
 *     - false : ne pas l'exécuter mais la retourner,
830
 *     - true : exécuter la requête
831
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
832
 * @return array|bool|string
833
 *     - string : texte de la requête si demandé
834
 *     - true si la requête a réussie, false sinon
835
 *     - array Tableau décrivant la requête et son temps d'exécution si var_profile est actif
836
 */
837 View Code Duplication
function sql_update($table, $exp, $where = '', $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
838
	$f = sql_serveur('update', $serveur, $option === 'continue' or $option === false);
839
	if (!is_string($f) or !$f) {
840
		return false;
841
	}
842
	$r = $f($table, $exp, $where, $desc, $serveur, $option !== false);
843
	if ($r === false) {
844
		spip_sql_erreur($serveur);
845
	}
846
847
	return $r;
848
}
849
850
851
/**
852
 * Met à jour du contenu d’une table SQL
853
 *
854
 * Le contenu transmis à la fonction est protégé automatiquement
855
 * comme sql_quote().
856
 *
857
 * @api
858
 * @see sql_quote()
859
 * @see sql_update()
860
 * @example
861
 *     ```
862
 *     sql_updateq('table', array('colonne' => $valeur), 'id_table=' . intval($id_table));
863
 *     sql_updateq("spip_auteurs", array("statut" => '6forum'), "id_auteur=$id_auteur") ;
864
 *     ```
865
 * @note
866
 *   sql_update() est presque toujours appelée sur des constantes ou des dates
867
 *   Cette fonction (sql_updateq) est donc plus utile que la précédente,
868
 *   d'autant qu'elle permet de gerer les différences de représentation des constantes.
869
 *
870
 * @param string $table
871
 *     Nom de la table SQL
872
 * @param array $exp
873
 *     Couples (colonne => valeur)
874
 * @param array|string $where
875
 *     Conditions à vérifier
876
 * @param array $desc
877
 *     Tableau de description des colonnes de la table SQL utilisée
878
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
879
 * @param string $serveur
880
 *     Nom du connecteur
881
 * @param bool|string $option
882
 *     Peut avoir 3 valeurs :
883
 *
884
 *     - false : ne pas l'exécuter mais la retourner,
885
 *     - true : exécuter la requête
886
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
887
 * @return bool|string
888
 *     - true si réussite
889
 *     - Texte de la requête si demandé,
890
 *     - False en cas d'erreur.
891
 **/
892 View Code Duplication
function sql_updateq($table, $exp, $where = '', $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
893
	$f = sql_serveur('updateq', $serveur, $option === 'continue' or $option === false);
894
	if (!is_string($f) or !$f) {
895
		return false;
896
	}
897
	$r = $f($table, $exp, $where, $desc, $serveur, $option !== false);
898
	if ($r === false) {
899
		spip_sql_erreur($serveur);
900
	}
901
902
	return $r;
903
}
904
905
/**
906
 * Supprime des enregistrements d'une table
907
 *
908
 * @example
909
 *     ```
910
 *     sql_delete('spip_articles', 'id_article='.sql_quote($id_article));
911
 *     ```
912
 *
913
 * @api
914
 * @param string $table
915
 *     Nom de la table SQL
916
 * @param string|array $where
917
 *     Conditions à vérifier
918
 * @param string $serveur
919
 *     Nom du connecteur
920
 * @param bool|string $option
921
 *     Peut avoir 3 valeurs :
922
 *
923
 *     - false : ne pas l'exécuter mais la retourner,
924
 *     - true : exécuter la requête
925
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
926
 *
927
 * @return bool|string
928
 *     - int : nombre de suppressions réalisées,
929
 *     - Texte de la requête si demandé,
930
 *     - False en cas d'erreur.
931
 **/
932 View Code Duplication
function sql_delete($table, $where = '', $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
933
	$f = sql_serveur('delete', $serveur, $option === 'continue' or $option === false);
934
	if (!is_string($f) or !$f) {
935
		return false;
936
	}
937
	$r = $f($table, $where, $serveur, $option !== false);
938
	if ($r === false) {
939
		spip_sql_erreur($serveur);
940
	}
941
942
	return $r;
943
}
944
945
/**
946
 * Insère où met à jour une entrée d’une table SQL
947
 *
948
 * La clé ou les cles primaires doivent être présentes dans les données insérés.
949
 * La fonction effectue une protection automatique des données.
950
 *
951
 * Préférez sql_insertq() et sql_updateq().
952
 *
953
 * @see sql_insertq()
954
 * @see sql_updateq()
955
 *
956
 * @param string $table
957
 *     Nom de la table SQL
958
 * @param array $couples
959
 *     Couples colonne / valeur à modifier,
960
 * @param array $desc
961
 *     Tableau de description des colonnes de la table SQL utilisée
962
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
963
 * @param string $serveur
964
 *     Nom du connecteur
965
 * @param bool|string $option
966
 *     Peut avoir 3 valeurs :
967
 *
968
 *     - false : ne pas l'exécuter mais la retourner,
969
 *     - true : exécuter la requête
970
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
971
 *
972
 * @return bool|string
973
 *     - true si réussite
974
 *     - Texte de la requête si demandé,
975
 *     - False en cas d'erreur.
976
 **/
977 View Code Duplication
function sql_replace($table, $couples, $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
978
	$f = sql_serveur('replace', $serveur, $option === 'continue' or $option === false);
979
	if (!is_string($f) or !$f) {
980
		return false;
981
	}
982
	$r = $f($table, $couples, $desc, $serveur, $option !== false);
983
	if ($r === false) {
984
		spip_sql_erreur($serveur);
985
	}
986
987
	return $r;
988
}
989
990
991
/**
992
 * Insère où met à jour des entrées d’une table SQL
993
 *
994
 * La clé ou les cles primaires doivent être présentes dans les données insérés.
995
 * La fonction effectue une protection automatique des données.
996
 *
997
 * Préférez sql_insertq_multi() et sql_updateq().
998
 *
999
 * @see sql_insertq_multi()
1000
 * @see sql_updateq()
1001
 * @see sql_replace()
1002
 *
1003
 * @param string $table
1004
 *     Nom de la table SQL
1005
 * @param array $tab_couples
1006
 *     Tableau de tableau (colonne / valeur à modifier),
1007
 * @param array $desc
1008
 *     Tableau de description des colonnes de la table SQL utilisée
1009
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
1010
 * @param string $serveur
1011
 *     Nom du connecteur
1012
 * @param bool|string $option
1013
 *     Peut avoir 3 valeurs :
1014
 *
1015
 *     - false : ne pas l'exécuter mais la retourner,
1016
 *     - true : exécuter la requête
1017
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1018
 *
1019
 * @return bool|string
1020
 *     - true si réussite
1021
 *     - Texte de la requête si demandé,
1022
 *     - False en cas d'erreur.
1023
 **/
1024 View Code Duplication
function sql_replace_multi($table, $tab_couples, $desc = array(), $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1025
	$f = sql_serveur('replace_multi', $serveur, $option === 'continue' or $option === false);
1026
	if (!is_string($f) or !$f) {
1027
		return false;
1028
	}
1029
	$r = $f($table, $tab_couples, $desc, $serveur, $option !== false);
1030
	if ($r === false) {
1031
		spip_sql_erreur($serveur);
1032
	}
1033
1034
	return $r;
1035
}
1036
1037
/**
1038
 * Supprime une table SQL (structure et données)
1039
 *
1040
 * @api
1041
 * @see sql_create()
1042
 * @see sql_drop_view()
1043
 *
1044
 * @param string $table
1045
 *     Nom de la table
1046
 * @param string $exist
1047
 *     true pour ajouter un test sur l'existence de la table, false sinon
1048
 * @param string $serveur
1049
 *     Nom du connecteur
1050
 * @param bool|string $option
1051
 *     Peut avoir 3 valeurs :
1052
 *
1053
 *     - false : ne pas l'exécuter mais la retourner,
1054
 *     - true : exécuter la requête
1055
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1056
 * @return bool|string
1057
 *     - True en cas de succès,
1058
 *     - Texte de la requête si demandé,
1059
 *     - False en cas d'erreur.
1060
 **/
1061 View Code Duplication
function sql_drop_table($table, $exist = '', $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1062
	$f = sql_serveur('drop_table', $serveur, $option === 'continue' or $option === false);
1063
	if (!is_string($f) or !$f) {
1064
		return false;
1065
	}
1066
	$r = $f($table, $exist, $serveur, $option !== false);
1067
	if ($r === false) {
1068
		spip_sql_erreur($serveur);
1069
	}
1070
1071
	return $r;
1072
}
1073
1074
/**
1075
 * Supprime une vue SQL
1076
 *
1077
 * @api
1078
 * @see sql_create_view()
1079
 * @see sql_drop_table()
1080
 *
1081
 * @param string $table Nom de la vue SQL
1082
 * @param string $exist True pour ajouter un test d'existence avant de supprimer
1083
 * @param string $serveur Nom de la connexion
1084
 * @param bool $option
1085
 *     Peut avoir 3 valeurs :
1086
 *
1087
 *     - false : ne pas l'exécuter mais la retourner,
1088
 *     - true : exécuter la requête
1089
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1090
 * @return bool|string
1091
 *     - string Texte de la requête si demandé
1092
 *     - true si la requête a réussie, false sinon
1093
 */
1094 View Code Duplication
function sql_drop_view($table, $exist = '', $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1095
	$f = sql_serveur('drop_view', $serveur, $option === 'continue' or $option === false);
1096
	if (!is_string($f) or !$f) {
1097
		return false;
1098
	}
1099
	$r = $f($table, $exist, $serveur, $option !== false);
1100
	if ($r === false) {
1101
		spip_sql_erreur($serveur);
1102
	}
1103
1104
	return $r;
1105
}
1106
1107
/**
1108
 * Retourne une ressource de la liste des tables de la base de données
1109
 *
1110
 * @api
1111
 * @see sql_alltable()
1112
 *
1113
 * @param string $spip
0 ignored issues
show
Documentation introduced by
Should the type for parameter $spip not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1114
 *     Filtre sur tables retournées
1115
 *     - NULL : retourne les tables SPIP uniquement (tables préfixées avec le préfixe de la connexion)
1116
 *     - '%' : retourne toutes les tables de la base
1117
 * @param string $serveur
1118
 *     Le nom du connecteur
1119
 * @param bool|string $option
1120
 *     Peut avoir 3 valeurs :
1121
 *     - false -> ne pas l'executer mais la retourner,
1122
 *     - continue -> ne pas echouer en cas de serveur sql indisponible,
1123
 *     - true -> executer la requete.
1124
 * @return ressource
1125
 *     Ressource à utiliser avec sql_fetch()
1126
 **/
1127
function sql_showbase($spip = null, $serveur = '', $option = true) {
1128
	$f = sql_serveur('showbase', $serveur, $option === 'continue' or $option === false);
1129
	if (!is_string($f) or !$f) {
1130
		return false;
1131
	}
1132
1133
	// la globale n'est remplie qu'apres l'appel de sql_serveur.
1134
	if ($spip == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $spip of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1135
		$connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
1136
		$spip = $connexion['prefixe'] . '\_%';
1137
	}
1138
1139
	return $f($spip, $serveur, $option !== false);
1140
}
1141
1142
/**
1143
 * Retourne la liste des tables SQL
1144
 *
1145
 * @api
1146
 * @uses sql_showbase()
1147
 * @param string $spip
0 ignored issues
show
Documentation introduced by
Should the type for parameter $spip not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1148
 *     Filtre sur tables retournées
1149
 *     - NULL : retourne les tables SPIP uniquement (tables préfixées avec le préfixe de la connexion)
1150
 *     - '%' : retourne toutes les tables de la base
1151
 * @param string $serveur
1152
 *     Le nom du connecteur
1153
 * @param bool|string $option
1154
 *     Peut avoir 3 valeurs :
1155
 *     - false -> ne pas l'executer mais la retourner,
1156
 *     - continue -> ne pas echouer en cas de serveur sql indisponible,
1157
 *     - true -> executer la requete.
1158
 * @return array
1159
 *     Liste des tables SQL
1160
 **/
1161
function sql_alltable($spip = null, $serveur = '', $option = true) {
1162
	$q = sql_showbase($spip, $serveur, $option);
1163
	$r = array();
1164
	if ($q) {
1165
		while ($t = sql_fetch($q, $serveur)) {
1166
			$r[] = array_shift($t);
1167
		}
1168
	}
1169
1170
	return $r;
1171
}
1172
1173
/**
1174
 * Retourne la liste (et description) des colonnes et key d’une table SQL
1175
 *
1176
 * @note
1177
 *     Dans la plupart des situations, il vaut mieux utiliser directement
1178
 *     la fonction trouver_table() qui possède un cache.
1179
 *
1180
 * @api
1181
 * @see base_trouver_table_dist()
1182
 *
1183
 * @param string $table
1184
 *     Nom de la table SQL
1185
 * @param bool $table_spip
1186
 *     true pour remplacer automatiquement « spip » par le vrai préfixe de table
1187
 * @param string $serveur
1188
 *     Nom du connecteur
1189
 * @param bool|string $option
1190
 *     Peut avoir 3 valeurs :
1191
 *
1192
 *     - false : ne pas l'exécuter mais la retourner,
1193
 *     - 'continue' : ne pas échouer en cas de serveur SQL indisponible,
1194
 *     - true : exécuter la requete.
1195
 * @return bool|array
1196
 *     - false en cas d'echec
1197
 *     - sinon array : Tableau avec
1198
 *       - 'field' => array(colonne => description)
1199
 *       - 'key' => array(type => key)
1200
 *       - 'join' => array() // jointures, si déclarées.
1201
 **/
1202
function sql_showtable($table, $table_spip = false, $serveur = '', $option = true) {
1203
	$f = sql_serveur('showtable', $serveur, $option === 'continue' or $option === false);
1204
	if (!is_string($f) or !$f) {
1205
		return false;
1206
	}
1207
1208
	// la globale n'est remplie qu'apres l'appel de sql_serveur.
1209
	if ($table_spip) {
1210
		$connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
1211
		$prefixe = $connexion['prefixe'];
1212
		$vraie_table = prefixer_table_spip($table, $prefixe);
1213
	} else {
1214
		$vraie_table = $table;
1215
	}
1216
1217
	$f = $f($vraie_table, $serveur, $option !== false);
1218
	if (!$f) {
1219
		return array();
1220
	}
1221
	if (isset($GLOBALS['tables_principales'][$table]['join'])) {
1222
		$f['join'] = $GLOBALS['tables_principales'][$table]['join'];
1223
	} elseif (isset($GLOBALS['tables_auxiliaires'][$table]['join'])) {
1224
		$f['join'] = $GLOBALS['tables_auxiliaires'][$table]['join'];
1225
	}
1226
1227
	return $f;
1228
}
1229
1230
/**
1231
 * Crée une table dans la base de données
1232
 *
1233
 * @api
1234
 * @example
1235
 *     ```
1236
 *     sql_create("spip_tables",
1237
 *       array(
1238
 *           "id_table" => "bigint(20) NOT NULL default '0'",
1239
 *           "colonne1"=> "varchar(3) NOT NULL default 'oui'",
1240
 *           "colonne2"=> "text NOT NULL default ''"
1241
 *        ),
1242
 *        array(
1243
 *           'PRIMARY KEY' => "id_table",
1244
 *           'KEY colonne1' => "colonne1"
1245
 *        )
1246
 *     );
1247
 *     ```
1248
 *
1249
 * @param string $nom
1250
 *     Nom de la table
1251
 * @param array $champs
1252
 *     Couples (colonne => description)
1253
 * @param array $cles
1254
 *     Clé (nomdelaclef => champ)
1255
 * @param bool $autoinc
1256
 *     Si un champ est clef primaire est numérique alors la propriété
1257
 *     d’autoincrémentation sera ajoutée
1258
 * @param bool $temporary
1259
 *     true pour créer une table temporaire (au sens SQL)
1260
 * @param string $serveur
1261
 *     Nom du connecteur
1262
 * @param bool|string $option
1263
 *     Peut avoir 3 valeurs :
1264
 *
1265
 *     - false : ne pas l'exécuter mais la retourner,
1266
 *     - 'continue' : ne pas échouer en cas de serveur SQL indisponible,
1267
 *     - true : exécuter la requete.
1268
 * @return bool
1269
 *     true si succès, false en cas d'echec
1270
 **/
1271 View Code Duplication
function sql_create(
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1272
	$nom,
1273
	$champs,
1274
	$cles = array(),
1275
	$autoinc = false,
1276
	$temporary = false,
1277
	$serveur = '',
1278
	$option = true
1279
) {
1280
	$f = sql_serveur('create', $serveur, $option === 'continue' or $option === false);
1281
	if (!is_string($f) or !$f) {
1282
		return false;
1283
	}
1284
	$r = $f($nom, $champs, $cles, $autoinc, $temporary, $serveur, $option !== false);
1285
	if ($r === false) {
1286
		spip_sql_erreur($serveur);
1287
	}
1288
1289
	return $r;
1290
}
1291
1292
/**
1293
 * Crée une base de données
1294
 *
1295
 * @api
1296
 * @param string $nom Nom de la base (sans l'extension de fichier si gestionnaire SQLite)
1297
 * @param string $serveur Nom de la connexion
1298
 * @param bool $option
1299
 *     Peut avoir 3 valeurs :
1300
 *
1301
 *     - false : ne pas l'exécuter mais la retourner,
1302
 *     - true : exécuter la requête
1303
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1304
 * @return bool true si la base est créee.
1305
 **/
1306
function sql_create_base($nom, $serveur = '', $option = true) {
1307
	$f = sql_serveur('create_base', $serveur, $option === 'continue' or $option === false);
1308
	if (!is_string($f) or !$f) {
1309
		return false;
1310
	}
1311
	$r = $f($nom, $serveur, $option !== false);
1312
	if ($r === false) {
1313
		spip_sql_erreur($serveur);
1314
	}
1315
1316
	return $r;
1317
}
1318
1319
1320
/**
1321
 * Crée une vue SQL
1322
 *
1323
 * @api
1324
 * @see sql_drop_view()
1325
 * @see sql_create()
1326
 * @see sql_get_select() Pour obtenir le texte de la requête SELECT pour créer la vue.
1327
 *
1328
 * @param string $nom
1329
 *     Nom de la vue
1330
 * @param string $select_query
1331
 *     Une requête SELECT, idéalement crée avec `sql_get_select(...)`
1332
 * @param string $serveur
1333
 *     Nom du connecteur
1334
 * @param bool|string $option
1335
 *     Peut avoir 3 valeurs :
1336
 *
1337
 *     - false : ne pas l'exécuter mais la retourner,
1338
 *     - true : exécuter la requête
1339
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1340
 * @return bool|string
1341
 *     - true si succès,
1342
 *     - texte de la requête si demandé
1343
 *     - false en cas d'échec.
1344
 **/
1345 View Code Duplication
function sql_create_view($nom, $select_query, $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1346
	$f = sql_serveur('create_view', $serveur, $option === 'continue' or $option === false);
1347
	if (!is_string($f) or !$f) {
1348
		return false;
1349
	}
1350
	$r = $f($nom, $select_query, $serveur, $option !== false);
1351
	if ($r === false) {
1352
		spip_sql_erreur($serveur);
1353
	}
1354
1355
	return $r;
1356
}
1357
1358
/**
1359
 * Retourne l'instruction SQL pour obtenir le texte d'un champ contenant
1360
 * une balise `<multi>` dans la langue indiquée
1361
 *
1362
 * Cette sélection est mise dans l'alias `multi` (instruction AS multi).
1363
 *
1364
 * @example
1365
 *     ```
1366
 *     $t = sql_multi('chapo', 'fr');
1367
 *     ```
1368
 * @api
1369
 * @param string $sel
1370
 *     Colonne ayant le texte
1371
 * @param string $lang
1372
 *     Langue à extraire
1373
 * @param string $serveur
1374
 *     Nom du connecteur
1375
 * @param bool|string $option
1376
 *     Peut avoir 2 valeurs :
1377
 *
1378
 *     - true : exécuter la requête
1379
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1380
 * @return string
1381
 *     Texte de sélection pour la requête
1382
 */
1383
function sql_multi($sel, $lang, $serveur = '', $option = true) {
1384
	$f = sql_serveur('multi', $serveur, $option === 'continue' or $option === false);
1385
	if (!is_string($f) or !$f) {
1386
		return false;
1387
	}
1388
1389
	return $f($sel, $lang);
1390
}
1391
1392
1393
/**
1394
 * Retourne la dernière erreur connue
1395
 *
1396
 * @api
1397
 * @param string $serveur
1398
 *      Nom du connecteur
1399
 * @return bool|string
1400
 *      Description de l'erreur
1401
 *      False si le serveur est indisponible
1402
 */
1403
function sql_error($serveur = '') {
1404
	$f = sql_serveur('error', $serveur, 'continue');
1405
	if (!is_string($f) or !$f) {
1406
		return false;
1407
	}
1408
1409
	return $f('query inconnue', $serveur);
1410
}
1411
1412
/**
1413
 * Retourne le numéro de la derniere erreur connue
1414
 *
1415
 * @api
1416
 * @param string $serveur
1417
 *      Nom du connecteur
1418
 * @return bool|int
1419
 *      Numéro de l'erreur
1420
 *      False si le serveur est indisponible
1421
 */
1422
function sql_errno($serveur = '') {
1423
	$f = sql_serveur('errno', $serveur, 'continue');
1424
	if (!is_string($f) or !$f) {
1425
		return false;
1426
	}
1427
1428
	return $f($serveur);
1429
}
1430
1431
/**
1432
 * Retourne une explication de requête (Explain) SQL
1433
 *
1434
 * @api
1435
 * @param string $q Texte de la requête
1436
 * @param string $serveur Nom de la connexion
1437
 * @param bool $option
1438
 *     Peut avoir 3 valeurs :
1439
 *
1440
 *     - false : ne pas l'exécuter mais la retourner,
1441
 *     - true : exécuter la requête
1442
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1443
 * @return array           Tableau de l'explication
1444
 */
1445 View Code Duplication
function sql_explain($q, $serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1446
	$f = sql_serveur('explain', $serveur, 'continue');
1447
	if (!is_string($f) or !$f) {
1448
		return false;
1449
	}
1450
	$r = $f($q, $serveur, $option !== false);
1451
	if ($r === false) {
1452
		spip_sql_erreur($serveur);
1453
	}
1454
1455
	return $r;
1456
}
1457
1458
/**
1459
 * Optimise une table SQL
1460
 *
1461
 * @api
1462
 * @param string $table Nom de la table
1463
 * @param string $serveur Nom de la connexion
1464
 * @param bool $option
1465
 *     Peut avoir 3 valeurs :
1466
 *
1467
 *     - false : ne pas l'exécuter mais la retourner,
1468
 *     - true : exécuter la requête
1469
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1470
 * @return bool            Toujours true
1471
 */
1472
function sql_optimize($table, $serveur = '', $option = true) {
1473
	$f = sql_serveur('optimize', $serveur, $option === 'continue' or $option === false);
1474
	if (!is_string($f) or !$f) {
1475
		return false;
1476
	}
1477
	$r = $f($table, $serveur, $option !== false);
1478
	if ($r === false) {
1479
		spip_sql_erreur($serveur);
1480
	}
1481
1482
	return $r;
1483
}
1484
1485
/**
1486
 * Répare une table SQL
1487
 *
1488
 * @api
1489
 * @param string $table Nom de la table SQL
1490
 * @param string $serveur Nom de la connexion
1491
 * @param bool $option
1492
 *     Peut avoir 3 valeurs :
1493
 *
1494
 *     - false : ne pas l'exécuter mais la retourner,
1495
 *     - true : exécuter la requête
1496
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1497
 * @return bool|string
1498
 *     - string Texte de la requête si demandée,
1499
 *     - true si la requête a réussie, false sinon
1500
 */
1501
function sql_repair($table, $serveur = '', $option = true) {
1502
	$f = sql_serveur('repair', $serveur, $option === 'continue' or $option === false);
1503
	if (!is_string($f) or !$f) {
1504
		return false;
1505
	}
1506
	$r = $f($table, $serveur, $option !== false);
1507
	if ($r === false) {
1508
		spip_sql_erreur($serveur);
1509
	}
1510
1511
	return $r;
1512
}
1513
1514
1515
/**
1516
 * Exécute une requête SQL
1517
 *
1518
 * Fonction la plus générale ... et la moins portable
1519
 * À n'utiliser qu'en dernière extrémité
1520
 *
1521
 * @api
1522
 * @param string $ins Requête
1523
 * @param string $serveur Nom de la connexion
1524
 * @param bool $option
1525
 *     Peut avoir 3 valeurs :
1526
 *
1527
 *     - false : ne pas l'exécuter mais la retourner,
1528
 *     - true : exécuter la requête
1529
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
1530
 * @return array|resource|string|bool
1531
 *     - string : Texte de la requête si on ne l'exécute pas
1532
 *     - ressource|bool : Si requête exécutée
1533
 *     - array : Tableau décrivant requête et temps d'exécution si var_profile actif pour tracer.
1534
 */
1535
function sql_query($ins, $serveur = '', $option = true) {
1536
	$f = sql_serveur('query', $serveur, $option === 'continue' or $option === false);
1537
	if (!is_string($f) or !$f) {
1538
		return false;
1539
	}
1540
	$r = $f($ins, $serveur, $option !== false);
1541
	if ($r === false) {
1542
		spip_sql_erreur($serveur);
1543
	}
1544
1545
	return $r;
1546
}
1547
1548
/**
1549
 * Retourne la première ligne d'une sélection
1550
 *
1551
 * Retourne la première ligne de résultat d'une sélection
1552
 * comme si l'on appelait successivement `sql_select()` puis `sql_fetch()`
1553
 *
1554
 * @example
1555
 *     ```
1556
 *     $art = sql_fetsel(array('id_rubrique','id_secteur'), 'spip_articles', 'id_article='.sql_quote($id_article));
1557
 *     $id_rubrique = $art['id_rubrique'];
1558
 *     ```
1559
 *
1560
 * @api
1561
 * @uses sql_select()
1562
 * @uses sql_fetch()
1563
 * @see  sql_getfetsel()
1564
 *
1565
 * @param array|string $select
1566
 *    Liste des champs a recuperer (Select)
1567
 * @param array|string $from
1568
 *    Tables a consulter (From)
1569
 * @param array|string $where
1570
 *    Conditions a remplir (Where)
1571
 * @param array|string $groupby
1572
 *    Critere de regroupement (Group by)
1573
 * @param array|string $orderby
1574
 *    Tableau de classement (Order By)
1575
 * @param string $limit
1576
 *    Critere de limite (Limit)
1577
 * @param array $having
1578
 *    Tableau des des post-conditions a remplir (Having)
1579
 * @param string $serveur
1580
 *    Le serveur sollicite (pour retrouver la connexion)
1581
 * @param bool|string $option
1582
 *    Peut avoir 3 valeurs :
1583
 *    - true -> executer la requete.
1584
 *    - continue -> ne pas echouer en cas de serveur sql indisponible.
1585
 *    - false -> ne pas l'executer mais la retourner.
1586
 *
1587
 * @return array
1588
 *     Tableau de la premiere ligne de resultat de la selection tel que
1589
 *     `array('id_rubrique' => 1, 'id_secteur' => 2)`
1590
 *
1591
 **/
1592
function sql_fetsel(
1593
	$select = array(),
1594
	$from = array(),
1595
	$where = array(),
1596
	$groupby = array(),
1597
	$orderby = array(),
1598
	$limit = '',
1599
	$having = array(),
1600
	$serveur = '',
1601
	$option = true
1602
) {
1603
	$q = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option);
1604
	if ($option === false) {
1605
		return $q;
1606
	}
1607
	if (!$q) {
1608
		return array();
1609
	}
1610
	$r = sql_fetch($q, $serveur, $option);
1611
	sql_free($q, $serveur, $option);
1612
1613
	return $r;
1614
}
1615
1616
1617
/**
1618
 * Retourne le tableau de toutes les lignes d'une selection
1619
 *
1620
 * Retourne toutes les lignes de resultat d'une selection
1621
 * comme si l'on appelait successivement sql_select() puis while(sql_fetch())
1622
 *
1623
 * @example
1624
 *    ```
1625
 *    $rubs = sql_allfetsel('id_rubrique', 'spip_articles', 'id_secteur='.sql_quote($id_secteur));
1626
 *    // $rubs = array(array('id_rubrique'=>1), array('id_rubrique'=>3, ...)
1627
 *    ```
1628
 *
1629
 * @api
1630
 * @uses sql_select()
1631
 * @uses sql_fetch()
1632
 *
1633
 * @param array|string $select
1634
 *    Liste des champs a recuperer (Select)
1635
 * @param array|string $from
1636
 *    Tables a consulter (From)
1637
 * @param array|string $where
1638
 *    Conditions a remplir (Where)
1639
 * @param array|string $groupby
1640
 *    Critere de regroupement (Group by)
1641
 * @param array|string $orderby
1642
 *    Tableau de classement (Order By)
1643
 * @param string $limit
1644
 *    Critere de limite (Limit)
1645
 * @param array $having
1646
 *    Tableau des des post-conditions a remplir (Having)
1647
 * @param string $serveur
1648
 *    Le serveur sollicite (pour retrouver la connexion)
1649
 * @param bool|string $option
1650
 *    Peut avoir 3 valeurs :
1651
 *    - true -> executer la requete.
1652
 *    - continue -> ne pas echouer en cas de serveur sql indisponible.
1653
 *    - false -> ne pas l'executer mais la retourner.
1654
 *
1655
 * @return array
1656
 *    Tableau de toutes les lignes de resultat de la selection
1657
 *    Chaque entree contient un tableau des elements demandees dans le SELECT.
1658
 *    {@example
1659
 *      ```
1660
 *      array(
1661
 *        array('id_rubrique' => 1, 'id_secteur' => 2)
1662
 *        array('id_rubrique' => 4, 'id_secteur' => 2)
1663
 *        ...
1664
 *      )
1665
 *      ```
1666
 *    }
1667
 *
1668
 **/
1669
function sql_allfetsel(
1670
	$select = array(),
1671
	$from = array(),
1672
	$where = array(),
1673
	$groupby = array(),
1674
	$orderby = array(),
1675
	$limit = '',
1676
	$having = array(),
1677
	$serveur = '',
1678
	$option = true
1679
) {
1680
	$q = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option);
1681
	if ($option === false) {
1682
		return $q;
1683
	}
1684
1685
	return sql_fetch_all($q, $serveur, $option);
1686
}
1687
1688
1689
/**
1690
 * Retourne un unique champ d'une selection
1691
 *
1692
 * Retourne dans la premiere ligne de resultat d'une selection
1693
 * un unique champ demande
1694
 *
1695
 * @example
1696
 *     ```
1697
 *     $id_rubrique = sql_getfetsel('id_rubrique', 'spip_articles', 'id_article='.sql_quote($id_article));
1698
 *     ```
1699
 *
1700
 * @api
1701
 * @uses sql_fetsel()
1702
 *
1703
 * @param array|string $select
1704
 *     Liste des champs à récupérer (Select)
1705
 * @param array|string $from
1706
 *     Tables à consulter (From)
1707
 * @param array|string $where
1708
 *     Conditions à remplir (Where)
1709
 * @param array|string $groupby
1710
 *     Critère de regroupement (Group by)
1711
 * @param array|string $orderby
1712
 *     Tableau de classement (Order By)
1713
 * @param string $limit
1714
 *     Critère de limite (Limit)
1715
 * @param array $having
1716
 *     Tableau des des post-conditions à remplir (Having)
1717
 * @param string $serveur
1718
 *     Le serveur sollicité (pour retrouver la connexion)
1719
 * @param bool|string $option
1720
 *     Peut avoir 3 valeurs :
1721
 *
1722
 *     - true -> executer la requete.
1723
 *     - continue -> ne pas echouer en cas de serveur sql indisponible.
1724
 *     - false -> ne pas l'executer mais la retourner.
1725
 *
1726
 * @return mixed
1727
 *     Contenu de l'unique valeur demandee du premier enregistrement retourne
1728
 *     ou NULL si la requete ne retourne aucun enregistrement 
1729
 *
1730
 **/
1731
function sql_getfetsel(
1732
	$select,
1733
	$from = array(),
1734
	$where = array(),
1735
	$groupby = array(),
1736
	$orderby = array(),
1737
	$limit = '',
1738
	$having = array(),
1739
	$serveur = '',
1740
	$option = true
1741
) {
1742
	if (preg_match('/\s+as\s+(\w+)$/i', $select, $c)) {
1743
		$id = $c[1];
1744
	} elseif (!preg_match('/\W/', $select)) {
1745
		$id = $select;
1746
	} else {
1747
		$id = 'n';
1748
		$select .= ' AS n';
1749
	}
1750
	$r = sql_fetsel($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option);
1751
	if ($option === false) {
1752
		return $r;
1753
	}
1754
	if (!$r) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $r of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1755
		return null;
1756
	}
1757
1758
	return $r[$id];
1759
}
1760
1761
/**
1762
 * Retourne le numero de version du serveur SQL
1763
 *
1764
 * @api
1765
 * @param string $serveur
1766
 *    Nom du connecteur
1767
 * @param bool|string $option
1768
 *    Peut avoir 2 valeurs :
1769
 *    - true pour executer la requete.
1770
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
1771
 *
1772
 * @return string
1773
 *    Numero de version du serveur SQL
1774
 **/
1775
function sql_version($serveur = '', $option = true) {
0 ignored issues
show
Unused Code introduced by
The parameter $option is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1776
	$row = sql_fetsel("version() AS n", '', '', '', '', '', '', $serveur);
1777
1778
	return ($row['n']);
1779
}
1780
1781
/**
1782
 * Informe si le moteur SQL prefere utiliser des transactions
1783
 *
1784
 * Cette fonction experimentale est pour l'instant presente pour accelerer certaines
1785
 * insertions multiples en SQLite, en les encadrant d'une transaction.
1786
 * SQLite ne cree alors qu'un verrou pour l'ensemble des insertions
1787
 * et non un pour chaque, ce qui accelere grandement le processus.
1788
 * Evidemment, si une des insertions echoue, rien ne sera enregistre.
1789
 * Pour ne pas perturber les autres moteurs, cette fonction permet
1790
 * de verifier que le moteur prefere utiliser des transactions dans ce cas.
1791
 *
1792
 * @example
1793
 *    ```
1794
 *    if (sql_preferer_transaction()) {
1795
 *      sql_demarrer_transaction();
1796
 *    }
1797
 *    ```
1798
 *
1799
 * @api
1800
 * @see sql_demarrer_transaction()
1801
 * @see sql_terminer_transaction()
1802
 *
1803
 * @param string $serveur
1804
 *    Nom du connecteur
1805
 * @param bool|string $option
1806
 *    Peut avoir 2 valeurs :
1807
 *    - true pour executer la requete.
1808
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
1809
 *
1810
 * @return bool
1811
 *    Le serveur SQL prefere t'il des transactions pour les insertions multiples ?
1812
 **/
1813 View Code Duplication
function sql_preferer_transaction($serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1814
	$f = sql_serveur('preferer_transaction', $serveur, 'continue');
1815
	if (!is_string($f) or !$f) {
1816
		return false;
1817
	}
1818
	$r = $f($serveur, $option !== false);
1819
	if ($r === false) {
1820
		spip_sql_erreur($serveur);
1821
	}
1822
1823
	return $r;
1824
}
1825
1826
;
1827
1828
/**
1829
 * Démarre une transaction
1830
 *
1831
 * @api
1832
 * @see sql_terminer_transaction() Pour cloturer la transaction
1833
 *
1834
 * @param string $serveur
1835
 *    Nom du connecteur
1836
 * @param bool|string $option
1837
 *    Peut avoir 3 valeurs :
1838
 *
1839
 *    - true pour executer la requete.
1840
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
1841
 *    - false pour obtenir le code de la requete
1842
 *
1843
 * @return bool
1844
 *      true si la transaction est demarree
1845
 *      false en cas d'erreur
1846
 **/
1847 View Code Duplication
function sql_demarrer_transaction($serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1848
	$f = sql_serveur('demarrer_transaction', $serveur, 'continue');
1849
	if (!is_string($f) or !$f) {
1850
		return false;
1851
	}
1852
	$r = $f($serveur, $option !== false);
1853
	if ($r === false) {
1854
		spip_sql_erreur($serveur);
1855
	}
1856
1857
	return $r;
1858
}
1859
1860
;
1861
1862
/**
1863
 * Termine une transaction
1864
 *
1865
 * @api
1866
 * @see sql_demarrer_transaction() Pour demarrer une transaction
1867
 *
1868
 * @param string $serveur
1869
 *    Nom du connecteur
1870
 * @param bool|string $option
1871
 *    Peut avoir 3 valeurs :
1872
 *
1873
 *    - true pour executer la requete.
1874
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
1875
 *    - false pour obtenir le code de la requete
1876
 *
1877
 * @return bool
1878
 *      true si la transaction est demarree
1879
 *      false en cas d'erreur
1880
 **/
1881 View Code Duplication
function sql_terminer_transaction($serveur = '', $option = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1882
	$f = sql_serveur('terminer_transaction', $serveur, 'continue');
1883
	if (!is_string($f) or !$f) {
1884
		return false;
1885
	}
1886
	$r = $f($serveur, $option !== false);
1887
	if ($r === false) {
1888
		spip_sql_erreur($serveur);
1889
	}
1890
1891
	return $r;
1892
}
1893
1894
;
1895
1896
1897
/**
1898
 * Prépare une chaine hexadécimale
1899
 *
1900
 * Prend une chaîne sur l'aphabet hexa
1901
 * et retourne sa représentation numérique attendue par le serveur SQL.
1902
 * Par exemple : FF ==> 0xFF en MySQL mais x'FF' en PG
1903
 *
1904
 * @api
1905
 * @param string $val
1906
 *     Chaine hexadécimale
1907
 * @param string $serveur
1908
 *     Nom du connecteur
1909
 * @param bool|string $option
1910
 *     Peut avoir 2 valeurs :
1911
 *
1912
 *     - true pour exécuter la demande.
1913
 *     - 'continue' pour ne pas échouer en cas de serveur SQL indisponible.
1914
 * @return string
1915
 *     Valeur hexadécimale attendue par le serveur SQL
1916
 **/
1917
function sql_hex($val, $serveur = '', $option = true) {
1918
	$f = sql_serveur('hex', $serveur, $option === 'continue' or $option === false);
1919
	if (!is_string($f) or !$f) {
1920
		return false;
1921
	}
1922
1923
	return $f($val);
1924
}
1925
1926
/**
1927
 * Echapper du contenu
1928
 *
1929
 * Echappe du contenu selon ce qu'attend le type de serveur SQL
1930
 * et en fonction du type de contenu.
1931
 *
1932
 * Permet entre autres de se protéger d'injections SQL.
1933
 *
1934
 * Cette fonction est automatiquement appelée par les fonctions `sql_*q`
1935
 * tel que `sql_instertq` ou `sql_updateq`
1936
 *
1937
 * @api
1938
 * @param string $val
1939
 *     Chaine à echapper
1940
 * @param string $serveur
1941
 *     Nom du connecteur
1942
 * @param string $type
1943
 *     Peut contenir une declaration de type de champ SQL.
1944
 *     Exemple : `int NOT NULL` qui sert alors aussi à calculer le type d'échappement
1945
 * @return string
1946
 *     La chaine echappee
1947
 **/
1948
function sql_quote($val, $serveur = '', $type = '') {
1949
	$f = sql_serveur('quote', $serveur, true);
1950
	if (!is_string($f) or !$f) {
1951
		$f = '_q';
1952
	}
1953
1954
	return $f($val, $type);
1955
}
1956
1957
/**
1958
 * Tester si une date est proche de la valeur d'un champ
1959
 *
1960
 * @api
1961
 * @param string $champ
1962
 *     Nom du champ a tester
1963
 * @param int $interval
1964
 *     Valeur de l'intervalle : -1, 4, ...
1965
 * @param string $unite
1966
 *     Utité utilisée (DAY, MONTH, YEAR, ...)
1967
 * @param string $serveur
1968
 *     Nom du connecteur
1969
 * @param bool|string $option
1970
 *     Peut avoir 2 valeurs :
1971
 *
1972
 *     - true pour exécuter la demande.
1973
 *     - 'continue' pour ne pas échouer en cas de serveur SQL indisponible.
1974
 * @return string|bool
1975
 *     - string : Expression SQL
1976
 *     - false si le serveur SQL est indisponible
1977
 **/
1978
function sql_date_proche($champ, $interval, $unite, $serveur = '', $option = true) {
0 ignored issues
show
Unused Code introduced by
The parameter $option is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1979
	$f = sql_serveur('date_proche', $serveur, true);
1980
	if (!is_string($f) or !$f) {
1981
		return false;
1982
	}
1983
1984
	return $f($champ, $interval, $unite);
1985
}
1986
1987
/**
1988
 * Retourne une expression IN pour le gestionnaire de base de données
1989
 *
1990
 * Retourne un code à insérer dans une requête SQL pour récupérer
1991
 * les éléments d'une colonne qui appartiennent à une liste donnée
1992
 *
1993
 * @example
1994
 *     `sql_in('id_rubrique', array(3,4,5))`
1995
 *     retourne approximativement «id_rubrique IN (3,4,5)» selon ce qu'attend
1996
 *     le gestionnaire de base de donnée du connecteur en cours.
1997
 *
1998
 * @api
1999
 * @param string $val
2000
 *     Colonne SQL sur laquelle appliquer le test
2001
 * @param string|array $valeurs
2002
 *     Liste des valeurs possibles (séparés par des virgules si string)
2003
 * @param string $not
2004
 *     - '' sélectionne les éléments correspondant aux valeurs
2005
 *     - 'NOT' inverse en sélectionnant les éléments ne correspondant pas aux valeurs
2006
 * @param string $serveur
2007
 *   Nom du connecteur
2008
 * @param bool|string $option
2009
 *   Peut avoir 2 valeurs :
2010
 *
2011
 *   - continue -> ne pas echouer en cas de serveur sql indisponible
2012
 *   - true ou false -> retourne l'expression
2013
 * @return string
2014
 *     Expression de requête SQL
2015
 **/
2016
function sql_in($val, $valeurs, $not = '', $serveur = '', $option = true) {
2017
	if (is_array($valeurs)) {
2018
		$f = sql_serveur('quote', $serveur, true);
2019
		if (!is_string($f) or !$f) {
2020
			return false;
2021
		}
2022
		$valeurs = join(',', array_map($f, array_unique($valeurs)));
2023
	} elseif (isset($valeurs[0]) and $valeurs[0] === ',') {
2024
		$valeurs = substr($valeurs, 1);
2025
	}
2026
	if (!strlen(trim($valeurs))) {
2027
		return ($not ? "0=0" : '0=1');
2028
	}
2029
2030
	$f = sql_serveur('in', $serveur, $option === 'continue' or $option === false);
2031
	if (!is_string($f) or !$f) {
2032
		return false;
2033
	}
2034
2035
	return $f($val, $valeurs, $not, $serveur, $option !== false);
2036
}
2037
2038
2039
/**
2040
 * Retourne une expression IN pour le gestionnaire de base de données
2041
 * à partir d'une sélection de données
2042
 *
2043
 * Sélectionne les données (comme sql_select()) et prépare avec l'expression IN
2044
 *
2045
 * @see sql_select()
2046
 * @see sql_in()
2047
 * @note
2048
 *   Penser à dire dans la description du serveur
2049
 *   s'il accepte les requêtes imbriquées afin d'optimiser ca
2050
 *
2051
 * @api
2052
 * @param string $in
2053
 *     Colonne SQL sur laquelle appliquer le test
2054
 * @param array|string $select
2055
 *     Liste des champs à récupérer (Select).
2056
 *     La donnée extraite est le premier élément de la sélection.
2057
 * @param array|string $from
2058
 *     Tables a consulter (From)
2059
 * @param array|string $where
2060
 *     Conditions a remplir (Where)
2061
 * @param array|string $groupby
2062
 *     Critere de regroupement (Group by)
2063
 * @param array|string $orderby
2064
 *     Tableau de classement (Order By)
2065
 * @param string $limit
2066
 *     Critere de limite (Limit)
2067
 * @param array $having
2068
 *     Tableau des des post-conditions a remplir (Having)
2069
 * @param string $serveur
2070
 *     Nom du connecteur
2071
 * @return string
2072
 *     Expression de requête SQL
2073
 **/
2074
function sql_in_select(
2075
	$in,
2076
	$select,
2077
	$from = array(),
2078
	$where = array(),
2079
	$groupby = array(),
2080
	$orderby = array(),
2081
	$limit = '',
2082
	$having = array(),
2083
	$serveur = ''
2084
) {
2085
	$liste = array();
2086
	$res = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur);
2087
	while ($r = sql_fetch($res)) {
2088
		$liste[] = array_shift($r);
2089
	}
2090
	sql_free($res);
2091
2092
	return sql_in($in, $liste);
2093
}
2094
2095
/**
2096
 * Implémentation sécurisée du saut en avant.
2097
 *
2098
 * Ne dépend pas de la disponibilité de la fonction `sql_seek()`.
2099
 * Ne fait rien pour une valeur négative ou nulle de `$saut`.
2100
 * Retourne la position après le saut
2101
 *
2102
 * @see sql_seek()
2103
 *
2104
 * @param resource $res
2105
 *    Ressource issue d'une selection sql_select
2106
 * @param int $pos
2107
 *   position courante
2108
 * @param int $saut
2109
 *   saut demande
2110
 * @param int $count
2111
 *   position maximale
2112
 *   (nombre de resultat de la requete OU position qu'on ne veut pas depasser)
2113
 * @param string $serveur
2114
 *   Nom du connecteur
2115
 * @param bool|string $option
2116
 *   Peut avoir 2 valeurs :
2117
 *   - true -> executer la requete
2118
 *   - continue -> ne pas echouer en cas de serveur sql indisponible
2119
 *
2120
 * @return int
2121
 *    Position apres le saut.
2122
 */
2123
function sql_skip($res, $pos, $saut, $count, $serveur = '', $option = true) {
2124
	// pas de saut en arriere qu'on ne sait pas faire sans sql_seek
2125
	if (($saut = intval($saut)) <= 0) {
2126
		return $pos;
2127
	}
2128
2129
	$seek = $pos + $saut;
2130
	// si le saut fait depasser le maxi, on libere la resource
2131
	// et on sort
2132
	if ($seek >= $count) {
2133
		sql_free($res, $serveur, $option);
2134
2135
		return $count;
2136
	}
2137
2138
	if (sql_seek($res, $seek)) {
2139
		$pos = $seek;
2140
	} else {
2141
		while ($pos < $seek and sql_fetch($res, $serveur, $option)) {
2142
			$pos++;
2143
		}
2144
	}
2145
2146
	return $pos;
2147
}
2148
2149
2150
/**
2151
 * Teste qu'une description de champ SQL est de type entier
2152
 *
2153
 * @api
2154
 * @see sql_test_date() pour tester les champs de date
2155
 *
2156
 * @param string $type
2157
 *     Description de la colonne SQL
2158
 * @param string $serveur
2159
 *    Nom du connecteur
2160
 * @param bool $option
2161
 *     Inutilisé
2162
 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2163
 *     True si le champ est de type entier
2164
 */
2165
function sql_test_int($type, $serveur = '', $option = true) {
0 ignored issues
show
Unused Code introduced by
The parameter $serveur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $option is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2166
	return preg_match('/^(TINYINT|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT)/i', trim($type));
2167
}
2168
2169
/**
2170
 * Teste qu'une description de champ SQL est de type entier
2171
 *
2172
 * @api
2173
 * @see sql_test_int() pour tester les champs d'entiers
2174
 *
2175
 * @param string $type
2176
 *     Description de la colonne SQL
2177
 * @param string $serveur
2178
 *    Nom du connecteur
2179
 * @param bool $option
2180
 *     Inutilisé
2181
 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2182
 *     True si le champ est de type entier
2183
 */
2184
function sql_test_date($type, $serveur = '', $option = true) {
0 ignored issues
show
Unused Code introduced by
The parameter $serveur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $option is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2185
	return preg_match('/^(DATE|DATETIME|TIMESTAMP|TIME)/i', trim($type));
2186
}
2187
2188
/**
2189
 * Formate une date
2190
 *
2191
 * Formater une date Y-m-d H:i:s sans passer par mktime
2192
 * qui ne sait pas gerer les dates < 1970
2193
 *
2194
 * @api
2195
 * @param int $annee Annee
2196
 * @param int $mois Numero du mois
2197
 * @param int $jour Numero du jour dans le mois
2198
 * @param int $h Heures
2199
 * @param int $m Minutes
2200
 * @param int $s Secondes
2201
 * @param string $serveur
2202
 *     Le serveur sollicite (pour retrouver la connexion)
2203
 * @return string
2204
 *     La date formatee
2205
 */
2206
function sql_format_date($annee = 0, $mois = 0, $jour = 0, $h = 0, $m = 0, $s = 0, $serveur = '') {
0 ignored issues
show
Unused Code introduced by
The parameter $serveur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2207
	$annee = sprintf("%04s", $annee);
2208
	$mois = sprintf("%02s", $mois);
2209
2210
	if ($annee == "0000") {
2211
		$mois = 0;
2212
	}
2213
	if ($mois == "00") {
2214
		$jour = 0;
2215
	}
2216
2217
	return sprintf("%04u", $annee) . '-' . sprintf("%02u", $mois) . '-'
2218
	. sprintf("%02u", $jour) . ' ' . sprintf("%02u", $h) . ':'
2219
	. sprintf("%02u", $m) . ':' . sprintf("%02u", $s);
2220
}
2221
2222
2223
/**
2224
 * Retourne la description de la table SQL
2225
 *
2226
 * Retrouve la description de la table SQL en privilegiant
2227
 * la structure reelle de la base de donnees.
2228
 * En absence, ce qui arrive lors de l'installation, la fonction
2229
 * s'appuie sur la declaration des tables SQL principales ou auxiliaires.
2230
 *
2231
 * @internal Cette fonction devrait disparaître
2232
 *
2233
 * @param string $nom
2234
 *    Nom de la table dont on souhait la description
2235
 * @param string $serveur
2236
 *    Nom du connecteur
2237
 * @return array|bool
2238
 *    Description de la table ou false si elle n'est pas trouvee ou declaree.
2239
 **/
2240
function description_table($nom, $serveur = '') {
2241
2242
	static $trouver_table;
2243
2244
	/* toujours utiliser trouver_table
2245
	 qui renverra la description theorique
2246
	 car sinon on va se comporter differement selon que la table est declaree
2247
	 ou non
2248
	 */
2249
	if (!$trouver_table) {
2250
		$trouver_table = charger_fonction('trouver_table', 'base');
2251
	}
2252
	if ($desc = $trouver_table($nom, $serveur)) {
2253
		return $desc;
2254
	}
2255
2256
	// sauf a l'installation :
2257
	include_spip('base/serial');
2258
	if (isset($GLOBALS['tables_principales'][$nom])) {
2259
		return $GLOBALS['tables_principales'][$nom];
2260
	}
2261
2262
	include_spip('base/auxiliaires');
2263
	if (isset($GLOBALS['tables_auxiliaires'][$nom])) {
2264
		return $GLOBALS['tables_auxiliaires'][$nom];
2265
	}
2266
2267
	return false;
2268
}
2269
2270
/**
2271
 * Corrige le nom d’une table SQL en utilisant le bon préfixe
2272
 *
2273
 * Ie: si prefixe 'dev', retournera, pour la table 'spip_articles' : 'dev_articles'.
2274
 *
2275
 * @param string $table
2276
 * @param string $prefixe
2277
 * @return string Table sql éventuellement renommée
2278
 */
2279
function prefixer_table_spip($table, $prefixe) {
2280
	if ($prefixe) {
2281
		$table = preg_replace('/^spip_/', $prefixe . '_', $table);
2282
	}
2283
	return $table;
2284
}