getMessage()) ne sont plus affichees * a l'ecran : elles sont journalisees via error_log() et un message * generique est montre a l'administrateur. * * Note : le controle par role (require_admin_role) est volontairement * absent de cette version, la separation des privileges etant reportee * a une migration dediee (voir admin_auth.php). * * Version complète : * - coordonnées GPS avec step="any" ; * - ajout dynamique de nouvelles cellules ; * - héritage MCC/MNC depuis l'opérateur du site ; * - INSERT avec exactement 14 paramètres et NOW() pour validated_at. */ declare(strict_types=1); require_once __DIR__ . '/admin_auth.php'; require_once __DIR__ . '/../lib/db.php'; require_once __DIR__ . '/_nav.php'; require_admin_auth(); $db = pdo(); $user = current_admin_username(); $successMessage = null; $errorMessage = null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { require_csrf_token(); $action = $_POST['action'] ?? ''; if ($action === 'save_site') { $siteId = (int)($_POST['site_id'] ?? 0); $lat = (float)($_POST['lat'] ?? 0); $lon = (float)($_POST['lon'] ?? 0); $locationDesc = trim($_POST['location_desc'] ?? ''); $addressDesc = trim($_POST['address_desc'] ?? ''); $cellIds = $_POST['row_cell_pk'] ?? []; $techs = $_POST['cell_tech'] ?? []; $cellRadioIds = $_POST['cell_id'] ?? []; $areaCodes = $_POST['cell_area_code'] ?? []; $subIds = $_POST['cell_sub_id'] ?? []; $subIds2 = $_POST['cell_sub_id2'] ?? []; $bands = $_POST['cell_band'] ?? []; $frequencies = $_POST['cell_frequency'] ?? []; $azimuths = $_POST['cell_azimuth'] ?? []; $bandwidths = $_POST['cell_bandwidth'] ?? []; $arfcns = $_POST['cell_arfcn'] ?? []; $newTechs = $_POST['new_cell_tech'] ?? []; $newCellRadioIds = $_POST['new_cell_id'] ?? []; $newAreaCodes = $_POST['new_cell_area_code'] ?? []; $newSubIds = $_POST['new_cell_sub_id'] ?? []; $newSubIds2 = $_POST['new_cell_sub_id2'] ?? []; $newBands = $_POST['new_cell_band'] ?? []; $newFrequencies = $_POST['new_cell_frequency'] ?? []; $newAzimuths = $_POST['new_cell_azimuth'] ?? []; $newBandwidths = $_POST['new_cell_bandwidth'] ?? []; $newArfcns = $_POST['new_cell_arfcn'] ?? []; if (!$siteId || !$lat || !$lon) { $errorMessage = 'Coordonnees invalides.'; } else { $siteMccMncStmt = $db->prepare(' SELECT o.mcc, o.mnc FROM sites s JOIN operators o ON o.id = s.operator_id WHERE s.id = ? '); $siteMccMncStmt->execute([$siteId]); $siteMccMnc = $siteMccMncStmt->fetch(PDO::FETCH_ASSOC); if (!$siteMccMnc) { $errorMessage = 'Site introuvable, impossible de determiner le MCC/MNC.'; } else { $siteMcc = $siteMccMnc['mcc']; $siteMnc = $siteMccMnc['mnc']; $db->beginTransaction(); try { $db->prepare('UPDATE sites SET lat = ?, lon = ?, location_desc = ?, address_desc = ? WHERE id = ?') ->execute([$lat, $lon, $locationDesc, $addressDesc, $siteId]); $updateCell = $db->prepare(' UPDATE cells SET tech = ?, cell_id = ?, area_code = ?, sub_id = ?, sub_id2 = ?, band = ?, frequency = ?, azimuth = ?, bandwidth = ?, arfcn = ?, validated_by = ?, validated_at = NOW() WHERE id = ? AND site_id = ? '); foreach ($cellIds as $i => $cellPk) { $cellPk = (int)$cellPk; if (!$cellPk) { continue; } $updateCell->execute([ $techs[$i] ?? null, $cellRadioIds[$i] ?? null, $areaCodes[$i] ?? null, ($subIds[$i] ?? '') !== '' ? $subIds[$i] : null, ($subIds2[$i] ?? '') !== '' ? $subIds2[$i] : null, ($bands[$i] ?? '') !== '' ? $bands[$i] : null, ($frequencies[$i] ?? '') !== '' ? $frequencies[$i] : null, ($azimuths[$i] ?? '') !== '' ? (int)$azimuths[$i] : null, ($bandwidths[$i] ?? '') !== '' ? $bandwidths[$i] : null, ($arfcns[$i] ?? '') !== '' ? $arfcns[$i] : null, $user, $cellPk, $siteId, ]); } // 14 marqueurs (?) et 14 valeurs dans execute(). // validated_at est fourni par NOW(), donc aucune valeur // supplémentaire ne doit être ajoutée dans execute(). $insertCell = $db->prepare(' INSERT INTO cells ( site_id, mcc, mnc, tech, cell_id, area_code, sub_id, sub_id2, band, frequency, azimuth, bandwidth, arfcn, validated_by, validated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW()) '); foreach ($newTechs as $i => $newTech) { $newCellIdVal = trim((string)($newCellRadioIds[$i] ?? '')); $newAreaCodeVal = trim((string)($newAreaCodes[$i] ?? '')); // Ignore une ligne ajoutée mais non remplie. if ($newCellIdVal === '' || $newAreaCodeVal === '') { continue; } $insertCell->execute([ $siteId, $siteMcc, $siteMnc, $newTech, $newCellIdVal, $newAreaCodeVal, ($newSubIds[$i] ?? '') !== '' ? $newSubIds[$i] : null, ($newSubIds2[$i] ?? '') !== '' ? $newSubIds2[$i] : null, ($newBands[$i] ?? '') !== '' ? $newBands[$i] : null, ($newFrequencies[$i] ?? '') !== '' ? $newFrequencies[$i] : null, ($newAzimuths[$i] ?? '') !== '' ? (int)$newAzimuths[$i] : null, ($newBandwidths[$i] ?? '') !== '' ? $newBandwidths[$i] : null, ($newArfcns[$i] ?? '') !== '' ? $newArfcns[$i] : null, $user, ]); } $db->commit(); $successMessage = 'Site mis a jour.'; } catch (Throwable $e) { if ($db->inTransaction()) { $db->rollBack(); } error_log('[edit_site] save_site: ' . $e->getMessage()); $errorMessage = "Une erreur est survenue lors de l'enregistrement. Consultez les journaux du serveur."; } } } } if ($action === 'delete_cell') { $cellId = (int)($_POST['cell_id_pk'] ?? 0); $siteId = (int)($_POST['site_id'] ?? 0); $countStmt = $db->prepare('SELECT COUNT(*) FROM cells WHERE site_id = ?'); $countStmt->execute([$siteId]); $remaining = (int)$countStmt->fetchColumn(); if ($remaining <= 1) { $errorMessage = "Impossible de retirer la derniere cellule d'un site : supprimez plutot le site entier."; } else { try { $db->prepare('DELETE FROM cells WHERE id = ? AND site_id = ?')->execute([$cellId, $siteId]); $successMessage = 'Cellule retiree du site.'; } catch (Throwable $e) { error_log('[edit_site] delete_cell: ' . $e->getMessage()); $errorMessage = 'Une erreur est survenue lors de la suppression.'; } } } if ($action === 'delete_site') { $siteId = (int)($_POST['site_id'] ?? 0); try { $db->prepare('DELETE FROM sites WHERE id = ?')->execute([$siteId]); header('Location: edit_site.php?deleted=1'); exit; } catch (Throwable $e) { error_log('[edit_site] delete_site: ' . $e->getMessage()); $errorMessage = 'Une erreur est survenue lors de la suppression du site.'; } } } $editingSiteId = isset($_GET['site_id']) ? (int)$_GET['site_id'] : null; $editingSite = null; $editingCells = []; if ($editingSiteId) { $siteStmt = $db->prepare(' SELECT s.*, o.brand AS operator_brand, o.mcc, o.mnc, c.name AS country_name, c.default_lat, c.default_lon, c.default_zoom, c.cadastre_wms_url, c.cadastre_wms_layer, c.cadastre_attribution_html FROM sites s JOIN operators o ON o.id = s.operator_id JOIN countries c ON c.id = s.country_id WHERE s.id = ? '); $siteStmt->execute([$editingSiteId]); $editingSite = $siteStmt->fetch(PDO::FETCH_ASSOC); if ($editingSite) { $cellsStmt = $db->prepare('SELECT * FROM cells WHERE site_id = ? ORDER BY tech, cell_id'); $cellsStmt->execute([$editingSiteId]); $editingCells = $cellsStmt->fetchAll(PDO::FETCH_ASSOC); } } $mapLat = null; $mapLon = null; $coordsInvalid = false; if ($editingSite) { $siteLat = (float)$editingSite['lat']; $siteLon = (float)$editingSite['lon']; if ($siteLat === 0.0 && $siteLon === 0.0) { $coordsInvalid = true; $mapLat = (float)($editingSite['default_lat'] ?? 20); $mapLon = (float)($editingSite['default_lon'] ?? 0); } else { $mapLat = $siteLat; $mapLon = $siteLon; } } $searchQuery = trim($_GET['q'] ?? ''); $countryFilter = $_GET['country'] ?? ''; $operatorFilter = $_GET['operator'] ?? ''; $sites = []; if (!$editingSiteId) { $sql = ' SELECT s.id, s.lat, s.lon, s.location_desc, s.address_desc, o.brand AS operator_brand, c.name AS country_name, GROUP_CONCAT(DISTINCT cl.tech ORDER BY cl.tech SEPARATOR ", ") AS techs, COUNT(cl.id) AS cell_count FROM sites s JOIN operators o ON o.id = s.operator_id JOIN countries c ON c.id = s.country_id LEFT JOIN cells cl ON cl.site_id = s.id WHERE 1=1 '; $params = []; if ($searchQuery !== '') { $sql .= ' AND (s.location_desc LIKE ? OR s.address_desc LIKE ? OR cl.cell_id LIKE ? OR cl.sub_id2 LIKE ?)'; $like = '%' . $searchQuery . '%'; array_push($params, $like, $like, $like, $like); } if ($countryFilter !== '') { $sql .= ' AND c.iso2 = ?'; $params[] = $countryFilter; } if ($operatorFilter !== '') { $sql .= ' AND o.id = ?'; $params[] = $operatorFilter; } $sql .= ' GROUP BY s.id ORDER BY s.created_at DESC LIMIT 200'; $stmt = $db->prepare($sql); $stmt->execute($params); $sites = $stmt->fetchAll(PDO::FETCH_ASSOC); } $countries = $db->query('SELECT id, iso2, name FROM countries ORDER BY name')->fetchAll(PDO::FETCH_ASSOC); $operators = $db->query('SELECT id, mcc, mnc, brand FROM operators ORDER BY brand')->fetchAll(PDO::FETCH_ASSOC); $deletedNotice = isset($_GET['deleted']); ?> NetMonster Admin - Edition de site

Edition d'un site valide

Recherchez un site pour corriger ses coordonnees, sa description, ou les parametres radio de ses cellules.

Site supprime avec succes.

OperateurPaysTechnosCellulesLieuLat/Lon
,
Aucun site trouve.

Edition du site —

← Retour a la liste

Attention : les coordonnees enregistrees pour ce site sont a 0,0 (invalides). La carte est centree sur le pays par defaut ; corrigez la position ci-dessous.

Localisation

Cellules du site ()

TechnoCell IDArea codeSub IDeNB/RNCBandeFrequenceAzimutLargeurARFCN

Zone sensible

La suppression du site retire aussi TOUTES ses cellules de la base validee (irreversible).

Site introuvable.

← Retour a la liste