true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 600, CURLOPT_HTTPHEADER => ['Accept: application/json'], CURLOPT_USERAGENT => 'ecoles-import/1.0', ]); $raw = curl_exec($ch); if ($raw === false) { $err = curl_error($ch); curl_close($ch); throw new RuntimeException('Téléchargement échoué : ' . $err); } $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($code !== 200) { throw new RuntimeException("Réponse HTTP $code de l'opendata."); } } else { $raw = @file_get_contents(OPENDATA_URL); if ($raw === false) { throw new RuntimeException('Téléchargement échoué (file_get_contents).'); } } $rows = json_decode($raw, true); unset($raw); if (!is_array($rows)) { throw new RuntimeException('Réponse opendata illisible.'); } // Transformation (clés courtes, géoloc obligatoire). $clean = []; $skipped = 0; foreach ($rows as $r) { $rec = map_opendata_row($r); if ($rec === null || empty($rec['id'])) { $skipped++; continue; } $clean[] = $rec; } unset($rows); $n = import_etablissements(db(), $clean); $total = (int) db()->query('SELECT COUNT(*) FROM etablissements')->fetchColumn(); json_out([ 'ok' => true, 'imported' => $n, 'skipped' => $skipped, 'total' => $total, ]); } catch (Throwable $e) { json_error('Import : ' . $e->getMessage(), 500); }