415 lines
15 KiB
PHP
Executable File
415 lines
15 KiB
PHP
Executable File
<?php
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
use PhpOffice\PhpSpreadsheet\Reader\Exception as SpreadsheetReaderException;
|
|
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
|
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
|
use PhpOffice\PhpSpreadsheet\Style\Color;
|
|
use PhpOffice\PhpSpreadsheet\Style\Font;
|
|
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
|
use PhpOffice\PhpSpreadsheet\Style\Border;
|
|
use PhpOffice\PhpSpreadsheet\Style\Borders;
|
|
|
|
|
|
if (!function_exists('generate_excel')) {
|
|
|
|
function generate_excel($headlines, $xldata)
|
|
{
|
|
|
|
$headersMain = $headlines['header1'];
|
|
$headersSub = $headlines['header2'];
|
|
$company = $headlines['company_name'];
|
|
$filename = $headlines['file_name'];
|
|
$type = $headlines['type'];
|
|
$footer = false;
|
|
$mergeEndCol = $headlines['merge_end_column'];
|
|
// $type = 1 means $data is single
|
|
// $type = 2 means $data is multiple array
|
|
|
|
|
|
// Create new Spreadsheet object
|
|
$spreadsheet = new Spreadsheet();
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
|
|
// Set worksheet title
|
|
$sheet->setTitle('Sheet 1');
|
|
|
|
|
|
// A1 Start here... should be compnay name ....
|
|
$sheet->setCellValue('A1', $company);
|
|
|
|
// Get last column letter based on headers count
|
|
// $lastColumnLetter = getExcelColumnName(count($headers) - 1);
|
|
$colCount = count($headersMain);
|
|
|
|
// Calculate end column by character math (works up to 'ZZ')
|
|
$lastColumnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($colCount);
|
|
|
|
$sheet->mergeCells("A1:{$lastColumnLetter}1");
|
|
|
|
// Style A1
|
|
$sheet->getStyle("A1")->getFill()
|
|
->setFillType(Fill::FILL_SOLID)
|
|
->getStartColor()->setRGB('ADD8E6'); // Light blue
|
|
|
|
$sheet->getStyle("A1")->getAlignment()
|
|
->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER)
|
|
->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER);
|
|
|
|
$sheet->getStyle("A1")->getFont()->setBold(true)->setSize(14);
|
|
|
|
$sheet->getStyle("A1")->getFont()
|
|
->getColor()
|
|
->setRGB(Color::COLOR_WHITE);
|
|
|
|
// /. A1 ends here
|
|
$currentRow = 2; // Start at row 2
|
|
if($type == 1){
|
|
$startCell = 'A' . $currentRow;
|
|
$lastcolrow = callHeader($sheet, $headersMain, $startCell,$headersSub);
|
|
$lastcolrow2 = callSkipRow($lastcolrow);
|
|
$lastcolrow3 = callData($sheet,$headersMain,$xldata,$lastcolrow2,$mergeEndCol);
|
|
$lastcolrow4 = callSkipRow($lastcolrow3);
|
|
if($footer){
|
|
$lastcolrow5 = callFooter($sheet, $headersMain, $xldata, $lastcolrow4,'','',$mergeEndCol);
|
|
}
|
|
|
|
|
|
}else if($type == 2){
|
|
// $final_Footer=[];
|
|
// foreach($xldata as $i => $xl){
|
|
// echo $i;
|
|
// echo "<pre>";
|
|
// print_r($xl[$i]);
|
|
// echo "</pre>";
|
|
// // echo count($xl[$i])."**";
|
|
// // $forFinalFooter
|
|
// }
|
|
// foreach ($xldata as $i => $xl) {
|
|
// $forFinalFooter[] = $xl[$i];
|
|
// }
|
|
$final_Footer = isset($headlines['final_Footer']) && !empty($headlines['final_Footer']) ? $headlines['final_Footer'] : [];
|
|
|
|
foreach ($xldata as $index => $data) {
|
|
if (!empty($data)) {
|
|
$startCell = 'A' . $currentRow;
|
|
|
|
$lastcolrow = callHeader($sheet, $headersMain, $startCell,$headersSub);
|
|
$lastcolrow2 = callSkipRow($lastcolrow);
|
|
$lastcolrow3 = callData($sheet, $headersMain, $data, $lastcolrow2);
|
|
$lastcolrow4 = callSkipRow($lastcolrow3);
|
|
$lastcolrow5 = callFooter($sheet, $headersMain, $data, $lastcolrow4,'Total Amount Rs','228B22',$mergeEndCol);
|
|
$lastcolrow6 = callSkipRow($lastcolrow5);
|
|
|
|
// Update currentRow for next iteration
|
|
$currentRow = (int) filter_var($lastcolrow6, FILTER_SANITIZE_NUMBER_INT);
|
|
} else {
|
|
$startCell = 'A' . $currentRow;
|
|
$lastcolrow = callHeader($sheet, $headersMain, $startCell,$headersSub);
|
|
$lastcolrow2 = callSkipRow($lastcolrow);
|
|
|
|
$currentRow = (int) filter_var($lastcolrow2, FILTER_SANITIZE_NUMBER_INT);
|
|
}
|
|
}
|
|
|
|
if(!empty($final_Footer)){
|
|
$startCell = 'A' . $currentRow;
|
|
callFooter($sheet, $headersMain, $final_Footer[0], $startCell,'Final Net Salary Amount Rs','DC143C',$mergeEndCol);
|
|
// echo "cr".$currentRow;die;
|
|
}
|
|
|
|
// $final_Footer
|
|
|
|
}
|
|
|
|
// Create Excel writer
|
|
$writer = new Xlsx($spreadsheet);
|
|
$columnCount = count($headersMain);
|
|
for ($col = 1; $col <= $columnCount; $col++) {
|
|
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
|
$sheet->getColumnDimension($columnLetter)->setAutoSize(true);
|
|
}
|
|
|
|
$highestColumn = $sheet->getHighestColumn(); // e.g., 'E'
|
|
$highestRow = $sheet->getHighestRow(); // e.g., 10
|
|
|
|
// Build the full range (e.g., 'A1:E10')
|
|
$range = 'A1:' . $highestColumn . $highestRow;
|
|
|
|
// Apply border to that range
|
|
$sheet->getStyle($range)->applyFromArray([
|
|
'borders' => [
|
|
'allBorders' => [
|
|
'borderStyle' => Border::BORDER_THIN,
|
|
'color' => ['argb' => 'FF000000'],
|
|
],
|
|
],
|
|
]);
|
|
|
|
try {
|
|
|
|
// Save Excel file to the specified path
|
|
ob_clean();
|
|
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
|
header('Cache-Control: max-age=0');
|
|
|
|
$writer->save('php://output'); // stream to browser
|
|
exit; // Return true if file was successfully saved
|
|
|
|
} catch (\Exception $e) {
|
|
// Log or handle the exception
|
|
return false; // Return false if there was an error saving the file
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function callHeader($sheet, $headersMain, $startCell, $headersSub = []) {
|
|
$rowNumber = (int) filter_var($startCell, FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$startCol = 'A';
|
|
$colCount = count($headersMain);
|
|
|
|
// Calculate end column by character math (works up to 'ZZ')
|
|
$endCol = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($colCount);
|
|
|
|
// Check if sub-header has any non-empty value
|
|
$hasSubHeader = !empty(array_filter($headersSub, function ($val) {
|
|
return trim($val) !== '';
|
|
}));
|
|
|
|
// 1. Write Main Header
|
|
$sheet->fromArray([$headersMain], null, $startCell);
|
|
$mainHeaderRange = "{$startCol}{$rowNumber}:{$endCol}{$rowNumber}";
|
|
|
|
// Style Main Header
|
|
$sheet->getStyle($mainHeaderRange)->applyFromArray([
|
|
'font' => [
|
|
'bold' => true,
|
|
'color' => ['rgb' => 'FF0000'],
|
|
'size' => 12,
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
|
|
]
|
|
]);
|
|
|
|
if ($hasSubHeader) {
|
|
// 2. Write Sub Header
|
|
$subHeaderRow = $rowNumber + 1;
|
|
$sheet->fromArray([$headersSub], null, "A{$subHeaderRow}");
|
|
|
|
$subHeaderRange = "{$startCol}{$subHeaderRow}:{$endCol}{$subHeaderRow}";
|
|
|
|
|
|
$sheet->getStyle($subHeaderRange)->applyFromArray([
|
|
'font' => [
|
|
'bold' => true,
|
|
'color' => ['rgb' => 'FF0000'],
|
|
'size' => 12,
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
|
|
]
|
|
]);
|
|
|
|
return 'A' . ($subHeaderRow + 1);
|
|
} else {
|
|
return 'A' . ($rowNumber + 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function callData($sheet, $headers, $data, $startCell) {
|
|
|
|
$startRow = (int) filter_var($startCell, FILTER_SANITIZE_NUMBER_INT);
|
|
$startCol = 'A';
|
|
$sheet->fromArray($data, null, $startCell);
|
|
|
|
$dataRowCount = count($data);
|
|
$lastDataRow = $startRow + $dataRowCount;
|
|
|
|
// $dataColCount = count($headers);
|
|
// $lastDataColumn = getExcelColumnName($dataColCount - 1);
|
|
// $dataRange = "{$startCol}{$startRow}:{$lastDataColumn}{$lastDataRow}";
|
|
// Set font color to black
|
|
// $sheet->getStyle($dataRange)->getFont()->getColor()->setRGB('000000');
|
|
|
|
return 'A' . ($lastDataRow + 1); // return next row
|
|
}
|
|
|
|
function callSkipRow($startCell){
|
|
$row = (int) filter_var($startCell, FILTER_SANITIZE_NUMBER_INT);
|
|
return 'A' . ($row + 1); // just skip a line
|
|
}
|
|
|
|
// function callFooter($sheet, $headers, $data, $startCell,$mergeEndindex) {
|
|
|
|
// $row = (int) filter_var($startCell, FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
// $startCol = preg_replace('/[0-9]/', '', $startCell);
|
|
|
|
// // Determine numeric columns dynamically
|
|
// // $numericIndexes = [];
|
|
// // foreach ($data as $index => $val) {
|
|
// // foreach ($data as $rowData) {
|
|
// // if (isset($rowData[$index]) && is_numeric($rowData[$index])) {
|
|
// // $numericIndexes[] = $index;
|
|
// // break;
|
|
// // }
|
|
// // }
|
|
// // }
|
|
// if (!empty($data)) {
|
|
// // Look at the first row
|
|
// $firstRow = $data[0];
|
|
|
|
// foreach ($firstRow as $key => $value) {
|
|
// foreach ($data as $row) {
|
|
// if (isset($row[$key]) && is_numeric($row[$key])) {
|
|
// $numericIndexes[] = $key; // use the key (could be column name)
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// // Get first numeric column index for placing totals
|
|
// if (empty($numericIndexes)) return 'A' . ($row + 1); // Nothing to total
|
|
|
|
// sort($numericIndexes);
|
|
// $firstNumericIndex = $numericIndexes[0];
|
|
// $colCount = count($headers);
|
|
|
|
// // Calculate end column by character math (works up to 'ZZ')
|
|
// if($mergeEndindex == ''){
|
|
// $mergeEndCol = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($colCount - 1);
|
|
|
|
// }else{
|
|
// $mergeEndCol = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex((int)$mergeEndindex);
|
|
// }
|
|
|
|
|
|
|
|
// // echo gettype($row);die;
|
|
|
|
// // Merge from A to column before first numeric column (for "TOTAL" label)
|
|
// $sheet->mergeCells("A{$row}:{$mergeEndCol}{$row}");
|
|
// $sheet->setCellValue("A{$row}", 'TOTAL');
|
|
|
|
// // Style for TOTAL label
|
|
// $sheet->getStyle("A{$row}:{$mergeEndCol}{$row}")->applyFromArray([
|
|
// 'font' => [
|
|
// 'bold' => true,
|
|
// 'size' => 14,
|
|
// 'color' => ['rgb' => '228B22']
|
|
// ],
|
|
// 'alignment' => [
|
|
// 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
|
|
// 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER
|
|
// ]
|
|
// ]);
|
|
|
|
// // Total each numeric column and write to corresponding cell
|
|
// foreach ($numericIndexes as $index) {
|
|
// $total = 0;
|
|
// foreach ($data as $rowData) {
|
|
// $value = $rowData[$index] ?? 0;
|
|
// if (is_numeric($value)) {
|
|
// $total += $value;
|
|
// }
|
|
// }
|
|
// $colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex((int)$index);
|
|
// $sheet->setCellValue("{$colLetter}{$row}", $total);
|
|
// }
|
|
|
|
// return 'A' . ($row + 1); // Return next available row
|
|
// }
|
|
function callFooter($sheet, $headers, $data, $startCell,$label,$code,$mergeEndIndex = null) {
|
|
$row = (int) filter_var($startCell, FILTER_SANITIZE_NUMBER_INT);
|
|
$startCol = preg_replace('/[0-9]/', '', $startCell);
|
|
|
|
$numericKeys = [];
|
|
$columnKeys = array_keys($data[0] ?? []);
|
|
$columnKeyToIndex = array_flip($columnKeys); // key => index
|
|
|
|
// Detect numeric columns
|
|
foreach ($columnKeys as $key) {
|
|
foreach ($data as $rowData) {
|
|
if (isset($rowData[$key]) && is_numeric($rowData[$key])) {
|
|
$numericKeys[] = $key;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If no numeric columns, skip total row
|
|
if (empty($numericKeys)) {
|
|
return $startCol . ($row + 1);
|
|
}
|
|
|
|
// Determine where to end the merge for the TOTAL label
|
|
if ($mergeEndIndex === null || $mergeEndIndex === '') {
|
|
$firstNumericKey = $numericKeys[0];
|
|
$firstNumericIndex = $columnKeyToIndex[$firstNumericKey];
|
|
$mergeEndIndex = $firstNumericIndex > 0 ? $firstNumericIndex - 1 : 0;
|
|
}
|
|
|
|
// Write totals for each numeric column
|
|
foreach ($numericKeys as $colKey) {
|
|
$total = 0;
|
|
foreach ($data as $rowData) {
|
|
$val = $rowData[$colKey] ?? 0;
|
|
if (is_numeric($val)) {
|
|
$total += $val;
|
|
}
|
|
}
|
|
|
|
$colIndex = $columnKeyToIndex[$colKey];
|
|
$colLetter = Coordinate::stringFromColumnIndex($colIndex + 1);
|
|
$sheet->setCellValue("{$colLetter}{$row}", $total);
|
|
$sheet->getStyle("{$colLetter}{$row}")->getNumberFormat()->setFormatCode('#,##0.00');
|
|
$sheet->getStyle("{$colLetter}{$row}")->applyFromArray([
|
|
'font' => [
|
|
'bold' => true,
|
|
'size' => 12
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => Alignment::VERTICAL_CENTER
|
|
]
|
|
]);
|
|
|
|
|
|
}
|
|
|
|
|
|
$mergeEndCol = Coordinate::stringFromColumnIndex((int)$mergeEndIndex + 1);
|
|
$mergeRange = "{$startCol}{$row}:{$mergeEndCol}{$row}";
|
|
|
|
// Merge cells and write $label name = "TOTAL"
|
|
$sheet->mergeCells($mergeRange);
|
|
$sheet->setCellValue("{$startCol}{$row}", $label);
|
|
|
|
// Style "TOTAL" label
|
|
$sheet->getStyle($mergeRange)->applyFromArray([
|
|
'font' => [
|
|
'bold' => true,
|
|
'size' => 14,
|
|
'color' => ['rgb' => $code]
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => Alignment::VERTICAL_CENTER
|
|
]
|
|
]);
|
|
|
|
// Return next row cell reference
|
|
return $startCol . ($row + 1);
|
|
}
|
|
|