Laravel Excel is working but the file cannot be opened
Asked Answered
J

1

5

I am using the Laravel Excel to create excel documents with many sheets. I have been following their example of how they do it, but when I go to download the file its:

Excel cannot open the file 'kingdoms (1).xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.

I am unsure why.

So heres how I do it:

Controller Method:

public function export() {
    return Excel::download(new KingdomsExport, 'kingdoms.xlsx', \Maatwebsite\Excel\Excel::XLSX);
}

Export Class

class KingdomsExport implements WithMultipleSheets {

    use Exportable;

    /**
     * @return array
     */
    public function sheets(): array {
        $sheets   = [];

        $sheets[] = new BuildingsSheet;

        // .. other commented out sheets.

        return $sheets;
    }
}

Buildings Sheet

class BuildingsSheet implements FromView, WithTitle, ShouldAutoSize {

    /**
     * @return View
     */
    public function view(): View {
        return view('admin.exports.kingdoms.sheets.buildings', [
            'buildings' => GameBuilding::all(),
        ]);
    }

    /**
     * @return string
     */
    public function title(): string {
        return 'Buildings';
    }
}

Buildings view

<table>
    <thead>
    <tr>
        <th>name</th>
        <th>description</th>
        <th>max_level</th>
        <th>base_durability</th>
        <th>base_defence</th>
        <th>required_population</th>
        <th>units_per_level</th>
        <th>only_at_level</th>
        <th>is_resource_building</th>
        <th>trains_units</th>
        <th>is_walls</th>
        <th>is_church</th>
        <th>is_farm</th>
        <th>wood_cost</th>
        <th>clay_cost</th>
        <th>stone_cost</th>
        <th>iron_cost</th>
        <th>time_to_build</th>
        <th>time_increase_amount</th>
        <th>decrease_morale_amount</th>
        <th>increase_population_amount</th>
        <th>increase_morale_amount</th>
        <th>increase_wood_amount</th>
        <th>increase_clay_amount</th>
        <th>increase_stone_amount</th>
        <th>increase_iron_amount</th>
        <th>increase_durability_amount</th>
        <th>increase_defence_amount</th>
    </tr>
    </thead>
    <tbody>
    @foreach($buildings as $building)
        <tr>
            <td>{{$building->name}}</td>
            <td>{{$building->description}}</td>
            <td>{{$building->max_level}}</td>
            <td>{{$building->base_durability}}</td>
            <td>{{$building->base_defence}}</td>
            <td>{{$building->required_population}}</td>
            <td>{{$building->units_per_level}}</td>
            <td>{{$building->only_at_level}}</td>
            <td>{{$building->is_resource_building}}</td>
            <td>{{$building->trains_units}}</td>
            <td>{{$building->is_walls}}</td>
            <td>{{$building->is_church}}</td>
            <td>{{$building->is_farm}}</td>
            <td>{{$building->wood_cost}}</td>
            <td>{{$building->clay_cost}}</td>
            <td>{{$building->stone_cost}}</td>
            <td>{{$building->iron_cost}}</td>
            <td>{{$building->time_to_build}}</td>
            <td>{{$building->time_increase_amount}}</td>
            <td>{{$building->decrease_morale_amount}}</td>
            <td>{{$building->increase_population_amount}}</td>
            <td>{{$building->increase_morale_amount}}</td>
            <td>{{$building->increase_wood_amount}}</td>
            <td>{{$building->increase_clay_amount}}</td>
            <td>{{$building->increase_stone_amount}}</td>
            <td>{{$building->increase_iron_amount}}</td>
            <td>{{$building->increase_durability_amount}}</td>
            <td>{{$building->increase_defence_amount}}</td>
        </tr>
    @endforeach
    </tbody>
</table>

I can't see anything wrong here with any of this, yet the file cannot be opened. I have tried to open it with vi but it's all gibberish. If I try and download as csv, it opens fine. but as I plan to have multiple sheets, it doesn't seem to include them with csv files.

I do have other sheets, but for simplicity I commented them out to see if one of them was having an issue. Alas even with just one sheet, it still won't open. Is it something wrong with how I download the excel file?

Jacobite answered 19/5, 2021 at 18:36 Comment(7)
Random question, do you have Laravel debugbar installed/enabled? I've had issues with Excel file corruption locally with that plugin installed. Also, at a glance, this all looks ok. If you run this export logic in a php artisan tinker session, and use ::store() instead of ::download(), can you open the file? (Will be in storage/app most likely) – Decembrist
@TimLewis I do not have that extension installed, how would it help out of curiosity? I do have telescope installed. As for storing it instead of downloading via tinker it works, but same issue - cannot be opened. – Jacobite
Was a long shot; and the extension is useful for logging/debugging in-app stuff: github.com/barryvdh/laravel-debugbar, but the way it does it actually interferes with excel generation in some instances (php headers or some weird stuff). I'm not sure of Telescope, might be similar, but if you're getting it via Console, it's irrelevant πŸ˜… – Decembrist
@TimLewis Should I move this over as a github issue then? If things look correct? Is it the download? Do I need special headers? They show some for the csv type – Jacobite
Might be worthwhile, but there's no harm in having the question open here too; hopefully someone else will be able to help. I can look more into it when I get a bit more free time; should be straightforward to debug with the information provided. – Decembrist
So the good news is I was able to use your code in a local sandbox and everything worked, but bad news is it wasn't corrupted... My guess is there's something in one of the $building instances that is causing the corruption, but it's a stab in the dark. Could you add an instance dd($building->toArray()) (or $buildings, if that's not too much data) to your code? Or drop the @foreach() from your view and download again, see if still corrupted. Also, I used local instead of \Maatwebsite\Excel\Excel::XLSX for my storage disk – Decembrist
@TimLewis With the dd there is nothing odd. In the github discussion, some one mentioned to check for white spaces and special characters but theres none (php storm with white spaces turned on and running on a mac) – Jacobite
J
11

So this might not be obvious to those who have this issue but:

    $response = Excel::download(new KingdomsExport, 'kingdoms.xlsx', \Maatwebsite\Excel\Excel::XLSX);
    ob_end_clean();

    return $response;

The trick: ob_end_clean. It seems that the buffer does not get properly cleaned up, so there is an extra space added. But doing this, the file downloaded and was able to be opened.

Jacobite answered 19/5, 2021 at 22:3 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.