"Invalid or unauthorized file path for JSON: $fileName"]; } if (!file_exists($filePath) || !is_readable($filePath)) { // Provide simulation data for key_metrics.json if not found if ($fileName === 'key_metrics.json') { error_log("JSON Handler: File '$fileName' not found, providing simulation."); return [ // Structure expected by displayDataAsCards in script.js ['title' => 'Total Revenue', 'value' => '$'.number_format(rand(50000, 200000)), 'icon' => 'attach_money', 'description' => 'This month'], ['title' => 'New Customers', 'value' => rand(50, 200), 'icon' => 'person_add', 'description' => 'This week'], ['title' => 'Page Views', 'value' => number_format(rand(10000, 50000)), 'icon' => 'visibility', 'description' => 'Past 7 days'], ['title' => 'Bounce Rate', 'value' => rand(20, 60).'%', 'icon' => 'trending_down', 'description' => 'Session average'], ['title' => 'Load Time', 'value' => rand(100, 500).'ms', 'icon' => 'speed', 'description' => 'Average response'] ]; } error_log("JSON Handler Error: File not found or not readable: $filePath"); return ['error' => "JSON file not found or not readable: $fileName"]; } // Read and decode JSON file $jsonContent = file_get_contents($filePath); if ($jsonContent === false) { error_log("JSON Handler Error: Could not read file: $filePath"); return ['error' => "Could not read JSON file: $fileName"]; } $data = json_decode($jsonContent, true); if (json_last_error() !== JSON_ERROR_NONE) { error_log("JSON Handler Error: Invalid JSON format in file: $filePath - ".json_last_error_msg()); return ['error' => "Invalid JSON format in file: $fileName - ".json_last_error_msg()]; } // Validate and format data based on the file type if ($fileName === 'key_metrics.json') { // Ensure proper format for dashboard cards if (!is_array($data)) { return ['error' => "Key metrics JSON must contain an array of metric objects"]; } $formattedData = []; foreach ($data as $item) { if (!is_array($item) || !isset($item['title']) || !isset($item['value'])) { error_log("JSON Handler Warning: Skipping invalid metric item in $fileName"); continue; } $formattedItem = [ 'title' => (string) $item['title'], 'value' => (string) $item['value'], 'icon' => $item['icon'] ?? 'info', 'description' => $item['description'] ?? '' ]; $formattedData[] = $formattedItem; } return $formattedData; } // For chart data or config files, return as-is after basic validation if (in_array($fileName, ['chart_data.json', 'dashboard_config.json', 'config.json'])) { // Basic structure validation can be added here if needed return $data; } // For generic JSON files that might be used for tables if (is_array($data) && !empty($data) && is_array($data[0])) { return [ 'columns' => array_keys($data[0]), 'rows' => $data ]; } return $data; // Return decoded data } /** * Validates JSON file content against expected structure * * @param array $data The decoded JSON data * @param string $fileName The filename to determine validation rules * @return bool True if valid, false otherwise */ function validateJsonStructure(array $data, string $fileName): bool { switch ($fileName) { case 'key_metrics.json': if (!is_array($data)) { return false; } foreach ($data as $item) { if (!is_array($item) || !isset($item['title']) || !isset($item['value'])) { return false; } } return true; case 'chart_data.json': // Basic validation for chart data return is_array($data) && (isset($data['labels']) || isset($data['datasets']) || isset($data['data'])); case 'dashboard_config.json': case 'config.json': // Configuration files should be objects/arrays return is_array($data); default: return true; // Allow other JSON structures } }