| Line 23... |
Line 23... |
| 23 |
// *et* la valeur maximale autorisée pour navigation.limite.
|
23 |
// *et* la valeur maximale autorisée pour navigation.limite.
|
| 24 |
define('_COSTE_TEXTE_MAX_RESULT_LIMIT', 500);
|
24 |
define('_COSTE_TEXTE_MAX_RESULT_LIMIT', 500);
|
| Line 25... |
Line 25... |
| 25 |
|
25 |
|
| 26 |
// simplifie et accélère la sanitization de l'input:
|
26 |
// simplifie et accélère la sanitization de l'input:
|
| 27 |
// SELECT MAX(num_nom) FROM coste_v2_00;
|
27 |
// SELECT MAX(num_nom) FROM coste_v2_00;
|
| - |
|
28 |
define('_COSTE_TEXTE_MAX_COSTE_NN', 7015 + 1000);
|
| - |
|
29 |
// SELECT MAX(num_nom) FROM bdtfx_v1_02;
|
| Line 28... |
Line 30... |
| 28 |
define('_COSTE_TEXTE_MAX_NUM_NOM', 7015 + 1000);
|
30 |
define('_COSTE_TEXTE_MAX_BDTFX_NN', 103386 + 10000);
|
| 29 |
|
31 |
|
| 30 |
/*restore_error_handler();
|
32 |
/*restore_error_handler();
|
| 31 |
error_reporting(E_ALL);*/
|
33 |
error_reporting(E_ALL);*/
|
| Line 43... |
Line 45... |
| 43 |
'navigation.depart' => 0, 'navigation.limite' => 50);
|
45 |
'navigation.depart' => 0, 'navigation.limite' => 50);
|
| Line 44... |
Line 46... |
| 44 |
|
46 |
|
| 45 |
// les champs de base de coste_v2_00
|
47 |
// les champs de base de coste_v2_00
|
| 46 |
// mysql -N tb_eflore<<<"SHOW FIELDS FROM coste_v2_00"|egrep -v 'page_'|awk '{print $1}'|xargs -i -n1 printf "'%s' => 'c.%s',\n" {} {}
|
48 |
// mysql -N tb_eflore<<<"SHOW FIELDS FROM coste_v2_00"|egrep -v 'page_'|awk '{print $1}'|xargs -i -n1 printf "'%s' => 'c.%s',\n" {} {}
|
| - |
|
49 |
static $allow_champs = array(
|
| - |
|
50 |
'coste:nn' => 'c.num_nom',
|
| - |
|
51 |
'bdtfx:nn' => 'IF(c.flore_bdtfx_nn = "",NULL,c.flore_bdtfx_nn)',
|
| 47 |
static $allow_champs = array(
|
52 |
'bdtfx:nt' => 'c.flore_bdtfx_nt',
|
| 48 |
'num_nom' => 'c.num_nom',
|
53 |
'num_nom' => 'c.num_nom',
|
| 49 |
'num_nom_retenu' => 'c.num_nom_retenu',
|
54 |
'num_nom_retenu' => 'c.num_nom_retenu',
|
| 50 |
'num_tax_sup' => 'c.num_tax_sup',
|
55 |
'num_tax_sup' => 'c.num_tax_sup',
|
| 51 |
'rang' => 'c.rang',
|
56 |
'rang' => 'c.rang',
|
| Line 91... |
Line 96... |
| 91 |
'famille' => 'b.famille', // cf sqlAddJoins()
|
96 |
'famille' => 'b.famille', // cf sqlAddJoins()
|
| 92 |
'*' => 'XXX' // spécial
|
97 |
'*' => 'XXX' // spécial
|
| 93 |
);
|
98 |
);
|
| Line 94... |
Line 99... |
| 94 |
|
99 |
|
| - |
|
100 |
// les champs suivants disparaissent de la liste utilisée pour former la requête SQL
|
| 95 |
// les champs suivants disparaissent de la liste utilisée pour former la requête SQL
|
101 |
// (ils sont exclue lorsque '*' est utilisée, ce sont généralement des synonymes)
|
| - |
|
102 |
static $special_champs = array('nom_sci_html', 'nom_sci', '*', 'flore_bdtfx_nn', 'flore_bdtfx_nt', 'num_nom');
|
| - |
|
103 |
|
| - |
|
104 |
// ces champs sont toujours dans les résultats (cf sqlSelectFields()
|
| - |
|
105 |
static $champs_obligatoires = array('coste:nn', 'bdtfx:nn');
|
| - |
|
106 |
|
| 96 |
static $special_champs = array('nom_sci_html', 'nom_sci', '*');
|
107 |
|
| 97 |
// le pattern utilisé pour la recherche dite "floue"
|
108 |
// le pattern utilisé pour la recherche dite "floue"
|
| Line 98... |
Line 109... |
| 98 |
static $soundex_scheme = '(%1$s LIKE %2$s OR SOUNDEX(%1$s) = SOUNDEX(%2$s) OR SOUNDEX(REVERSE(%1$s)) = SOUNDEX(REVERSE(%2$s)))';
|
109 |
static $soundex_scheme = '(%1$s LIKE %2$s OR SOUNDEX(%1$s) = SOUNDEX(%2$s) OR SOUNDEX(REVERSE(%1$s)) = SOUNDEX(REVERSE(%2$s)))';
|
| 99 |
|
110 |
|
| Line 143... |
Line 154... |
| 143 |
// nombre de matches (sans LIMIT) utilisé pour l'en-tête
|
154 |
// nombre de matches (sans LIMIT) utilisé pour l'en-tête
|
| 144 |
$matches = $db->recuperer('SELECT FOUND_ROWS() AS total');
|
155 |
$matches = $db->recuperer('SELECT FOUND_ROWS() AS total');
|
| 145 |
$matches = intval($matches['total']);
|
156 |
$matches = intval($matches['total']);
|
| 146 |
}
|
157 |
}
|
| Line 147... |
Line 158... |
| 147 |
|
158 |
|
| 148 |
// reformate les résultats pour les indexer par num_nom
|
159 |
// reformate les résultats pour les indexer par coste:nn
|
| 149 |
$res2 = array();
|
160 |
$res2 = array();
|
| 150 |
foreach($res as $v) {
|
161 |
foreach($res as $v) {
|
| 151 |
$res2[$v['num_nom']] = $v;
|
162 |
$res2[$v['coste:nn']] = $v;
|
| Line 152... |
Line 163... |
| 152 |
}
|
163 |
}
|
| 153 |
|
164 |
|
| 154 |
// l'appelant s'occupera du json_encode()
|
165 |
// l'appelant s'occupera du json_encode()
|
| Line 161... |
Line 172... |
| 161 |
'resultats' => $res2);
|
172 |
'resultats' => $res2);
|
| Line 162... |
Line 173... |
| 162 |
|
173 |
|
| Line 163... |
Line 174... |
| 163 |
}
|
174 |
}
|
| 164 |
|
175 |
|
| 165 |
|
176 |
|
| 166 |
// la fonction central: récupère les infos à partir de paramètres
|
177 |
// la fonction centrale: récupère les infos à partir de paramètres
|
| 167 |
// et une optionnel contrainte de num_nom
|
178 |
// et une optionnelle contrainte sur coste:nn ou bdtfx:nn
|
| 168 |
static function getCosteInfo(array $params, $db) {
|
179 |
static function getCosteInfo(array $params, $db) {
|
| Line 174... |
Line 185... |
| 174 |
$champs_valides_non_formattes = NULL;
|
185 |
$champs_valides_non_formattes = NULL;
|
| 175 |
$champs_valides = self::sqlSelectFields($params, $champs_valides_non_formattes);
|
186 |
$champs_valides = self::sqlSelectFields($params, $champs_valides_non_formattes);
|
| Line 176... |
Line 187... |
| 176 |
|
187 |
|
| 177 |
// joins:
|
188 |
// joins:
|
| 178 |
$other_join = self::sqlAddJoins($params, $champs_valides_non_formattes);
|
- |
|
| 179 |
|
189 |
$other_join = self::sqlAddJoins($params, $champs_valides_non_formattes);
|
| 180 |
$req = sprintf(<<<EOF
|
190 |
$req = sprintf(<<<EOF
|
| 181 |
SELECT SQL_CALC_FOUND_ROWS c.num_nom, %s
|
191 |
SELECT SQL_CALC_FOUND_ROWS %s
|
| 182 |
FROM tb_eflore.coste_v2_00 c
|
192 |
FROM tb_eflore.coste_v2_00 c
|
| 183 |
LEFT JOIN tela_prod_wikini.florecoste_pages dsc ON c.page_wiki_dsc = dsc.tag AND dsc.latest = 'Y'
|
193 |
LEFT JOIN tela_prod_wikini.florecoste_pages dsc ON c.page_wiki_dsc = dsc.tag AND dsc.latest = 'Y'
|
| 184 |
LEFT JOIN tela_prod_wikini.florecoste_pages cle ON c.page_wiki_cle = cle.tag AND cle.latest = 'Y'
|
194 |
LEFT JOIN tela_prod_wikini.florecoste_pages cle ON c.page_wiki_cle = cle.tag AND cle.latest = 'Y'
|
| 185 |
%s
|
195 |
%s
|
| Line 253... |
Line 263... |
| 253 |
|
263 |
|
| 254 |
if(array_key_exists('masque.tome', $params)) {
|
264 |
if(array_key_exists('masque.tome', $params)) {
|
| 255 |
$stack[] = 'c.tome = ' . intval($params['masque.tome']);
|
265 |
$stack[] = 'c.tome = ' . intval($params['masque.tome']);
|
| Line 256... |
Line 266... |
| 256 |
}
|
266 |
}
|
| 257 |
|
267 |
|
| - |
|
268 |
// ajout de la contrainte sur coste:nn ou bdtfx:nn si un composant d'URL supplémentaire
|
| 258 |
// ajout de la contrainte sur num_nom si un composant d'URL supplémentaire
|
269 |
// comportant un #id existe, cf self::requestFilterIds()
|
| - |
|
270 |
$o_stack = array();
|
| 259 |
// comportant un #id existe, cf self::requestFilterIds()
|
271 |
if(array_key_exists('_ids', $params) && $params['_ids']) {
|
| - |
|
272 |
if($params['_ids']['coste']) {
|
| - |
|
273 |
$o_stack[] = sprintf("c.num_nom IN (%s)", implode(',', $params['_ids']['coste']));
|
| - |
|
274 |
}
|
| - |
|
275 |
if($params['_ids']['bdtfx']) {
|
| 260 |
if(array_key_exists('_ids', $params) && $params['_ids']) {
|
276 |
$o_stack[] = sprintf("c.flore_bdtfx_nn IN (%s)", implode(',', $params['_ids']['bdtfx']));
|
| - |
|
277 |
}
|
| Line 261... |
Line 278... |
| 261 |
$stack[] = sprintf("c.num_nom IN (%s)", implode(',', $params['_ids']));
|
278 |
}
|
| 262 |
}
|
279 |
if($o_stack) $stack[] = '(' . implode(' OR ', $o_stack) . ')';
|
| Line 269... |
Line 286... |
| 269 |
// à la différence que celle-ci n'est pas reformatée et s'avère donc
|
286 |
// à la différence que celle-ci n'est pas reformatée et s'avère donc
|
| 270 |
// utilisable plus aisément dans sqlAddJoins() qui peut en avoir besoin
|
287 |
// utilisable plus aisément dans sqlAddJoins() qui peut en avoir besoin
|
| 271 |
static function sqlSelectFields($params, &$unmerged) {
|
288 |
static function sqlSelectFields($params, &$unmerged) {
|
| 272 |
$champs = $params['retour.champs'];
|
289 |
$champs = $params['retour.champs'];
|
| 273 |
// champs coste_v2_00
|
290 |
// champs coste_v2_00
|
| 274 |
$c = array_intersect_key(self::$allow_champs, array_flip(explode(',', $champs)));
|
291 |
$c = self::addSQLToFieldSynonym(explode(',', $champs));
|
| 275 |
if(isset($c['*'])) {
|
292 |
if(isset($c['*'])) {
|
| 276 |
$t = array_diff_key(self::$allow_champs, array_flip(self::$special_champs));
|
293 |
$t = array_diff_key(self::$allow_champs, array_flip(self::$special_champs));
|
| 277 |
}
|
294 |
}
|
| 278 |
else {
|
295 |
else {
|
| 279 |
// just loop below
|
296 |
// just loop below
|
| Line 289... |
Line 306... |
| 289 |
}
|
306 |
}
|
| Line 290... |
Line 307... |
| 290 |
|
307 |
|
| 291 |
if(array_key_exists('titre', $t))
|
308 |
if(array_key_exists('titre', $t))
|
| Line -... |
Line 309... |
| - |
|
309 |
$t['titre'] = $params['txt.format'] == 'txt' ? 'c.nom_sci' : 'c.nom_sci_html';
|
| - |
|
310 |
|
| 292 |
$t['titre'] = $params['txt.format'] == 'txt' ? 'c.nom_sci' : 'c.nom_sci_html';
|
311 |
// champs obligatoires:
|
| Line 293... |
Line 312... |
| 293 |
|
312 |
$t = array_merge($t, self::addSQLToFieldSynonym(self::$champs_obligatoires));
|
| 294 |
$unmerged = $t;
|
313 |
$unmerged = $t;
|
| 295 |
|
314 |
|
| - |
|
315 |
// XXX: PHP-5.3
|
| - |
|
316 |
$ret = array();
|
| - |
|
317 |
foreach($t as $k => $v) {
|
| 296 |
// XXX: PHP-5.3
|
318 |
if(strpos($k, ':') !== FALSE) {
|
| - |
|
319 |
$ret[] = "$v AS \"$k\"";
|
| 297 |
$ret = array();
|
320 |
} else {
|
| 298 |
foreach($t as $k => $v) {
|
321 |
$ret[] = "$v AS $k";
|
| 299 |
$ret[] = "$v AS $k";
|
322 |
}
|
| Line 300... |
Line 323... |
| 300 |
}
|
323 |
}
|
| 301 |
return implode(',',$ret);
|
324 |
return implode(',',$ret);
|
| 302 |
}
|
325 |
}
|
| 303 |
|
326 |
|
| 304 |
static function sqlAddJoins($params, $champs) {
|
327 |
static function sqlAddJoins($params, $champs) {
|
| 305 |
$j = '';
|
328 |
$j = '';
|
| 306 |
// ces tests doivent correspondre aux champs générés par sqlSelectFields()
|
329 |
// ces tests doivent correspondre aux champs générés par sqlSelectFields()
|
| 307 |
// ou contraintes générées par sqlAddConstraint()
|
330 |
// ou contraintes générées par sqlAddConstraint()
|
| Line 308... |
Line 331... |
| 308 |
if(array_key_exists('masque.famille', $params) ||
|
331 |
if(array_key_exists('masque.famille', $params) ||
|
| 309 |
array_key_exists('famille', $champs)) {
|
332 |
array_key_exists('famille', $champs)) {
|
| Line -... |
Line 333... |
| - |
|
333 |
$j .= 'LEFT JOIN tb_eflore.bdtfx_v1_02 b ON c.flore_bdtfx_nn = b.num_nom';
|
| - |
|
334 |
}
|
| - |
|
335 |
|
| - |
|
336 |
return $j;
|
| - |
|
337 |
}
|
| - |
|
338 |
|
| - |
|
339 |
// d'un tableau de type array("coste:nn", "type_epithete")
|
| - |
|
340 |
// retourne
|
| 310 |
$j .= 'LEFT JOIN tb_eflore.bdtfx_v1_02 b ON c.num_nom = b.num_nom';
|
341 |
// un tableau de type array("coste:nn" => "c.num_nom", "type_epithete" => "c.type_epithete")
|
| 311 |
}
|
342 |
// basé sur self::$allow_champs
|
| 312 |
|
343 |
static function addSQLToFieldSynonym(Array $syno) {
|
| 313 |
return $j;
|
344 |
return array_intersect_key(self::$allow_champs, array_flip($syno));
|
| 314 |
}
|
345 |
}
|
| Line 353... |
Line 384... |
| 353 |
'max_range' => _COSTE_TEXTE_MAX_RESULT_LIMIT)));
|
384 |
'max_range' => _COSTE_TEXTE_MAX_RESULT_LIMIT)));
|
| 354 |
$p['navigation.depart'] = filter_var(@$params['navigation.depart'],
|
385 |
$p['navigation.depart'] = filter_var(@$params['navigation.depart'],
|
| 355 |
FILTER_VALIDATE_INT,
|
386 |
FILTER_VALIDATE_INT,
|
| 356 |
array('options' => array('default' => NULL,
|
387 |
array('options' => array('default' => NULL,
|
| 357 |
'min_range' => 0,
|
388 |
'min_range' => 0,
|
| 358 |
'max_range' => _COSTE_TEXTE_MAX_NUM_NOM)));
|
389 |
'max_range' => _COSTE_TEXTE_MAX_COSTE_NN)));
|
| Line 359... |
Line 390... |
| 359 |
|
390 |
|
| 360 |
// on filtre les NULL, FALSE et '', mais pas les 0, d'où le callback()
|
391 |
// on filtre les NULL, FALSE et '', mais pas les 0, d'où le callback()
|
| 361 |
// TODO: PHP-5.3
|
392 |
// TODO: PHP-5.3
|
| 362 |
$p = array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);'));
|
393 |
$p = array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);'));
|
| Line 366... |
Line 397... |
| 366 |
}
|
397 |
}
|
| Line 367... |
Line 398... |
| 367 |
|
398 |
|
| 368 |
static function requestFilterIds($uri) {
|
399 |
static function requestFilterIds($uri) {
|
| Line 369... |
Line 400... |
| 369 |
if(count($uri) != 1) return NULL;
|
400 |
if(count($uri) != 1) return NULL;
|
| - |
|
401 |
|
| - |
|
402 |
// getNN* renvoient le num_nom passé comme segment d'URI:
|
| 370 |
|
403 |
// - soit un id selon coste (num_nom dans coste_v2_00)
|
| - |
|
404 |
// - soit un id selon bdtfx (num_nom dans bdtfx_v1_02)
|
| 371 |
// getNN renvoie le num_nom passé comme segment d'URI
|
405 |
// ou bien l'extrait du pattern bdtfx.nn:(#id)
|
| Line 372... |
Line 406... |
| 372 |
// ou bien l'extrait du pattern bdtfx.nn:(#id)
|
406 |
$ids_coste = array_filter(array_map(array(__CLASS__, 'getNNCoste'), explode(',', $uri[0])));
|
| 373 |
$ids = array_filter(array_map(array(__CLASS__, 'getNN'), explode(',', $uri[0])));
|
407 |
$ids_bdtfx = array_filter(array_map(array(__CLASS__, 'getNNBdtfx'), explode(',', $uri[0])));
|
| 374 |
|
408 |
|
| 375 |
// en cas d'échec (tous les id sont invalides), bail-out
|
409 |
// en cas d'échec (tous les id sont invalides), bail-out
|
| 376 |
if(!$ids) {
|
410 |
if(!$ids_bdtfx && !$ids_coste) {
|
| Line -... |
Line 411... |
| - |
|
411 |
// http_response_code(500);
|
| - |
|
412 |
throw new Exception('not supported', 500);
|
| 377 |
// http_response_code(500);
|
413 |
}
|
| - |
|
414 |
|
| 378 |
throw new Exception('not supported', 500);
|
415 |
return array(
|
| Line 379... |
Line 416... |
| 379 |
}
|
416 |
'coste' => array_slice($ids_coste, 0, intval(_COSTE_TEXTE_MAX_RESULT_LIMIT/2) ),
|
| 380 |
|
417 |
'bdtfx' => array_slice($ids_bdtfx, 0, intval(_COSTE_TEXTE_MAX_RESULT_LIMIT/2) )
|
| 381 |
return array_slice($ids, 0, _COSTE_TEXTE_MAX_RESULT_LIMIT);
|
418 |
);
|
| 382 |
}
|
419 |
}
|
| 383 |
|
420 |
|
| 384 |
static function aide() {
|
421 |
static function aide() {
|
| 385 |
header("Content-Type: text/plain; charset=utf-8");
|
- |
|
| - |
|
422 |
header("Content-Type: text/plain; charset=utf-8");
|
| 386 |
return sprintf("
|
423 |
return sprintf("
|
| 387 |
Service coste/textes:
|
424 |
Service coste/textes:
|
| 388 |
Retourne des informations (choisies) à propos d'un taxon donné (à partir de son numéro nomenclatural
|
425 |
Retourne des informations (choisies) à propos d'un taxon donné (à partir de son numéro nomenclatural
|
| 389 |
Retourne des informations (choisies) à propos de taxons recherchés (à partir de divers critères)
|
426 |
Retourne des informations (choisies) à propos de taxons recherchés (à partir de divers critères)
|
| - |
|
427 |
Les résultats sont indexés. La clef par défaut est le num_nom d'après coste (attribut \"coste:nn\")
|
| 390 |
|
428 |
Usage:
|
| 391 |
Usage:
|
429 |
coste/textes/<liste-num_nom>?<params>
|
| 392 |
coste/textes/<liste-num_nom>?<params>
|
430 |
* <liste-num_nom> étant une liste de numéros nomenclaturaux de taxons séparés par des virgules au format:
|
| 393 |
* <liste-num_nom> étant une liste de numéros nomenclaturaux de taxons bdtfx séparés par des virgules
|
431 |
- <#id>: un numéro nomenclatural dans la base coste
|
| 394 |
au format <#id> ou <bdtfx.nn:#id>
|
432 |
- <bdtfx.nn:#id>: un numéro nomenclatural dans la base bdtfx
|
| Line 402... |
Line 440... |
| 402 |
implode(',', self::$allow_params),
|
440 |
implode(',', self::$allow_params),
|
| 403 |
self::$default_params['retour.champs']
|
441 |
self::$default_params['retour.champs']
|
| 404 |
);
|
442 |
);
|
| 405 |
}
|
443 |
}
|
| Line 406... |
Line 444... |
| 406 |
|
444 |
|
| 407 |
static function getNN($refnn) {
|
445 |
static function getNNCoste($refnn) {
|
| 408 |
if(is_numeric($refnn)) {
|
446 |
if(is_numeric($refnn)) {
|
| 409 |
$t = intval($refnn);
|
447 |
$t = intval($refnn);
|
| 410 |
if($t >= 1 && $t < _COSTE_TEXTE_MAX_NUM_NOM) return $t;
|
- |
|
| 411 |
return FALSE;
|
448 |
if($t >= 1 && $t < _COSTE_TEXTE_MAX_COSTE_NN) return $t;
|
| - |
|
449 |
}
|
| - |
|
450 |
return FALSE;
|
| - |
|
451 |
}
|
| - |
|
452 |
|
| 412 |
}
|
453 |
static function getNNBdtfx($refnn) {
|
| 413 |
if(strpos($refnn, 'bdtfx.nn:') !== 0) return FALSE;
|
454 |
if(strpos($refnn, 'bdtfx.nn:') !== 0) return FALSE;
|
| - |
|
455 |
$t = intval(str_replace('bdtfx.nn:', '', $refnn));
|
| - |
|
456 |
if($t >= 1 && $t < _COSTE_TEXTE_MAX_BDTFX_NN) return $t;
|
| 414 |
return intval(str_replace('bdtfx.nn:', '', $refnn));
|
457 |
return FALSE;
|
| 415 |
}
|
458 |
}
|