<?php
// php/csv_handler.php
/**
* Reads data from a CSV file (simulated for key_metrics.csv).
*
* @param string $fileName The name of the CSV file to read (e.g., 'key_metrics.csv').
* @return array|null The CSV data formatted for the dashboard, or null/error array on failure.
*/
function readCsvFile(string $fileName): ?array
{
error_log("CSV Handler: Called for file '$fileName'");
$baseDataPath = __DIR__.'/../data/'; // Assumes 'data' folder is one level up from 'php'
$filePath = realpath($baseDataPath.$fileName);
// Security check: Ensure the resolved path is within the intended data directory
// And that the filename is one of the allowed ones (expanded whitelist)
$allowedFiles = [
'key_metrics.csv',
'sample_data.csv',
'sales_data.csv',
'user_analytics.csv',
'financial_report.csv'
];
if (!$filePath || strpos($filePath, realpath($baseDataPath)) !== 0 || !in_array(basename($filePath), $allowedFiles)) {
error_log("CSV Handler Error: Invalid, unauthorized or non-existent file path requested: $fileName");
return ['error' => "Invalid or unauthorized file path for CSV: $fileName"];
}
if (!file_exists($filePath) || !is_readable($filePath)) {
// Simulate data if actual file not found but is 'key_metrics.csv' for demo purposes
if ($fileName === 'key_metrics.csv') {
error_log("CSV Handler: File '$fileName' not found, providing simulation.");
return [
// Structure expected by displayDataAsCards in script.js
['title' => 'Total Orders', 'value' => rand(100, 500), 'icon' => 'shopping_cart', 'description' => 'Past 30 days'],
['title' => 'Active Users', 'value' => rand(1000, 5000), 'icon' => 'people_alt', 'description' => 'Currently online'],
['title' => 'Conversion Rate', 'value' => rand(1, 15).'%', 'icon' => 'ads_click', 'description' => 'Lead to purchase'],
['title' => 'Support Tickets', 'value' => rand(5, 50), 'icon' => 'support_agent', 'description' => 'Open tickets'],
['title' => 'Server Uptime', 'value' => '99.'.rand(90, 99).'%', 'icon' => 'dns', 'description' => 'Past 24 hours']
];
}
error_log("CSV Handler Error: File not found or not readable: $filePath");
return ['error' => "CSV file not found or not readable: $fileName"];
}
// Actual CSV parsing if file exists
$data = [];
$header = null;
if (($handle = fopen($filePath, 'r')) !== false) {
if (($row = fgetcsv($handle)) !== false) {
$header = array_map('trim', $row); // Trim header names
}
while (($row = fgetcsv($handle)) !== false) {
if ($header && count($header) == count($row)) {
$data[] = array_combine($header, $row);
} else {
// If no header or mismatched column count, store as simple array (or error out)
// For this dashboard, we generally expect headers.
error_log("CSV Handler: Row with mismatched column count or no header for file $fileName.");
// $data[] = $row; // uncomment if you want to allow non-headered or mismatched data
}
}
fclose($handle);
} else {
error_log("CSV Handler Error: Could not open file: $filePath");
return ['error' => "Could not open CSV file: $fileName"];
}
// If the file is key_metrics.csv, ensure it has title and value for cards.
// The data_provider.php will typically handle this transformation based on the 'source' type.
// This is more of a validation/defaulting step within the handler itself.
if ($fileName === 'key_metrics.csv') {
$formattedData = [];
foreach ($data as $item) {
$formattedItem = [
'title' => $item['title'] ?? 'N/A',
'value' => $item['value'] ?? 'N/A',
'icon' => $item['icon'] ?? null, // Optional
'description' => $item['description'] ?? null // Optional
];
$formattedData[] = $formattedItem;
}
return $formattedData;
}
// For generic CSVs that might be used for tables
if (!empty($data) && is_array($data[0])) {
return [
'columns' => array_keys($data[0]),
'rows' => $data
];
}
return $data; // Return raw parsed data or empty if issues
}; // Example of how you might call this (not used by data_provider.php directly like this); /*
if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
header('Content-Type: application/json');
$testFile = $_GET['file'] ?? 'key_metrics.csv';
$simulatedData = readCsvFile($testFile);
if (isset($simulatedData['error'])) {
http_response_code(400); // Or 404 if file not found
}
echo json_encode($simulatedData);
}