Version initiale — carte des établissements scolaires
Carte Leaflet (annuaire Éducation nationale) + API PHP/MySQL : fiche établissement (effectifs, IPS, population INSEE, DPE ADEME), GED documents/photos, commentaires par groupe, gestion utilisateurs et politique de mots de passe. Imports opendata (effectifs, IPS, population, DPE, IRIS). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+161
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
/**
|
||||
* Import de l'IPS (indice de position sociale) des établissements — historique.
|
||||
* Source : data.education.gouv.fr. Trois datasets remplis dans la même table « ips » :
|
||||
* - écoles : « fr-en-ips-ecoles-ap2022 » (ips + ips_departemental ; rentrées 2022→2024)
|
||||
* - collèges : « fr-en-ips-colleges-ap2022 » (ips ; rentrée 2022-2023)
|
||||
* - lycées : « fr-en-ips-lycees-ap2022 » (ips_ensemble_gt_pro, repli ips_voie_gt)
|
||||
*
|
||||
* Clé = UAI + rentrée scolaire (année de début, ex. « 2022-2023 » → 2022).
|
||||
* ips_dep (IPS moyen départemental de référence) n'existe que pour les écoles.
|
||||
*
|
||||
* Usage : php import_ips.php (les trois niveaux)
|
||||
* php import_ips.php --niveau=colleges (un seul : ecoles|colleges|lycees)
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
require __DIR__ . '/api/db.php';
|
||||
|
||||
function say(string $m): void { echo $m . "\n"; flush(); }
|
||||
|
||||
// Datasets et mapping des colonnes (le nom de la colonne IPS varie selon le niveau).
|
||||
const IPS_DATASETS = [
|
||||
'ecoles' => [
|
||||
'ds' => 'fr-en-ips-ecoles-ap2022',
|
||||
'select' => 'rentree_scolaire,uai,ips,ips_departemental',
|
||||
'ips' => ['ips'],
|
||||
'dep' => 'ips_departemental',
|
||||
'file' => 'ips_ecoles.csv',
|
||||
],
|
||||
'colleges' => [
|
||||
'ds' => 'fr-en-ips-colleges-ap2022',
|
||||
'select' => 'rentree_scolaire,uai,ips',
|
||||
'ips' => ['ips'],
|
||||
'dep' => null,
|
||||
'file' => 'ips_colleges.csv',
|
||||
],
|
||||
'lycees' => [
|
||||
'ds' => 'fr-en-ips-lycees-ap2022',
|
||||
'select' => 'rentree_scolaire,uai,ips_ensemble_gt_pro,ips_voie_gt',
|
||||
'ips' => ['ips_ensemble_gt_pro', 'ips_voie_gt'], // ensemble, sinon voie GT
|
||||
'dep' => null,
|
||||
'file' => 'ips_lycees.csv',
|
||||
],
|
||||
];
|
||||
|
||||
/** Télécharge l'export CSV d'un dataset vers $path s'il est absent. */
|
||||
function ips_download(string $ds, string $select, string $path): void
|
||||
{
|
||||
if (is_file($path)) {
|
||||
return;
|
||||
}
|
||||
@mkdir(dirname($path), 0777, true);
|
||||
$url = 'https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/'
|
||||
. $ds . '/exports/csv?select=' . rawurlencode($select) . '&delimiter=%3B';
|
||||
say("… Téléchargement de $ds …");
|
||||
$fp = fopen($path, 'w');
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_FILE => $fp, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 600,
|
||||
CURLOPT_USERAGENT => 'ecoles-import/1.0',
|
||||
]);
|
||||
$ok = curl_exec($ch);
|
||||
$err = curl_error($ch);
|
||||
curl_close($ch);
|
||||
fclose($fp);
|
||||
if (!$ok) {
|
||||
@unlink($path);
|
||||
throw new RuntimeException("Téléchargement échoué ($ds) : $err");
|
||||
}
|
||||
}
|
||||
|
||||
/** Importe un dataset IPS dans la table « ips ». Renvoie le nombre de lignes. */
|
||||
function ips_import_one(PDO $pdo, array $cfg): int
|
||||
{
|
||||
$path = __DIR__ . '/data/insee/' . $cfg['file'];
|
||||
ips_download($cfg['ds'], $cfg['select'], $path);
|
||||
|
||||
$fh = fopen($path, 'r');
|
||||
$header = fgetcsv($fh, 0, ';');
|
||||
$header[0] = preg_replace('/^\xEF\xBB\xBF/', '', (string) $header[0]); // retire un éventuel BOM
|
||||
$idx = static fn(string $name) => array_search($name, $header, true);
|
||||
$iY = $idx('rentree_scolaire');
|
||||
$iU = $idx('uai');
|
||||
$ipsCols = array_values(array_filter(array_map($idx, $cfg['ips']), static fn($v) => $v !== false));
|
||||
$iD = $cfg['dep'] !== null ? $idx($cfg['dep']) : false;
|
||||
if ($iY === false || $iU === false || !$ipsCols) {
|
||||
fclose($fh);
|
||||
throw new RuntimeException("Colonnes attendues introuvables dans {$cfg['file']}.");
|
||||
}
|
||||
|
||||
$ins = $pdo->prepare('REPLACE INTO ips (uai, annee, ips, ips_dep) VALUES (?, ?, ?, ?)');
|
||||
$dec = static fn($v) => ($v === null || $v === '') ? null : (float) str_replace(',', '.', (string) $v);
|
||||
|
||||
$pdo->beginTransaction();
|
||||
$n = 0;
|
||||
while (($row = fgetcsv($fh, 0, ';')) !== false) {
|
||||
$uai = $row[$iU] ?? '';
|
||||
$annee = (int) ($row[$iY] ?? 0);
|
||||
// Première colonne IPS non vide (ensemble, sinon repli).
|
||||
$ips = null;
|
||||
foreach ($ipsCols as $c) {
|
||||
$ips = $dec($row[$c] ?? null);
|
||||
if ($ips !== null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($uai === '' || $annee === 0 || $ips === null) {
|
||||
continue;
|
||||
}
|
||||
$ins->execute([$uai, $annee, $ips, $iD !== false ? $dec($row[$iD] ?? null) : null]);
|
||||
if (++$n % 5000 === 0) {
|
||||
$pdo->commit();
|
||||
$pdo->beginTransaction();
|
||||
}
|
||||
}
|
||||
$pdo->commit();
|
||||
fclose($fh);
|
||||
return $n;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->exec(
|
||||
'CREATE TABLE IF NOT EXISTS ips (
|
||||
uai VARCHAR(12) NOT NULL,
|
||||
annee SMALLINT NOT NULL,
|
||||
ips DECIMAL(5,1) NOT NULL,
|
||||
ips_dep DECIMAL(5,1) NULL,
|
||||
PRIMARY KEY (uai, annee),
|
||||
INDEX idx_uai (uai)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
|
||||
);
|
||||
|
||||
// Filtre éventuel sur un niveau.
|
||||
$only = null;
|
||||
foreach ($argv ?? [] as $a) {
|
||||
if (preg_match('/^--niveau=(ecoles|colleges|lycees)$/', $a, $m)) {
|
||||
$only = $m[1];
|
||||
}
|
||||
}
|
||||
|
||||
$total = 0;
|
||||
foreach (IPS_DATASETS as $niveau => $cfg) {
|
||||
if ($only !== null && $only !== $niveau) {
|
||||
continue;
|
||||
}
|
||||
$n = ips_import_one($pdo, $cfg);
|
||||
say("✔ $niveau : $n lignes importées.");
|
||||
$total += $n;
|
||||
}
|
||||
|
||||
$ecoles = (int) $pdo->query('SELECT COUNT(DISTINCT uai) FROM ips')->fetchColumn();
|
||||
say("✔ ips : $total lignes au total ($ecoles établissements distincts).");
|
||||
say('🎉 Terminé.');
|
||||
} catch (Throwable $e) {
|
||||
if (isset($pdo) && $pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
http_response_code(500);
|
||||
say('!! ERREUR : ' . $e->getMessage());
|
||||
exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user