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:
2026-06-03 21:35:41 +02:00
commit 5633969d98
40 changed files with 7242 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
<?php
/**
* Import des effectifs et nombres de classes des écoles (1er degré) — historique.
* Source : data.education.gouv.fr, dataset « fr-en-ecoles-effectifs-nb_classes ».
*
* Télécharge l'export CSV (champs réduits) puis remplit la table effectifs
* (uai, annee → élèves, classes). Clé = numéro d'école (UAI) + rentrée scolaire.
*
* Usage : php import_effectifs.php
*/
declare(strict_types=1);
require __DIR__ . '/api/db.php';
const EFFECTIFS_CSV =
'https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/'
. 'fr-en-ecoles-effectifs-nb_classes/exports/csv'
. '?select=rentree_scolaire,numero_ecole,nombre_total_eleves,nombre_total_classes&delimiter=%3B';
function say(string $m): void { echo $m . "\n"; flush(); }
try {
$pdo = db();
$pdo->exec(
'CREATE TABLE IF NOT EXISTS effectifs (
uai VARCHAR(12) NOT NULL,
annee SMALLINT NOT NULL,
eleves INT NOT NULL DEFAULT 0,
classes INT NOT NULL DEFAULT 0,
PRIMARY KEY (uai, annee),
INDEX idx_uai (uai)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
// Télécharge le CSV dans un fichier temporaire si absent localement.
$csv = __DIR__ . '/data/insee/effectifs.csv';
if (!is_file($csv)) {
@mkdir(dirname($csv), 0777, true);
say('… Téléchargement de lexport CSV …');
$fp = fopen($csv, 'w');
$ch = curl_init(EFFECTIFS_CSV);
curl_setopt_array($ch, [
CURLOPT_FILE => $fp, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 600,
CURLOPT_USERAGENT => 'ecoles-import/1.0',
]);
if (!curl_exec($ch)) {
throw new RuntimeException('Téléchargement échoué : ' . curl_error($ch));
}
curl_close($ch);
fclose($fp);
}
$fh = fopen($csv, 'r');
$header = fgetcsv($fh, 0, ';');
$header[0] = preg_replace('/^\xEF\xBB\xBF/', '', (string) $header[0]); // retire un éventuel BOM
$iY = array_search('rentree_scolaire', $header, true);
$iU = array_search('numero_ecole', $header, true);
$iE = array_search('nombre_total_eleves', $header, true);
$iC = array_search('nombre_total_classes', $header, true);
if (in_array(false, [$iY, $iU, $iE, $iC], true)) {
throw new RuntimeException('Colonnes attendues introuvables dans le CSV.');
}
$ins = $pdo->prepare('REPLACE INTO effectifs (uai, annee, eleves, classes) VALUES (?, ?, ?, ?)');
$pdo->beginTransaction();
$n = 0;
$num = static fn($v) => (int) round((float) str_replace(',', '.', (string) $v));
while (($row = fgetcsv($fh, 0, ';')) !== false) {
$uai = $row[$iU] ?? '';
$annee = (int) ($row[$iY] ?? 0);
if ($uai === '' || $annee === 0) {
continue;
}
$ins->execute([$uai, $annee, $num($row[$iE] ?? 0), $num($row[$iC] ?? 0)]);
if (++$n % 5000 === 0) {
$pdo->commit();
$pdo->beginTransaction();
if ($n % 100000 === 0) say("$n lignes");
}
}
$pdo->commit();
fclose($fh);
$ecoles = (int) $pdo->query('SELECT COUNT(DISTINCT uai) FROM effectifs')->fetchColumn();
say("✔ effectifs : $n lignes importées ($ecoles écoles).");
say('🎉 Terminé.');
} catch (Throwable $e) {
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
http_response_code(500);
say('!! ERREUR : ' . $e->getMessage());
exit(1);
}