function filtrage_company_to_csv(string $clientId, string $compname, string $ctyregist, $outHandle): int { // Paramètres globaux existants global $badwords; global $match_threshold; global $weighting_coef; // Compteur de matches retournés $nbmatch = 0; // Nettoyage du nom de société côté client $cname = trim($compname, " \n\r\t\v\0,.;!"); if ($cname === '') { return 0; // rien à filtrer } $cnam = mb_convert_case($cname, MB_CASE_UPPER, "UTF-8"); $cnam = stripAccents($cnam); $cnam = str_replace("-", " ", $cnam); $cnam_ori = $cnam; // Construction de la liste de mots significatifs du nom $tabmots = []; $words = explode(" ", $cnam); foreach ($words as $w) { $w = trim($w); if ($w === '') { continue; } if (in_array($w, $badwords, true)) { continue; // mot insignifiant } if (is_numeric($w)) { continue; // ignore les numéros } $tabmots[] = $w; } if (empty($tabmots)) { // Aucun mot significatif -> rien à faire return 0; } // Tri décroissant par longueur / ordre (comme dans ton code) rsort($tabmots); // On garde aussi une version "string" du nom nettoyé côté client $cnam_client = implode(" ", $tabmots); $nbmots = 0; // Construction des préfixes pour la requête LIKE $tabpremc = []; foreach ($tabmots as $mot) { $len = mb_strlen($mot, 'UTF-8'); if ($len > 3) { $nbmots++; $premcar = mb_substr($mot, 0, 3, 'UTF-8') . '%'; $tabpremc[] = $premcar; } elseif ($len === 3) { $nbmots++; $tabpremc[] = $mot . '%'; } else { // len < 3 $nbmots++; $tabpremc[] = $mot . '%'; } } // Connexion à la base hidlo_companies_list une seule fois (optimisation avec static) static $bdd = null; if ($bdd === null) { try { $bdd = new PDO( 'mysql:host=vps-2ee7d3b0.vps.ovh.net;port=3307;dbname=hidlo_companies_list;charset=utf8', 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); } catch (Exception $e) { // On log plutôt que de die() pour ne pas casser tout le flux error_log('Erreur connexion DB filtrage_company_to_csv : ' . $e->getMessage()); return 0; } } $rechetendue = 'N'; // comme dans ton code, mode standard // Construction de la requête SQL switch ($rechetendue) { default: if ($ctyregist === '') { // Pas de filtre pays, on utilise les préfixes dans c_name // On limite à 5 préfixes comme dans ton code $conditions = []; $max = min(count($tabpremc), 5); for ($i = 0; $i < $max; $i++) { $conditions[] = 'UPPER(cn_compname) LIKE ' . $bdd->quote($tabpremc[$i]); } if (empty($conditions)) { return 0; } $sql = 'SELECT cn_reflistid, cn_datentlist, cn_compname, cn_suffix, cn_typname, cn_oriname FROM c_name WHERE ' . implode(' OR ', $conditions); } else { // Filtrage par pays avec jointure sur c_country // (on utilise le 1er préfixe le plus significatif) $prefix = isset($tabpremc[1]) ? $tabpremc[1] : $tabpremc[0]; $sql = 'SELECT cn_reflistid, cn_datentlist, cn_compname, cn_suffix, cn_typname, cn_oriname, cc_ctycode FROM c_name JOIN c_country ON cc_reflistid = cn_reflistid WHERE UPPER(cn_compname) LIKE ' . $bdd->quote($prefix) . ' AND cc_ctycode = ' . $bdd->quote($ctyregist); } break; case 'Y': // Mode "recherche étendue" (non utilisé dans ton code courant) if ($ctyregist === '') { $sql = 'SELECT cn_reflistid, cn_datentlist, cn_compname, cn_suffix, cn_typname, cn_oriname FROM c_name'; } else { $sql = 'SELECT cn_reflistid, cn_datentlist, cn_compname, cn_suffix, cn_typname, cn_oriname, cc_ctycode FROM c_name JOIN c_country ON cc_reflistid = cn_reflistid WHERE cc_ctycode = ' . $bdd->quote($ctyregist); } break; } try { $det = $bdd->query($sql); } catch (Exception $e) { error_log('Erreur requête filtrage_company_to_csv : ' . $e->getMessage()); return 0; } // Parcours des enregistrements trouvés while ($data = $det->fetch(PDO::FETCH_ASSOC)) { $listId = $data['cn_reflistid']; $entrydate = $data['cn_datentlist'] ?? ''; $complist = $data['cn_compname']; $suffix = $data['cn_suffix']; $typname = $data['cn_typname']; $oriname = $data['cn_oriname']; // Si ctyregist est vide, on met "" dans le CSV ; sinon le code pays client $cty = $ctyregist !== '' ? $ctyregist : ''; // Décodage du code liste -> nom lisible $listori = substr($listId, 0, 2); if ($listori == "80") $listname = "HATVP"; elseif ($listori == "85") $listname = "HMT"; elseif ($listori == "86") $listname = "SECO"; elseif ($listori == "87") $listname = "ANF"; elseif ($listori == "88") $listname = "RNE"; elseif ($listori == "89") $listname = "RNG"; elseif ($listori == "99") $listname = "ONU"; elseif ($listori == "98") $listname = "SDN"; elseif ($listori == "97") $listname = "EU"; else $listname = "UNKNOWN"; // Distance finale $dist1 = 0.0; // 1) Cas d’égalité exact avec le nom d’origine dans la liste if ($compname === $oriname) { $dist1 = 1.0; } else { // 2) Cas général : comparaison multi-mots avec Jaro-Winkler // Nettoyage du nom dans la liste $search1 = trim($complist, " \n\r\t\v\0,.;!"); $search1 = mb_convert_case($search1, MB_CASE_UPPER, "UTF-8"); $search1 = stripAccents($search1); $search1 = str_replace("-", " ", $search1); // Découpage en mots significatifs $tabwords = []; foreach (explode(" ", $search1) as $mot) { $mot = trim($mot); if ($mot === '') { continue; } if (in_array($mot, $badwords, true)) { continue; } if (is_numeric($mot)) { continue; } $tabwords[] = $mot; } if (empty($tabwords)) { // aucun mot significatif côté liste -> on ignore continue; } rsort($tabwords); // même approche que côté client $distance = []; $tmatch = []; // Si même nombre de mots -> comparaison globale if (count($tabwords) === $nbmots) { $search_join = implode(" ", $tabwords); $dist1 = (float) number_format(JaroWinkler($search_join, $cnam_client), 2, '.', ''); if ($dist1 >= $match_threshold) { $distance[] = $dist1; $tmatch[] = $cnam_client; } } else { // Nombres de mots différents -> comparaison mot à mot if (count($tabwords) > $nbmots) { // plus de mots côté liste for ($y = 0; $y < $nbmots; $y++) { $cnam_word = $tabmots[$y]; for ($x = 0; $x < count($tabwords); $x++) { $search_word = $tabwords[$x]; $d = (float) number_format(JaroWinkler($search_word, $cnam_word), 2, '.', ''); if ($d >= $match_threshold && !in_array($cnam_word, $tmatch, true)) { $distance[] = $d; $tmatch[] = $cnam_word; } } } } else { // plus de mots côté client ou égal mais traité ici for ($y = 0; $y < count($tabwords); $y++) { $cnam_word = $tabwords[$y]; for ($x = 0; $x < $nbmots; $x++) { $search_word = $tabmots[$x]; $d = (float) number_format(JaroWinkler($search_word, $cnam_word), 2, '.', ''); if ($d >= $match_threshold && !in_array($search_word, $tmatch, true)) { $distance[] = $d; $tmatch[] = $search_word; } } } } // Calcul de la distance moyenne + pondération "mots non trouvés" if (!empty($distance)) { $sum = 0.0; foreach ($distance as $d) { $sum += $d; } $dist1 = $sum / count($distance); if (count($tabwords) > $nbmots) { $nontrouv = count($tabwords) - count($distance); $coef = (count($tabwords) - $nontrouv) / count($tabwords); } else { $nontrouv = $nbmots - count($distance); $coef = ($nbmots - $nontrouv) / $nbmots; } $ponderation = $nontrouv * $weighting_coef; $dist1 = $dist1 - $ponderation; if ($coef <= 0.5) { $dist1 = $dist1 - $coef; } } } } // Si la distance finale est au-dessus du seuil -> on écrit l’alerte if ($dist1 >= $match_threshold) { $nbmatch++; $idalert = md5($compname.$listId.$complist.$suffix); $datalert = date("Y-m-d"); $typcli = "C"; $statut = "PENDING"; $comment = ""; $blanc = ""; $active = 1; $deceased = 0; $doblist = "0000-00-00"; $dobcli = "0000-00-00"; $datqualif = "0000-00-00"; $typalert = "S"; // Sanction // 🔹 valeurs manquantes initialisées $idcomp = $clientId; $refnumber = ''; $interpol = ''; $reload = 'N'; fputcsv($outHandle, [ $idalert, // idalert $datalert, // datalert $typcli, // typentite $listori, // codelist $listId, // listid $entrydate, // datentlist $complist, // nomlist $suffix, // prenomlist $typname, // typnomlist $blanc, // listrole $doblist, // doblist $blanc, //sexlist $active, // active $deceased, // deceased $cty, // cnat $blanc, // cbirth $blanc, // cres $idcomp, // cliid $compname, // nomcli $blanc, // prenomcli $dobcli, // dobcli $blanc, // sexcli $statut, // statut $datqualif, // datqualif $comment, // comment $blanc, // gestionnaire $blanc, // image number_format($dist1, 2, '.', ''), // distance $refnumber, // refnumber $interpol, // interpol $reload, // reload $typalert // typalert ], ';'); } } // while fetch return $nbmatch; }