├── .gitattributes ├── .gitignore ├── composer.json ├── public └── test.xlsx └── src ├── ExcelTo.php └── ServiceProvider.php /.gitattributes: -------------------------------------------------------------------------------- 1 | /Readme.md export-ignore 2 | /tests export-ignore 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .vscode 3 | composer.lock -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "knackline/excel-to-x", 3 | "description": "Laravel Package that converts excel to JSON/collection", 4 | "license": "MIT", 5 | "autoload": { 6 | "psr-4": { 7 | "Knackline\\ExcelTo\\": "src/" 8 | } 9 | }, 10 | "authors": [ 11 | { 12 | "name": "RAJKUMAR SAMRA", 13 | "email": "rajkumarsamra@gmail.com" 14 | } 15 | ], 16 | "require": { 17 | "php": "^8.2", 18 | "phpoffice/phpspreadsheet": "^1.29" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^9.5" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /public/test.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Knackline/laravel-excel-to-x/4ea1ba0092208396d0f81598d0bb1b32ba986d46/public/test.xlsx -------------------------------------------------------------------------------- /src/ExcelTo.php: -------------------------------------------------------------------------------- 1 | getSheetCount(); 18 | $jsonData = []; 19 | 20 | foreach ($spreadsheet->getAllSheets() as $worksheet) { 21 | $sheetData = self::processSheet($worksheet); 22 | 23 | if ($sheetCount > 1) { 24 | $jsonData[$worksheet->getTitle()] = $sheetData; 25 | } else { 26 | $jsonData = $sheetData; 27 | } 28 | } 29 | 30 | return json_encode($jsonData); 31 | } 32 | 33 | public static function collection(string $filePath): Collection 34 | { 35 | $spreadsheet = self::loadSpreadsheet($filePath); 36 | $collection = collect(); 37 | 38 | foreach ($spreadsheet->getAllSheets() as $worksheet) { 39 | $collection->put($worksheet->getTitle(), collect(self::processSheet($worksheet))); 40 | } 41 | 42 | return $collection; 43 | } 44 | 45 | public static function array(string $filePath): array 46 | { 47 | return self::collection($filePath)->toArray(); 48 | } 49 | 50 | private static function loadSpreadsheet(string $filePath): Spreadsheet 51 | { 52 | self::validateFilePath($filePath); 53 | return IOFactory::load($filePath); 54 | } 55 | 56 | private static function validateFilePath(string $filePath): void 57 | { 58 | if (!file_exists($filePath)) { 59 | throw new \InvalidArgumentException("File does not exist: $filePath"); 60 | } 61 | 62 | if (!is_readable($filePath)) { 63 | throw new \InvalidArgumentException("File is not readable: $filePath"); 64 | } 65 | 66 | $fileInfo = new finfo(FILEINFO_MIME_TYPE); 67 | $mimeType = $fileInfo->file($filePath); 68 | 69 | if ( 70 | $mimeType !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' && 71 | $mimeType !== 'application/vnd.ms-excel' 72 | ) { 73 | throw new \InvalidArgumentException("Invalid file type: $mimeType"); 74 | } 75 | } 76 | 77 | private static function processSheet($worksheet): array 78 | { 79 | $excelData = $worksheet->toArray(null, true, true, true); // Load with nulls 80 | $mergedCells = $worksheet->getMergeCells(); // Get merged cells info 81 | $header = array_shift($excelData); 82 | $sheetData = []; 83 | 84 | foreach ($excelData as $rowIndex => $row) { 85 | $rowData = []; 86 | 87 | foreach ($header as $colIndex => $columnName) { 88 | $columnLetter = $colIndex; // PhpSpreadsheet uses lettered indexes 89 | $cellAddress = $columnLetter . ($rowIndex + 2); 90 | 91 | // Check if the cell is part of a merged range 92 | $value = $worksheet->getCell($cellAddress)->getCalculatedValue(); 93 | foreach ($mergedCells as $range) { 94 | if (self::isCellInRange($cellAddress, $range)) { 95 | $value = $worksheet->getCell(explode(':', $range)[0])->getCalculatedValue(); 96 | break; 97 | } 98 | } 99 | 100 | // Handle date values 101 | $cell = $worksheet->getCell($cellAddress); 102 | $isDate = Date::isDateTime($cell); 103 | 104 | if ($isDate && is_numeric($value)) { 105 | $value = Date::excelToDateTimeObject($value)->format('d/m/Y'); 106 | } 107 | 108 | $rowData[$columnName] = $value; 109 | } 110 | 111 | $sheetData[] = $rowData; 112 | } 113 | 114 | return $sheetData; 115 | } 116 | 117 | private static function isCellInRange(string $cellAddress, string $range): bool 118 | { 119 | [$startCell, $endCell] = explode(':', $range); 120 | [$startCol, $startRow] = Coordinate::coordinateFromString($startCell); 121 | [$endCol, $endRow] = Coordinate::coordinateFromString($endCell); 122 | [$col, $row] = Coordinate::coordinateFromString($cellAddress); 123 | 124 | return $row >= $startRow && $row <= $endRow && $col >= $startCol && $col <= $endCol; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton('excel-to-x', function () { 17 | return new ExcelTo(); 18 | }); 19 | } 20 | } 21 | --------------------------------------------------------------------------------