2022, 'P16_POP' => 2016, 'P11_POP' => 2011, 'P06_POP' => 2006, 'D99_POP' => 1999, 'D90_POP' => 1990, 'D82_POP' => 1982, 'D75_POP' => 1975, 'D68_POP' => 1968, ]; function say(string $m): void { echo $m . "\n"; flush(); } /** * Lit une entrée d'un fichier ZIP (méthodes « stored » et « deflate ») sans ext/zip. * Renvoie le contenu décompressé, ou null si absente. */ function zip_entry(string $path, string $name): ?string { $fh = fopen($path, 'rb'); if (!$fh) { return null; } $size = filesize($path); $look = min($size, 22 + 65536); fseek($fh, $size - $look); $buf = fread($fh, $look); $eo = strrpos($buf, "PK\x05\x06"); if ($eo === false) { fclose($fh); return null; } $eocd = unpack('Vsig/vdisk/vcddisk/ventries/vtotal/Vcdsize/Vcdoffset/vcomlen', substr($buf, $eo, 22)); fseek($fh, $eocd['cdoffset']); $cd = fread($fh, $eocd['cdsize']); $off = 0; $found = null; $n = strlen($cd); while ($off + 46 <= $n && substr($cd, $off, 4) === "PK\x01\x02") { $h = unpack('vver/vverneed/vflags/vmethod/vmtime/vmdate/Vcrc/Vcsize/Vusize/vnlen/velen/vclen/vdisk/viattr/Veattr/Vloffset', substr($cd, $off + 4, 42)); $fname = substr($cd, $off + 46, $h['nlen']); if ($fname === $name) { $found = $h; break; } $off += 46 + $h['nlen'] + $h['elen'] + $h['clen']; } if (!$found) { fclose($fh); return null; } fseek($fh, $found['loffset']); $lh = unpack('Vsig/vver/vflags/vmethod/vmtime/vmdate/Vcrc/Vcsize/Vusize/vnlen/velen', fread($fh, 30)); fseek($fh, $found['loffset'] + 30 + $lh['nlen'] + $lh['elen']); $comp = fread($fh, $found['csize']); fclose($fh); if ($found['method'] === 0) { return $comp; } if ($found['method'] === 8) { return gzinflate($comp); } return null; } try { $pdo = db(); $pdo->exec( 'CREATE TABLE IF NOT EXISTS pop_commune ( comc VARCHAR(5) NOT NULL, annee SMALLINT NOT NULL, pop INT NOT NULL DEFAULT 0, PRIMARY KEY (comc, annee), INDEX idx_comc (comc) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4' ); $zipPath = __DIR__ . '/data/insee/serie_hist.zip'; if (!is_file($zipPath)) { @mkdir(dirname($zipPath), 0777, true); say('… Téléchargement de la base INSEE (~6,7 Mo) …'); $fp = fopen($zipPath, 'w'); $ch = curl_init(INSEE_SERIE_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 || filesize($zipPath) < 100000) { @unlink($zipPath); throw new RuntimeException('Téléchargement échoué : ' . $err); } } say('… Lecture du CSV …'); $csv = zip_entry($zipPath, INSEE_CSV_NAME); if ($csv === null || $csv === '') { throw new RuntimeException('CSV introuvable dans le zip : ' . INSEE_CSV_NAME); } $lines = preg_split('/\r\n|\n|\r/', $csv); $header = str_getcsv(array_shift($lines), ';'); $header[0] = preg_replace('/^\xEF\xBB\xBF/', '', (string) $header[0]); // BOM $iCode = array_search('CODGEO', $header, true); if ($iCode === false) { throw new RuntimeException('Colonne CODGEO introuvable.'); } $colIdx = []; foreach (POP_COLS as $col => $annee) { $k = array_search($col, $header, true); if ($k !== false) { $colIdx[$k] = $annee; } } if (!$colIdx) { throw new RuntimeException('Aucune colonne de population trouvée.'); } $ins = $pdo->prepare('REPLACE INTO pop_commune (comc, annee, pop) VALUES (?, ?, ?)'); $pdo->exec('TRUNCATE TABLE pop_commune'); $pdo->beginTransaction(); $n = 0; foreach ($lines as $line) { if ($line === '') { continue; } $row = str_getcsv($line, ';'); $code = trim((string) ($row[$iCode] ?? '')); if (!preg_match('/^[0-9AB]\w{4}$/', $code)) { continue; } foreach ($colIdx as $k => $annee) { $v = $row[$k] ?? ''; if ($v === '' || !is_numeric(str_replace([' ', ','], ['', '.'], $v))) { continue; } $ins->execute([$code, $annee, (int) round((float) str_replace([' ', ','], ['', '.'], $v))]); if (++$n % 10000 === 0) { $pdo->commit(); $pdo->beginTransaction(); } } } $pdo->commit(); $communes = (int) $pdo->query('SELECT COUNT(DISTINCT comc) FROM pop_commune')->fetchColumn(); $arr = (int) $pdo->query("SELECT COUNT(DISTINCT comc) FROM pop_commune WHERE comc BETWEEN '13201' AND '13216' OR comc BETWEEN '69381' AND '69389' OR comc LIKE '751__'")->fetchColumn(); say("✔ pop_commune : $n lignes ($communes codes dont $arr arrondissements PLM, INSEE séries historiques 1968→2022)."); say('🎉 Terminé.'); } catch (Throwable $e) { if (isset($pdo) && $pdo->inTransaction()) { $pdo->rollBack(); } http_response_code(500); say('!! ERREUR : ' . $e->getMessage()); exit(1); }