Skip to content

[FEATURE] Ability to stream to an Amazon S3 bucket #2326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 16, 2021
Merged

[FEATURE] Ability to stream to an Amazon S3 bucket #2326

merged 2 commits into from
Oct 16, 2021

Conversation

ayacoo
Copy link
Contributor

@ayacoo ayacoo commented Oct 8, 2021

Related #2249

This is:

- [ ] a bugfix
- [x] a new feature

Requirements
composer required aws/aws-sdk-php

Example

require '../vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$client = new Aws\S3\S3Client([
    'credentials' => [
        'key' => 'KEY',
        'secret' => 'SECRET',
    ],
    'default_cache_config' => '',
    'certificate_authority' => true,
    'region' => 'REGION',
    'version' => 'latest'
]);

// Register the stream wrapper from an S3Client object
$client->registerStreamWrapper();

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');

$writer = new Xlsx($spreadsheet);
$writer->save('s3://BUCKETNAME/myfile.xlsx');

@oleibman
Copy link
Collaborator

I usually like to see a unit test demonstrating that the change works. However, such a test seems impractical here - it requires access to s3, which probably introduces security and availability challenges. It seems clear to me that the change will have no adverse effect for non-s3 access.

@ayacoo
Copy link
Contributor Author

ayacoo commented Oct 10, 2021

Of course, you could refactor a little more. Example: There is a function setModeForFileHandle() There one could test also without S3 package dependency simply whether the scheme changes.

For future changes e.g. further PHP wrapper this would be surely also more suitable. What do you think?

@alexanderkraemer
Copy link

This change makes a lot of sense! Looking forward for it getting merged!

@oleibman oleibman merged commit 1f08f16 into PHPOffice:master Oct 16, 2021
@oleibman
Copy link
Collaborator

Thank you for your contribution.

oleibman added a commit to oleibman/PhpSpreadsheet that referenced this pull request Mar 7, 2022
BaseWriter openFileHandle opens its output file with mode `wb+`. We don't appear to attempt any reads on the file after it is opened in write mode, so `wb` should be sufficient. This may have been a factor in the need for PR PHPOffice#2326, and is likely to be responsible for issue PHPOffice#2372.
@oleibman oleibman mentioned this pull request Mar 7, 2022
5 tasks
oleibman added a commit that referenced this pull request Mar 12, 2022
BaseWriter openFileHandle opens its output file with mode `wb+`. We don't appear to attempt any reads on the file after it is opened in write mode, so `wb` should be sufficient. This may have been a factor in the need for PR #2326, and is likely to be responsible for issue #2372.
@warespace-silas-winter
Copy link

Hi everyone, sorry for reopening the pull request.

I see that the S3 protocol works for the writer. Could s3:// be a workaround for #1147 and #1931? At least for me it would be great.

@oleibman
Copy link
Collaborator

oleibman commented Nov 28, 2024

I think s3:// would work in much the same way as http://. Unfortunately, http:// doesn't work for read. It will fail in Shared\File::assertFile because is_file will return false. And, even if I change the code to bypass that check, it will will fail in Reader\Xlsx::loadSpreadsheetFromFile because $zip->open will fail and return ZipArchive::ER_READ.

However, the following code may be useful to you (substitute your own s3 filename - I have no way to test that):

        $filename = 'http://localhost:8000/filename.xlsx';
        $contents = file_get_contents($filename);
        $tmpfile = tmpfile();
        $path = stream_get_meta_data($tmpfile)['uri'];
        echo "path is $path\n";
        fwrite($tmpfile, $contents);
        fseek($tmpfile, 0);
        $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
        $spreadsheet = $reader->load($path);
        fclose($tmpfile);

The temporary file should be deleted by the fclose, and you can always write some sort of handler to force its deletion even if the spreadsheet load fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants