/** * Décrit un critère non déclaré explicitement * * Décrit un critère non déclaré comme {id_article} {id_article>3} en * retournant un tableau de l'analyse si la colonne (ou l'alias) existe vraiment. * * Ajoute au passage pour chaque colonne utilisée (alias et colonne véritable) * un modificateur['criteres'][colonne]. * * S'occupe de rechercher des exceptions, tel que * - les id_parent, id_enfant, id_secteur, * - des colonnes avec des exceptions déclarées, * - des critères de date (jour_relatif, ...), * - des critères sur tables jointes explicites (mots.titre), * - des critères sur tables de jointure non explicite (id_mot sur une boucle articles...) * * * @param string $idb Identifiant de la boucle * @param array $boucles AST du squelette * @param Critere $crit Paramètres du critère dans cette boucle * @return array|string * Liste si on trouve le champ : * - string $arg * Opérande avant l'opérateur : souvent la colonne d'application du critère, parfois un calcul * plus complexe dans le cas des dates. * - string $op * L'opérateur utilisé, tel que '=' * - string[] $val * Liste de codes PHP obtenant les valeurs des comparaisons (ex: id_article sur la boucle parente) * Souvent (toujours ?) un tableau d'un seul élément. * - $col_alias * - $where_complement * * Chaîne vide si on ne trouve pas le champ... **/ function calculer_critere_infixe($idb, &$boucles, $crit) { global $table_criteres_infixes; global $exceptions_des_jointures, $exceptions_des_tables; $boucle =& $boucles[$idb]; $type = $boucle->type_requete; $table = $boucle->id_table; $desc = $boucle->show; $col_vraie = null; list($fct, $col, $op, $val, $args_sql) = calculer_critere_infixe_ops($idb, $boucles, $crit); $col_alias = $col; $where_complement = false; // Cas particulier : id_enfant => utiliser la colonne id_objet if ($col == 'id_enfant') { $col = $boucle->primary; } // Cas particulier : id_parent => verifier les exceptions de tables if (in_array($col, array('id_parent', 'id_secteur')) and isset($exceptions_des_tables[$table][$col]) or isset($exceptions_des_tables[$table][$col]) and is_string($exceptions_des_tables[$table][$col])) { $col = $exceptions_des_tables[$table][$col]; } else { if ($col == 'id_secteur' and $critere_secteur = charger_fonction("critere_secteur_{$type}", "public", true)) { $table = $critere_secteur($idb, $boucles, $val, $crit); } else { if (!isset($exceptions_des_jointures[table_objet_sql($table)][$col]) and !isset($exceptions_des_jointures[$col]) and count(trouver_champs_decomposes($col, $desc)) > 1) { $e = decompose_champ_id_objet($col); $col = array_shift($e); $where_complement = primary_doublee($e, $table); } else { if ($c = calculer_critere_infixe_date($idb, $boucles, $col)) { list($col, $col_vraie) = $c; $table = ''; } else { if (preg_match('/^(.*)\\.(.*)$/', $col, $r)) { list(, $table, $col) = $r; $col_alias = $col; $trouver_table = charger_fonction('trouver_table', 'base'); if ($desc = $trouver_table($table, $boucle->sql_serveur) and isset($desc['field'][$col]) and $cle = array_search($desc['table'], $boucle->from)) { $table = $cle; } else { $table = trouver_jointure_champ($col, $boucle, array($table), $crit->cond or $op != '='); } #$table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op!='='), true); if (!$table) { return ''; } } elseif (@(!array_key_exists($col, $desc['field'])) and @(!array_key_exists('*', $desc['field']))) { $r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table); if (!$r) { return ''; } list($col, $col_alias, $table, $where_complement, $desc) = $r; } } } } } $col_vraie = $col_vraie ? $col_vraie : $col; // Dans tous les cas, // virer les guillemets eventuels autour d'un int (qui sont refuses par certains SQL) // et passer dans sql_quote avec le type si connu // et int sinon si la valeur est numerique // sinon introduire le vrai type du champ si connu dans le sql_quote (ou int NOT NULL sinon) // Ne pas utiliser intval, PHP tronquant les Bigint de SQL if ($op == '=' or in_array($op, $table_criteres_infixes)) { // defaire le quote des int et les passer dans sql_quote avec le bon type de champ si on le connait, int sinon // prendre en compte le debug ou la valeur arrive avec un commentaire PHP en debut if (preg_match(",^\\A(\\s*//.*?\$\\s*)?\"'(-?\\d+)'\"\\z,ms", $val[0], $r)) { $val[0] = $r[1] . '"' . sql_quote($r[2], $boucle->sql_serveur, isset($desc['field'][$col_vraie]) ? $desc['field'][$col_vraie] : 'int NOT NULL') . '"'; } elseif (preg_match('/\\Asql_quote[(](.*?)(,[^)]*?)?(,[^)]*(?:\\(\\d+\\)[^)]*)?)?[)]\\s*\\z/ms', $val[0], $r) and (!isset($r[3]) or !$r[3])) { $r = $r[1] . ((isset($r[2]) and $r[2]) ? $r[2] : ",''") . ",'" . (isset($desc['field'][$col_vraie]) ? addslashes($desc['field'][$col_vraie]) : 'int NOT NULL') . "'"; $val[0] = "sql_quote({$r})"; } } // Indicateur pour permettre aux fonctionx boucle_X de modifier // leurs requetes par defaut, notamment le champ statut // Ne pas confondre champs de la table principale et des jointures if ($table === $boucle->id_table) { $boucles[$idb]->modificateur['criteres'][$col_vraie] = true; if ($col_alias != $col_vraie) { $boucles[$idb]->modificateur['criteres'][$col_alias] = true; } } // ajout pour le cas special d'une condition sur le champ statut: // il faut alors interdire a la fonction de boucle // de mettre ses propres criteres de statut // http://www.spip.net/@statut (a documenter) // garde pour compatibilite avec code des plugins anterieurs, mais redondant avec la ligne precedente if ($col == 'statut') { $boucles[$idb]->statut = true; } // inserer le nom de la table SQL devant le nom du champ if ($table) { if ($col[0] == "`") { $arg = "{$table}." . substr($col, 1, -1); } else { $arg = "{$table}.{$col}"; } } else { $arg = $col; } // inserer la fonction SQL if ($fct) { $arg = "{$fct}({$arg}{$args_sql})"; } return array($arg, $op, $val, $col_alias, $where_complement); }
function calculer_critere_infixe($idb, &$boucles, $crit) { global $table_criteres_infixes; global $exceptions_des_jointures, $exceptions_des_tables; $boucle = &$boucles[$idb]; $type = $boucle->type_requete; $table = $boucle->id_table; $desc = $boucle->show; $date = array(); list($fct, $col, $op, $val, $args_sql) = calculer_critere_infixe_ops($idb, $boucles, $crit); $col_alias = $col; $where_complement =false; // Cas particulier : id_enfant => utiliser la colonne id_objet if ($col == 'id_enfant') $col = $boucle->primary; // Cas particulier : id_parent => verifier les exceptions de tables if ($col == 'id_parent') $col = isset($exceptions_des_tables[$table]['id_parent']) ? $exceptions_des_tables[$table]['id_parent'] : 'id_parent'; // Cas particulier : id_secteur pour certaines tables else if (($col == 'id_secteur')&&($type == 'breves')) { $col = 'id_rubrique'; } // et possibilite de gerer un critere secteur sur des tables de plugins (ie forums) else if (($col == 'id_secteur') AND ($critere_secteur = charger_fonction("critere_secteur_$type","public",true))) { $table = $critere_secteur($idb, $boucles, $val, $crit); } // cas id_article=xx qui se mappe en id_objet=xx AND objet=article else if (count(trouver_champs_decomposes($col,$desc))>1){ $e = decompose_champ_id_objet($col); $col = array_shift($e); $where_complement = primary_doublee($e, $table); } // Cas particulier : expressions de date else if ($date = tester_param_date($boucle->type_requete, $col)) { $col = calculer_critere_infixe_date($idb, $boucles, $date); $table = ''; } else if (preg_match('/^(.*)\.(.*)$/', $col, $r)) { list(,$table, $col) = $r; $col_alias = $col; $table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op !='='), true); if (!$table) return ''; } elseif (@!array_key_exists($col, $desc['field'])) { $r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table); if (!$r) return ''; list($col, $col_alias, $table, $where_complement) = $r; } // Si la colonne SQL est numerique ou le critere est une date relative // virer les guillemets eventuels qui sont refuses par certains SQL // Ne pas utiliser intval, PHP tronquant les Bigint de SQL if (($op == '=' OR in_array($op, $table_criteres_infixes)) AND (($desc AND isset($desc['field'][$col]) AND sql_test_int($desc['field'][$col])) OR ($date AND strpos($date[0], '_relatif')))) { if (preg_match("/^\"'(-?\d+)'\"$/", $val[0], $r)) $val[0] = $r[1]; elseif (preg_match('/^sql_quote[(](.*?)(,[^)]*)?[)]\s*$/', $val[0], $r)) { $r = $r[1] . ($r[2] ? $r[2] : ",''") . ",'int'"; $val[0] = "sql_quote($r)"; } } // Indicateur pour permettre aux fonctionx boucle_X de modifier // leurs requetes par defaut, notamment le champ statut // Ne pas confondre champs de la table principale et des jointures if ($table === $boucle->id_table) { $boucles[$idb]->modificateur['criteres'][$col] = true; if ($col_alias!=$col) $boucles[$idb]->modificateur['criteres'][$col_alias] = true; } // ajout pour le cas special d'une condition sur le champ statut: // il faut alors interdire a la fonction de boucle // de mettre ses propres criteres de statut // http://www.spip.net/@statut (a documenter) // garde pour compatibilite avec code des plugins anterieurs, mais redondant avec la ligne precedente if ($col == 'statut') $boucles[$idb]->statut = true; // ajout pour le cas special des forums // il faut alors interdire a la fonction de boucle sur forum // de selectionner uniquement les forums sans pere elseif ($boucles[$idb]->type_requete == 'forums' AND ($col == 'id_parent' OR $col == 'id_forum')) $boucles[$idb]->modificateur['plat'] = true; // inserer le nom de la table SQL devant le nom du champ if ($table) { if ($col[0] == "`") $arg = "$table." . substr($col,1,-1); else $arg = "$table.$col"; } else $arg = $col; // inserer la fonction SQL if ($fct) $arg = "$fct($arg$args_sql)"; return array($arg, $op, $val, $col_alias, $where_complement); }