'Unauthorised']); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; } // CSRF check if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) { http_response_code(403); echo json_encode(['error' => 'Invalid CSRF token']); exit; } // Whitelist of updatable columns — never allow id or modx_user_id $allowedColumns = ['n', 'p', 'k', 'Na', 'Ca', 'Mg', 'B', 'Zn', 'Cu', 'Mn', 'Fe', 'Co', 'Mo', 'name', 'chemical']; $column = $_POST['column'] ?? ''; $id = (int) ($_POST['id'] ?? 0); $editval = $_POST['editval'] ?? ''; if (!in_array($column, $allowedColumns, true)) { http_response_code(400); echo json_encode(['error' => 'Invalid column']); exit; } if ($id <= 0) { http_response_code(400); echo json_encode(['error' => 'Invalid record ID']); exit; } // Validate the value is numeric for nutrient columns $numericColumns = ['n', 'p', 'k', 'Na', 'Ca', 'Mg', 'B', 'Zn', 'Cu', 'Mn', 'Fe', 'Co', 'Mo']; if (in_array($column, $numericColumns, true) && $editval !== '' && !is_numeric($editval)) { http_response_code(400); echo json_encode(['error' => 'Value must be numeric']); exit; } // Verify the record belongs to the current user try { $pdo = getDBConnection(); $userId = getCurrentUserId(); $check = $pdo->prepare( 'SELECT id FROM fertiliser_specifications WHERE id = ? AND modx_user_id = ? LIMIT 1' ); $check->execute([$id, $userId]); if (!$check->fetch()) { http_response_code(403); echo json_encode(['error' => 'Record not found or access denied']); exit; } // Column name is from whitelist — safe to interpolate as identifier $stmt = $pdo->prepare("UPDATE fertiliser_specifications SET `{$column}` = ? WHERE id = ?"); $stmt->execute([$editval === '' ? null : $editval, $id]); echo json_encode(['success' => true]); } catch (PDOException $e) { error_log('updateproduct.php DB error: ' . $e->getMessage()); http_response_code(500); echo json_encode(['error' => 'Database error']); }