X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=modules%2Fsearch%2Fclasses.inc.php;h=5f01c97c35af1a32778618594e82bd3f62429511;hb=993e0a863c5bcd5847520f817c0d88dff6fb1958;hp=db3c46624c6a515812980604916c363f7878f452;hpb=a7de4ef724d1a3b0bf978a50ce7cc9d23412c7a0;p=platal.git diff --git a/modules/search/classes.inc.php b/modules/search/classes.inc.php index db3c466..5f01c97 100644 --- a/modules/search/classes.inc.php +++ b/modules/search/classes.inc.php @@ -1,6 +1,6 @@ search->result_fields = ' - u.user_id, u.promo, u.matricule, u.matricule_ax, - if(u.nom_usage=\'\', u.nom, u.nom_usage) AS NomSortKey, - u.nom_usage,u.date, - u.deces!=0 AS dcd,u.deces, - u.perms IN (\'admin\',\'user\', \'disabled\') AS inscrit, - u.perms != \'pending\' AS wasinscrit, - FIND_IN_SET(\'femme\', u.flags) AS sexe, - a.alias AS forlife, - ad0.text AS app0text, ad0.url AS app0url, ai0.type AS app0type, - ad1.text AS app1text, ad1.url AS app1url, ai1.type AS app1type, - es.label AS secteur, ef.fonction_fr AS fonction, - IF(n.nat=\'\',n.pays,n.nat) AS nat, n.a2 AS iso3166, - COUNT(em.email) > 0 AS actif,'; +@$globals->search->result_fields = ' + u.user_id, u.promo, u.matricule, u.matricule_ax, + if(u.nom_usage=\'\', u.nom, u.nom_usage) AS NomSortKey, + u.nom_usage,u.date, + u.deces!=0 AS dcd,u.deces, + u.perms IN (\'admin\',\'user\', \'disabled\') AS inscrit, + u.perms != \'pending\' AS wasinscrit, + FIND_IN_SET(\'femme\', u.flags) AS sexe, + a.alias AS forlife, + ad0.text AS app0text, ad0.url AS app0url, ai0.type AS app0type, + ad1.text AS app1text, ad1.url AS app1url, ai1.type AS app1type, + es.label AS secteur, ef.fonction_fr AS fonction, + IF(n.nat=\'\',n.pays,n.nat) AS nat, n.a2 AS iso3166, + (COUNT(em.email) > 0 OR FIND_IN_SET("googleapps", u.mail_storage) > 0) AS actif,'; // hide private information if not logged -if (S::logged()) - $globals->search->result_fields .=' - q.profile_web AS web, - q.profile_mobile AS mobile, - q.profile_freetext AS freetext, - adr.city, gp.pays AS countrytxt, gr.name AS region, - e.entreprise,'; +if (S::logged()) + $globals->search->result_fields .=' + q.profile_web AS web, + q.profile_mobile AS mobile, + q.profile_freetext AS freetext, + adr.city, gp.pays AS countrytxt, gr.name AS region, + e.entreprise,'; else - $globals->search->result_fields .=" - IF(q.profile_web_pub='public', q.profile_web, '') AS web, - IF(q.profile_mobile_pub='public', q.profile_mobile, '') AS mobile, - IF(q.profile_freetext_pub='public', q.profile_freetext, '') AS freetext, - IF(adr.pub='public', adr.city, '') AS city, - IF(adr.pub='public', gp.pays, '') AS countrytxt, - IF(adr.pub='public', gr.name, '') AS region, - IF(e.pub='public', e.entreprise, '') AS entreprise,"; -$globals->search->result_where_statement = ' - LEFT JOIN applis_ins AS ai0 ON (u.user_id = ai0.uid AND ai0.ordre = 0) - LEFT JOIN applis_def AS ad0 ON (ad0.id = ai0.aid) - LEFT JOIN applis_ins AS ai1 ON (u.user_id = ai1.uid AND ai1.ordre = 1) - LEFT JOIN applis_def AS ad1 ON (ad1.id = ai1.aid) - LEFT JOIN entreprises AS e ON (e.entrid = 0 AND e.uid = u.user_id) - LEFT JOIN emploi_secteur AS es ON (e.secteur = es.id) - LEFT JOIN fonctions_def AS ef ON (e.fonction = ef.id) - LEFT JOIN geoloc_pays AS n ON (u.nationalite = n.a2) - LEFT JOIN adresses AS adr ON (u.user_id = adr.uid AND FIND_IN_SET(\'active\',adr.statut)) - LEFT JOIN geoloc_pays AS gp ON (adr.country = gp.a2) - LEFT JOIN geoloc_region AS gr ON (adr.country = gr.a2 AND adr.region = gr.region) - LEFT JOIN emails AS em ON (em.uid = u.user_id AND em.flags = \'active\')'; - -// }}} -// {{{ function display_lines() - -/** - * This function is a heuristic that approximatively tells - * how many lines of output the contact list will use. - */ -function display_lines($text) -{ - $n = 0; - $tokens = Array('', '
'); - foreach ($tokens as $t) { - $i = -1; - while ( ($i = strpos($text,$t,$i+1))!==false) { $n++; } - } - return $n; -} + $globals->search->result_fields .=" + IF(q.profile_web_pub='public', q.profile_web, '') AS web, + IF(q.profile_mobile_pub='public', q.profile_mobile, '') AS mobile, + IF(q.profile_freetext_pub='public', q.profile_freetext, '') AS freetext, + IF(adr.pub='public', adr.city, '') AS city, + IF(adr.pub='public', gp.pays, '') AS countrytxt, + IF(adr.pub='public', gr.name, '') AS region, + IF(e.pub='public', e.entreprise, '') AS entreprise,"; +@$globals->search->result_where_statement = ' + LEFT JOIN applis_ins AS ai0 ON (u.user_id = ai0.uid AND ai0.ordre = 0) + LEFT JOIN applis_def AS ad0 ON (ad0.id = ai0.aid) + LEFT JOIN applis_ins AS ai1 ON (u.user_id = ai1.uid AND ai1.ordre = 1) + LEFT JOIN applis_def AS ad1 ON (ad1.id = ai1.aid) + LEFT JOIN entreprises AS e ON (e.entrid = 0 AND e.uid = u.user_id) + LEFT JOIN emploi_secteur AS es ON (e.secteur = es.id) + LEFT JOIN fonctions_def AS ef ON (e.fonction = ef.id) + LEFT JOIN geoloc_pays AS n ON (u.nationalite = n.a2) + LEFT JOIN adresses AS adr ON (u.user_id = adr.uid AND FIND_IN_SET(\'active\',adr.statut)) + LEFT JOIN geoloc_pays AS gp ON (adr.country = gp.a2) + LEFT JOIN geoloc_region AS gr ON (adr.country = gr.a2 AND adr.region = gr.region) + LEFT JOIN emails AS em ON (em.uid = u.user_id AND em.flags = \'active\')'; // }}} // {{{ class ThrowError @@ -96,13 +76,26 @@ function display_lines($text) */ class ThrowError { + public static $throwHook = array('ThrowError', 'defaultHandler'); + /** constuctor * @param $explain string the error (in natural language) */ - function ThrowError($explain) + public function __construct($explain) { - global $page; - $page->trig('Erreur : '.$explain); + call_user_func(ThrowError::$throwHook, $explain); + } + + /** defaut error handler + */ + private static function defaultHandler($explain) + { + global $globals; + $page =& Platal::page(); + $page->changeTpl('search/index.tpl'); + $page->setTitle('Polytechnique.org - Annuaire'); + $page->assign('baseurl', $globals->baseurl); + $page->trigError($explain); $page->run(); } } @@ -117,7 +110,7 @@ class ThrowError class SField { // {{{ properties - + /** le nom du champ dans le formulaire HTML */ var $fieldFormName; /** champs de la bdd correspondant à ce champ sous forme d'un tableau */ @@ -144,7 +137,7 @@ class SField // }}} // {{{ function get_request() - /** récupérer la requête de l'utilisateur + /** récupérer la requête de l'utilisateur * on met une chaîne vide si le champ n'a pas été complété */ function get_request() { @@ -153,9 +146,9 @@ class SField // }}} // {{{ function get_where_statement() - + /** récupérer la clause correspondant au champ dans la clause WHERE de la requête - * on parcourt l'ensemble des champs de la bdd de $fieldDbName et on associe + * on parcourt l'ensemble des champs de la bdd de $fieldDbName et on associe * à chacun d'entre eux une clause spécifique * la clause totale et la disjonction de ces clauses spécifiques */ function get_where_statement() @@ -169,7 +162,7 @@ class SField // }}} // {{{ function get_order_statement() - + /** récupérer la clause correspondant au champ dans la clause ORDER BY de la requête * utilisé par exemple pour placer d'abord le nom égal à la requête avant les approximations */ function get_order_statement() @@ -208,20 +201,23 @@ class SField class QuickSearch extends SField { // {{{ properties - + /** stores tokens */ var $strings; /** stores numerical ranges */ var $ranges; + /** stores admin searches */ + var $email; + var $ip; // }}} // {{{ constructor - + function QuickSearch($_fieldFormName) { $this->fieldFormName = $_fieldFormName; $this->get_request(); - if (preg_match(":[\]\[{}~/§_`|%$^=+]|\*\*:", $this->value)) { + if (preg_match(":[\]\[{}~/§_`|%$^=+]|\*\*:u", $this->value)) { new ThrowError('Un champ contient un caractère interdit rendant la recherche impossible.'); } } @@ -231,62 +227,91 @@ class QuickSearch extends SField function isempty() { - return empty($this->strings) && empty($this->ranges); + return empty($this->strings) && empty($this->ranges) && empty($this->email) && empty($this->ip); } // }}} // {{{ function get_request() - + function get_request() { - parent::get_request(); - $s = replace_accent(trim($this->value)); - $s = preg_replace('!\d+!', ' ', $s); - $s = str_replace('*','%',$s); - $this->strings = preg_split("![^a-zA-Z%]+!",$s, -1, PREG_SPLIT_NO_EMPTY); + parent::get_request(); + $s = replace_accent(trim($this->value)); + $r = $s = str_replace('*','%',$s); + + if (S::has_perms() && strpos($s, '@') !== false) { + $this->email = $s; + } else if (S::has_perms() && preg_match('/[0-9]+\.([0-9]+|%)\.([0-9]+|%)\.([0-9]+|%)/', $s)) { + $this->ip = $s; + } + if ($this->email || $this->ip) { + $this->strings = $this->ranges = array(); + return; + } + + $s = preg_replace('!\d+!', ' ', $s); + $this->strings = preg_split("![^a-zA-Z%]+!",$s, -1, PREG_SPLIT_NO_EMPTY); + if (count($this->strings) > 5) { + Platal::page()->trigWarning("Tu as indiqué trop d'éléments dans ta recherche, seuls les 5 premiers seront pris en compte"); + $this->strings = array_slice($this->strings, 0, 5); + } - $s = trim($this->value); - $s = preg_replace('! *- *!', '-', $s); - $s = preg_replace('!([<>]) *!', ' \1', $s); - $s = preg_replace('![^0-9\-><]!', ' ', $s); - $s = preg_replace('![<>\-] !', '', $s); - $ranges = preg_split('! +!', $s, -1, PREG_SPLIT_NO_EMPTY); - $this->ranges=Array(); - foreach ($ranges as $r) { - if (preg_match('!^([<>]\d{4}|\d{4}(-\d{4})?)$!', $r)) $this->ranges[] = $r; - } + $s = preg_replace('! *- *!', '-', $r); + $s = preg_replace('!([<>]) *!', ' \1', $s); + $s = preg_replace('![^0-9\-><]!', ' ', $s); + $s = preg_replace('![<>\-] !', '', $s); + $ranges = preg_split('! +!', $s, -1, PREG_SPLIT_NO_EMPTY); + $this->ranges=Array(); + foreach ($ranges as $r) { + if (preg_match('!^([<>]\d{4}|\d{4}(-\d{4})?)$!', $r)) $this->ranges[] = $r; + } } // }}} // {{{ function get_where_statement() - + function get_where_statement() { - $where = Array(); - foreach ($this->strings as $i => $s) { - $t = str_replace('*', '%', $s).'%'; - $t = str_replace('%%', '%', $t); - $where[] = "sn$i.token LIKE '$t'"; - } - - $wherep = Array(); - foreach ($this->ranges as $r) { - if (preg_match('!^\d{4}$!', $r)) { - $wherep[] = "u.promo=$r"; - } elseif (preg_match('!^(\d{4})-(\d{4})$!', $r, $matches)) { - $p1=min(intval($matches[1]), intval($matches[2])); - $p2=max(intval($matches[1]), intval($matches[2])); - $wherep[] = "(u.promo>=$p1 AND u.promo<=$p2)"; - } elseif (preg_match('!^<(\d{4})!', $r, $matches)) { - $wherep[] = "u.promo<={$matches[1]}"; - } elseif (preg_match('!^>(\d{4})!', $r, $matches)) { - $wherep[] = "u.promo>={$matches[1]}"; - } - } - if (!empty($wherep)) { + $where = Array(); + foreach ($this->strings as $i => $s) { + if (Env::i('with_soundex') && strlen($s) > 1) { + $t = soundex_fr($s); + $where[] = "sn$i.soundex = '$t'"; + } elseif (Env::i('exact')) { + $where[] = "sn$i.token = '$s'"; + } else { + $t = str_replace('*', '%', $s).'%'; + $t = str_replace('%%', '%', $t); + $where[] = "sn$i.token LIKE '$t'"; + } + } + + $wherep = Array(); + foreach ($this->ranges as $r) { + if (preg_match('!^\d{4}$!', $r)) { + $wherep[] = "u.promo=$r"; + } elseif (preg_match('!^(\d{4})-(\d{4})$!', $r, $matches)) { + $p1=min(intval($matches[1]), intval($matches[2])); + $p2=max(intval($matches[1]), intval($matches[2])); + $wherep[] = "(u.promo>=$p1 AND u.promo<=$p2)"; + } elseif (preg_match('!^<(\d{4})!', $r, $matches)) { + $wherep[] = "u.promo<={$matches[1]}"; + } elseif (preg_match('!^>(\d{4})!', $r, $matches)) { + $wherep[] = "u.promo>={$matches[1]}"; + } + } + if (!empty($wherep)) { $where[] = '('.join(' OR ',$wherep).')'; } - return join(" AND ", $where); + if (!empty($this->email)) { + $where[] = 'ems.email = ' . XDB::escape($this->email); + } + if (!empty($this->ip)) { + $ip = ip_to_uint($this->ip); + $where[] = "( ls.ip = $ip OR ls.forward_ip = $ip ) AND ls.suid = 0"; + } + + return join(" AND ", $where); } // }}} @@ -294,14 +319,27 @@ class QuickSearch extends SField function get_select_statement() { $join = ""; - foreach ($this->strings as $i => $s) { - $join .= "INNER JOIN search_name AS sn$i ON (u.user_id = sn$i.uid)\n"; + $and = ''; + $uniq = ''; + foreach ($this->strings as $i => $s) { + if (!S::logged()) { + $and = "AND FIND_IN_SET('public', sn$i.flags)"; + } + $myu = str_replace('snv', "sn$i", $uniq); + $join .= "INNER JOIN search_name AS sn$i ON (u.user_id = sn$i.uid $and$myu)\n"; + $uniq .= " AND sn$i.token != snv.token"; + } + if (!empty($this->email)) { + $join .= "LEFT JOIN emails AS ems ON (ems.uid = u.user_id)"; + } + if (!empty($this->ip)) { + $join .= "INNER JOIN logger.sessions AS ls ON (ls.uid = u.user_id)\n"; } return $join; } // }}} // {{{ function get_order_statement() - + function get_order_statement() { return false; @@ -309,11 +347,11 @@ class QuickSearch extends SField // }}} // {{{ function get_score_statement - + function get_score_statement() { $sum = array('0'); - foreach ($this->strings as $i => $s) { + foreach ($this->strings as $i => $s) { $sum[] .= "SUM(sn$i.score + IF('$s'=sn$i.token,5,0))"; } return join('+', $sum).' AS score'; @@ -330,7 +368,7 @@ class QuickSearch extends SField class NumericSField extends SField { // {{{ constructor - + /** constructeur * (récupère la requête de l'utilisateur pour ce champ) */ function NumericSField($_fieldFormName) @@ -341,7 +379,7 @@ class NumericSField extends SField // }}} // {{{ function get_request() - + /** récupère la requête de l'utilisateur et échoue s'il ne s'agit pas d'un entier */ function get_request() { @@ -353,7 +391,7 @@ class NumericSField extends SField new ThrowError('Un champ numérique contient des caractères alphanumériques.'); } } - + // }}} } @@ -363,7 +401,7 @@ class NumericSField extends SField class RefSField extends SField { // {{{ properties - + var $refTable; var $refAlias; var $refCondition; @@ -385,7 +423,7 @@ class RefSField extends SField // }}} // {{{ function get_request() - + function get_request() { parent::get_request(); if ($this->value=='00' || $this->value=='0') { @@ -407,6 +445,7 @@ class RefSField extends SField function compare() { $val = addslashes($this->value); + if (Env::i('exact')) return "='$val'"; return $this->exact ? "='$val'" : " LIKE '%$val%'"; } @@ -435,7 +474,16 @@ class RefSField extends SField return false; } $res = implode(' OR ', array_filter(array_map(array($this, 'get_single_match_statement'), $this->fieldDbName))); - return "INNER JOIN {$this->refTable} AS {$this->refAlias} ON ({$this->refCondition} AND ($res) )"; + if (is_array($this->refTable)) { + foreach ($this->refTable as $i => $refT) + $last = $i; + $inner = ""; + foreach ($this->refTable as $i => $refT) + $inner .= " INNER JOIN {$refT} AS {$this->refAlias[$i]} ON ({$this->refCondition[$i]} ".(($i == $last)?"AND ($res) ":"").")\n"; + return $inner; + } else { + return "INNER JOIN {$this->refTable} AS {$this->refAlias} ON ({$this->refCondition} AND ($res) )"; + } } // }}} @@ -446,16 +494,18 @@ class RefSField extends SField // {{{ class RefSFieldMultipleTable class MapSField extends RefSField { - var $mapId; - + var $mapId; + function MapSField($_fieldFormName, $_fieldDbName='', $_refTable, $_refAlias, $_refCondition, $_mapId=false) { if ($_mapId === false) $this->mapId = Env::v($_fieldFormName, ''); else $this->mapId = $_mapId; + $this->value = $this->mapId; $this->RefSField($_fieldFormName, $_fieldDbName, $_refTable, $_refAlias, $_refCondition, true, false); } + function get_select_statement() { if ($this->mapId === '') return false; @@ -478,10 +528,10 @@ class MapSField extends RefSField class RefWithSoundexSField extends RefSField { // {{{ function compare() - + function compare() { - return "='".soundex_fr($this->value)."'"; + return "='".soundex_fr($this->value)."'"; } // }}} @@ -495,13 +545,13 @@ class RefWithSoundexSField extends RefSField class StringSField extends SField { // {{{ function get_request() - + /** récupère la requête de l'utilisateur et échoue si la chaîne contient des caractères * interdits */ function get_request() { parent::get_request(); - if (preg_match(":[\]\[<>{}~/§_`|%$^=+]|\*\*:", $this->value)) { + if (preg_match(":[\]\[<>{}~/§_`|%$^=+]|\*\*:u", $this->value)) { new ThrowError('Un champ contient un caractère interdit rendant la recherche impossible.'); } } @@ -514,8 +564,9 @@ class StringSField extends SField * imposées par l'utilisateur) */ function length() { - global $lc_accent,$uc_accent; - return strlen($this->value) - strlen(ereg_replace('[a-z'.$lc_accent.$uc_accent.']', '', strtolower($this->value))); + $cleaned = replace_accent(strtolower($this->value)); + $length = strlen(ereg_replace('[a-z0-9]', '', $cleaned)); + return strlen($this->value) - $length; } // }}} @@ -533,7 +584,9 @@ class StringSField extends SField * @param field nom de champ de la bdd concerné par la clause */ function get_single_where_statement($field) { - $regexp = strtr(addslashes($this->value), '-*', '_%'); + $val = addslashes($this->value); + if (Env::i('exact')) return "$field = '$val'"; + $regexp = strtr($val, '-*', '_%'); return "$field LIKE '$regexp%'"; } @@ -561,16 +614,18 @@ class StringSField extends SField class NameSField extends StringSField { // {{{ function get_single_where_statement() - + function get_single_where_statement($field) { - $regexp = strtr(addslashes($this->value), '-*', '_%'); + $val = addslashes($this->value); + if (Env::i('exact')) return "$field = '$val'"; + $regexp = strtr($val, '-*', '_%'); return "$field LIKE '$regexp%' OR $field LIKE '% $regexp%' OR $field LIKE '%-$regexp%'"; } // }}} // {{{ function get_order_statement() - + function get_order_statement() { if ($this->value!='' && $this->fieldResultName!='') { @@ -608,14 +663,14 @@ class StringWithSoundexSField extends StringSField class PromoSField extends SField { // {{{ properties - + /** opérateur de comparaison (<,>,=) de la promo utilisé pour ce champ de formulaire */ var $compareField; // }}} // {{{ constructor - /** constructeur + /** constructeur * compareField est un champ de formulaire très simple qui ne sert qu'à la construction de la * clause WHERE de la promo */ function PromoSField($_fieldFormName, $_compareFieldFormName, $_fieldDbName, $_fieldResultName) @@ -691,7 +746,7 @@ class PromoSField extends SField class SFieldGroup { // {{{ properties - + /** tableau des classes correspondant aux champs groupés */ var $fields; /** type de groupe : ET ou OU */ @@ -705,6 +760,11 @@ class SFieldGroup { $this->fields = $_fields; $this->and = $_and; + foreach ($this->fields as $key=>&$field) { + if (is_null($field)) { + unset($this->fields[$key]); + } + } } // }}} @@ -713,8 +773,10 @@ class SFieldGroup function too_large() { $b = true; - for ($i=0; $b && $ifields); $i++) { - $b &= $this->fields[$i]->too_large(); + for ($i=0 ; $b && $ifields) ; $i++) { + if (!is_null($this->fields[$i])) { + $b = $b && $this->fields[$i]->too_large(); + } } return $b; } @@ -753,7 +815,7 @@ class SFieldGroup { return $f->get_url(); } - + // }}} // {{{ function get_select_statement()