I am working on a project to convert payment methods into tokens. To do this, I need to generate Method IDs using the customer numbers from my database. I have created a simple HTML form where I can upload an excel sheet with the customer numbers and receive a new excel sheet with the updated information (when submitting the form), including the Method IDs. However, all the new data is appearing in a single column. Can you show me how to separate the data into separate columns in the output?
Here is an example of the current output.
Excel export
Here is my code
<?php
ob_start();
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;
if ($_SERVER["REQUEST_METHOD"] === "POST")
{
$wsdl = "https://sandbox.usaepay.com/soap/gate/43R1QPKU/usaepay.wsdl";
$sourceKey = "_g6BALVW9vpPZ3jEqf5kwe4pIrqyvabY";
$pin = "1234";
function getClient($wsdl)
{
return new SoapClient($wsdl, array(
'trace' => 1,
'exceptions' => 1,
'stream_context' => stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
))
));
}
function getToken($sourceKey, $pin)
{
$seed = time() . rand();
return array(
'SourceKey' => $sourceKey,
'PinHash' => array(
'Type' => 'sha1',
'Seed' => $seed,
'HashValue' => sha1($sourceKey . $seed . $pin)
) ,
'ClientIP' => $_SERVER['REMOTE_ADDR']
);
}
$client = getClient($wsdl);
$token = getToken($sourceKey, $pin);
// Load the customer numbers from the uploaded Excel file
try
{
// Load the customer numbers from the uploaded Excel file
$file = $_FILES['file'];
if (!$file)
{
throw new Exception('File not uploaded');
}
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file['tmp_name']);
$worksheet = $spreadsheet->getActiveSheet();
$customer_numbers = $worksheet->toArray();
// Generate the method ID for each customer number
foreach ($customer_numbers as $customer_number)
{
try
{
print_r($client->getCustomer($token, $customer_number[0]));
}
catch(soapFault $e)
{
// Code to handle the exception
echo "An error occurred for customer number: " . $customer_number[0] . " - " . $e->getMessage() . "\n";
}
}
// Save the new Excel sheet with the information and Method IDs
$outputFileName = 'output.csv';
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Csv');
$writer->save($outputFileName);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename=output.csv');
}
catch(Exception $e)
{
echo "An error occurred: " . $e->getMessage() . "\n";
}
}
ob_end_flush();
?>
HTMl
<!DOCTYPE html>
<html>
<head>
<title>Method ID Generator</title>
</head>
<body>
<h1>Method ID Generator</h1>
<form action="getmethodID.php" method="post" enctype="multipart/form-data">
<label for="file">Upload Excel File:</label>
<input type="file" name="file" id="file">
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
I have already spent over 2 hours figuring it out
can anyone help me here?
You are using print_r which will send the output of your function back to the browser, and setting the headers will instruct the browser to offer the file for download. This is the file you have showed in your screenshot which contains the output of print_r.
At the same time you are exporting a CSV file from php spreadsheet which will save the file on your web server in the same directory as the php script (assuming it has permission). You have not shown us the content of this file but it will be the same as your input file as your script never writes to the $spreadsheet object.
You need to write the content from your function into the $spreadsheet object.
$sheet = $spreadsheet->getActiveSheet();
// export headers
$sheet->setCellValue('A1','Ammount');
$sheet->setCellValue('B1','City');
// more headers ...
$spreadsheetrow = 2; // set a row counter
foreach ($customer_numbers as $customer_number){
$data = $client->getCustomer($token, $customer_number[0]);
// export data
$sheet->setCellValue('A'.$spreadsheetrow,$data['Ammount']);
$sheet->setCellValue('B'.$spreadsheetrow,$data['Billing']['City']);
// etc..
$spreadsheetrow++; // increment row counter
}
You can then save the file inline back to the browser:
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename=output.csv');
$writer->save('php://output'); // Exports inline to browser, rather than saving to file
Alternativly for CSV you can use built in PHP functions:
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment;filename=output.csv');
$output = fopen('php://output', 'w');
fputcsv($output, ['Ammount', 'City']);
foreach ($customer_numbers as $customer_number){
$data = $client->getCustomer($token, $customer_number[0]);
fputcsv($data['Ammount'], $data['Billing']['City']);
}
Related
I need to generate an Excel file with extension .xlsx.
Here is my simple code:
$file = "test.xlsx";
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.$file);
$content = "Col1\tCol2\tCol3\t\n";
$content .= "test1\ttest1\ttest3\t\n";
$content .= "testtest1\ttesttest2\ttesttest3\t\n";
echo $content;
But I get this error when I open the generated file:
Excel cannot open the file 'test.xlsx' because the file format or file extension is not valid.
Any ideas?
SimpleXLSXGen
$books = [
['ISBN', 'title', 'author', 'publisher', 'ctry' ],
[618260307, 'The Hobbit', 'J. R. R. Tolkien', 'Houghton Mifflin', 'USA'],
[908606664, 'Slinky Malinki', 'Lynley Dodd', 'Mallinson Rendel', 'NZ']
];
$xlsx = Shuchkin\SimpleXLSXGen::fromArray( $books );
$xlsx->saveAs('books.xlsx');
// $xlsx->downloadAs('books.xlsx');
After trying a few options, I found that PHP_XLSX_Writer suited my needs.
PHP_XLSX_Writer
-
...designed to be lightweight, minimal memory usage, generates an
Excel-compatible workbook in XLSX format, with basic features supported:
- supports PHP 5.2.1+
- takes 'UTF-8' characters (or encoded input)
- multiple worksheets
- supports currency/date/numeric cell formatting, simple formulas
- supports basic cell styling
- supports writing huge 100K+ row spreadsheets
(Adapted from the library's GitHub repository)
Here's an working example demonstrating a few features on 3 worksheets (tabs):
First create a file called xlsxwriter.class.php containing the code found here.
Create another PHP file (in the same folder) containing:
require('xlsxwriter.class.php');
$fname='my_1st_php_excel_workbook.xlsx';
$header1 = [ 'create_date' => 'date',
'quantity' => 'string',
'product_id' => 'string',
'amount' => 'money',
'description' => 'string' ];
$data1 = [ ['2021-04-20', 1, 27, '44.00', 'twig'],
['2021-04-21', 1, '=C1', '-44.00', 'refund'] ];
$data2 = [ ['2','7','ᑌᑎIᑕᗝᗪᗴ ☋†Ϝ-➑'],
['4','8','😁'] ];
$styles2 = array( ['font-size'=>6],['font-size'=>8],['font-size'=>10],['font-size'=>16] );
$writer = new XLSXWriter();
$writer->setAuthor('Your Name Here');
$writer->writeSheet($data1,'MySheet1', $header1); // with headers
$writer->writeSheet($data2,'MySheet2'); // no headers
$writer->writeSheetRow('MySheet2', $rowdata = array(300,234,456,789), $styles2 );
$writer->writeToFile($fname); // creates XLSX file (in current folder)
echo "Wrote $fname (".filesize($fname)." bytes)<br>";
// ...or instead of creating the XLSX you can just trigger a
// download by replacing the last 2 lines with:
// header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
// header('Content-Disposition: attachment;filename="'.$fname.'"');
// header('Cache-Control: max-age=0');
// $writer->writeToStdOut();
More Information:
GitHub repository
author's website
lots more examples
As others have mentioned, PhpSpreadsheet provides a nice library for this. Assuming you have it installed via composer and the vendor/autoload.php has been included in your project, you can use the function below to generate an xlsx from an array of arrays. I've included extensive comments here to help teach beginners about how PhpSpreadsheet works and what the code is doing:
function writeXLSX($filename, $rows, $keys = [], $formats = []) {
// instantiate the class
$doc = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $doc->getActiveSheet();
// $keys are for the header row. If they are supplied we start writing at row 2
if ($keys) {
$offset = 2;
} else {
$offset = 1;
}
// write the rows
$i = 0;
foreach($rows as $row) {
$doc->getActiveSheet()->fromArray($row, null, 'A' . ($i++ + $offset));
}
// write the header row from the $keys
if ($keys) {
$doc->setActiveSheetIndex(0);
$doc->getActiveSheet()->fromArray($keys, null, 'A1');
}
// get last row and column for formatting
$last_column = $doc->getActiveSheet()->getHighestColumn();
$last_row = $doc->getActiveSheet()->getHighestRow();
// autosize all columns to content width
for ($i = 'A'; $i <= $last_column; $i++) {
$doc->getActiveSheet()->getColumnDimension($i)->setAutoSize(TRUE);
}
// if $keys, freeze the header row and make it bold
if ($keys) {
$doc->getActiveSheet()->freezePane('A2');
$doc->getActiveSheet()->getStyle('A1:' . $last_column . '1')->getFont()->setBold(true);
}
// format all columns as text
$doc->getActiveSheet()->getStyle('A2:' . $last_column . $last_row)->getNumberFormat()->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_TEXT);
if ($formats) {
// if there are user supplied formats, set each column format accordingly
// $formats should be an array with column letter as key and one of the PhpOffice constants as value
// https://phpoffice.github.io/PhpSpreadsheet/1.2.1/PhpOffice/PhpSpreadsheet/Style/NumberFormat.html
// EXAMPLE:
// ['C' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_00, 'D' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_00]
foreach ($formats as $col => $format) {
$doc->getActiveSheet()->getStyle($col . $offset . ':' . $col . $last_row)->getNumberFormat()->setFormatCode($format);
}
}
// write and save the file
$writer = new PhpOffice\PhpSpreadsheet\Writer\Xlsx($doc);
$writer->save($filename);
}
EXAMPLE USAGE:
$rows = [
['sku' => 'A123', 'price' => '99'],
['sku' => 'B456', 'price' => '5.35'],
['sku' => 'C789', 'price' => '17.7']
];
$keys = array_keys(current($rows));
$formats = ['B' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_00];
writeXLSX('pricelist.xlsx', $rows, $keys, $formats);
You can still use previous versions of PHPSpreadsheet if you are using old versions of PHP.
You have to include the version number of PHPSpreadsheet while installing it in your project directory.
This worked for me:
composer require phpoffice/phpspreadsheet:1.8.0
May be the file is not compatible with the version of Excel that is used.
Try with change your file extension 'xlsx' to 'xls and check it's working or not.
if it's working then this file extension(.xlsx) is not compatible with the version of Excel that, you used.
The content is not a valid xlsx content. Try sending your content as a comma separated value content and use xls to open that
As a suggestion, If u can change your content, May be you could try this?
$file = "test.csv";
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.$file);
$content = "Col1,Col2,Col3\n";
$content .= "test1,test1,test3\n";
$content .= "testtest,ttesttest2,testtest3\n";
echo $content;
See my code, here I have made simple xlsx file
<?php
include 'PHPExcel/PHPExcel.php';
include 'PHPExcel/PHPExcel/Writer/Excel2007.php';
$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Hello');
$objPHPExcel->getActiveSheet()->SetCellValue('B1', 'Trudeau');
$objPHPExcel->getActiveSheet()->SetCellValue('C1', 'Fernandes');
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$objWriter->save(str_replace('.php', '.xlsx', __FILE__));
echo " Click here for gerate xlsx file <a href='test.xlsx'>clicking me</a>";
?>
and for me, it's working fine.
Found a handful of questions on here about this with no answer, so hopefully, someone can point me in the right direction...
I'm trying to create and save a csv file to storage, then update the DB in Laravel. I can create the file successfully, and I can update the DB successfully... but I'm stuck on putting them both together. In my controller, I have this for creating the file (taken from here):
public function updatePaymentConfirm(Request $request) {
$users = User::all();
$fileName = 'test.csv';
$headers = array(
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=$fileName",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
);
$columns = array('First Name', 'Email');
$callback = function() use($users, $columns) {
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach ($users as $user) {
$row['First Name'] = $user->first_name;
$row['Email'] = $user->email;
fputcsv($file, array($row['First Name'], $row['Email']));
}
fclose($file);
};
// return response()->stream($callback, 200, $headers);
}
When the function completes, the last line (that's commented out) prompts the user to download the newly created file (which is not the functionality I'm looking for). I tried adding this to my controller in its place for saving to storage and also updating the database:
$fileModel = new UserDocument;
if($callback) {
$filePath = $callback->storeAs('uploads', $fileName, 'public');
$fileModel->name = $fileName;
$fileModel->file_path = '/storage/' . $filePath;
$fileModel->save();
return back()
->with('success','File has been uploaded.')
->with('file', $fileName);
}
It saves a row to the db, albeit incorrectly, but it doesn't save the file to storage. I've reworked the $filePath line a million times, but I keep getting this error Call to a member function storeAs() on resource or something similar. I'm relatively new to working with Laravel, so I'm not sure what I should be looking for. Thoughts?
Removed everything and started over... got it! And for anyone else running into the same issue: just calling for a file that doesn't exist creates the file (unless the file exists - then it updates it), so you don't have to create a temp file or use $file = fopen('php://output', 'w'); to create the file. It'll automatically "save" the newly generated file in the file path you specified when you fclose() out of the file.
The only thing I'll note is that the file path has to exist (the file doesn't, but the file path does). In my instance, the file path already exists, but if yours doesn't or if you're not sure if it does, check to see if it exists, and then make the directory.
public function updatePaymentConfirm(Request $request) {
$user = Auth::user();
$path = storage_path('app/public/docs/user_docs/'.$user->id);
$fileName = $user->ein.'.csv';
$file = fopen($path.$fileName, 'w');
$columns = array('First Name', 'Email Address');
fputcsv($file, $columns);
$data = [
'First Name' => $user->first_name,
'Email Address' => $user->email,
];
fputcsv($file, $data);
fclose($file);
$symlink = 'public/docs/user_docs/'.$user->id.'/';
$fileModel = new UserDocument;
$fileModel->name = 'csv';
$fileModel->file_path = $symlink.$fileName;
$fileModel->save();
return redirect()->route('completed');
}
** UPDATE **
Everything worked perfectly locally, and when I pushed this to production, I received this error 🙄:
fopen(https://..../12-3456789.csv): failed to open stream: HTTP wrapper does not support writeable connections.
I'm saving to an s3 bucket, and I had to rework the entire process. You can't create and/or write to a file in the directory. I had to create a temp file first. Here's where I landed:
$user = Auth::user();
$s3 = Storage::disk('s3');
$storage = Storage::disk('s3')->url('/');
$path = 'public/docs/user_docs/'.$user->id.'/';
$csvFile = tmpfile();
$csvPath = stream_get_meta_data($csvFile)['uri'];
$fd = fopen($csvPath, 'w');
$columns = array('First Name', 'Email Address');
$data = array(
'First Name' => $user->first_name,
'Email Address' => $user->email,
);
fputcsv($fd, $columns);
fputcsv($fd, $data);
fclose($fd);
$s3->putFileAs('', $csvPath, $path.$user->ein.'.csv');
Today I have fixed it with this snipe:
// output up to 5MB is kept in memory, if it becomes bigger it will
// automatically be written to a temporary file
$csv = fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
fputcsv($csv, array('blah','blah'));
rewind($csv);
$output = stream_get_contents($csv);
// Put the content directly in file into the disk
Storage::disk('myDisk')->put("report.csv", $output);
This code is easy and functional, use Laravel Storage Class
https://laravel.com/docs/9.x/filesystem#main-content
use Illuminate\Support\Facades\Storage;
// data array
$results = [
['id' => 0, 'name' => 'David', 'parent' => 1],
['id' => 1, 'name' => 'Ron', 'parent' => 0],
['id' => 2, 'name' => 'Mark', 'parent' => 1]
];
// create a variable to store data
$pages = "id,name,parent\n"; // use " not ' or \n not working
// use foreach to data
foreach ($results as $where) {
$pages .= "{$where['id']},{$where['name']},{$where['parent']}\n";
}
// use Fecades Laravel Storage
Storage::disk('local')->put('file.csv', $pages);
I know one should not use echo in controllers, but I don't understand what I should use to return an xml in order to download it. Please note, it's not a file on the server, it's just a string:
public function export()
{
$this->autoRender = false;
$id = $this->request->getQuery('id');
$invoice = $this->Invoices->get($id, ['contain' => ['Customers', 'ItemInvoices' => ['ItemProformas' => ['ItemDeliveryNotes' => ['ItemOrders' => ['Orders' => ['Customers']]]]]]]);
$fpr = new ExportInvoice();
$fpr->SetInvoice($invoice);
header('Content-type: text/xml');
header('Content-Disposition: attachment; filename="' . $fpr->getFilename() . '"');
$xml = $fpr->asXML();
echo $xml;
}
it actually works as expected: the browser download a file with the given filename and its content is the $xml value.
But at the end of the file there are warnings about headers:
Warning (512): Unable to emit headers. Headers sent in file=/home/mark/myproject/src/Controller/InvoicesController.php line=130 [CORE/src/Http/ResponseEmitter.php, line 51]
Warning (2): Cannot modify header information - headers already sent by (output started at /home/mark/myproject/src/Controller/InvoicesController.php:130) [CORE/src/Http/ResponseEmitter.php, line 152]
Warning (2): Cannot modify header information - headers already sent by (output started at /home/mark/myproject/src/Controller/InvoicesController.php:130) [CORE/src/Http/ResponseEmitter.php, line 181]
Warning (2): Cannot modify header information - headers already sent by (output started at /home/mark/myproject/src/Controller/InvoicesController.php:130) [CORE/src/Http/ResponseEmitter.php, line 181]
As far as I know this is due to the usage of echo in controller. It may happens there's an output before sending the header, and then the warnings.
What's the correct way to replace the echo function?
Prior to the docs , you can use the framework for that , checkout how to Sending a String as File
public function export()
{
$this->autoRender = false;
$id = $this->request->getQuery('id');
$invoice = $this->Invoices->get($id, ['contain' => ['Customers', 'ItemInvoices' => ['ItemProformas' => ['ItemDeliveryNotes' => ['ItemOrders' => ['Orders' => ['Customers']]]]]]]);
$fpr = new ExportInvoice();
$fpr->SetInvoice($invoice);
// header('Content-type: text/xml');
// header('Content-Disposition: attachment; filename="' . $fpr->getFilename() . '"');
$xml = $fpr->asXML();
$response = $this->response;
$response = $response->withStringBody($xml);
// use $response->body($xml); for versions before 3.4.0
$response = $response->withType('xml');
$response = $response->withDownload($fpr->getFilename());
return $response;
}
Just use die() or exit()
public function export()
{
$this->autoRender = false;
$id = $this->request->getQuery('id');
$invoice = $this->Invoices->get($id, ['contain' => ['Customers', 'ItemInvoices' => ['ItemProformas' => ['ItemDeliveryNotes' => ['ItemOrders' => ['Orders' => ['Customers']]]]]]]);
$fpr = new ExportInvoice();
$fpr->SetInvoice($invoice);
if (!headers_sent())
{
header('Content-type: text/xml');
header('Content-Disposition: attachment; filename="' . $fpr->getFilename() . '"');
}
else
{
//Do something else to let them know they can't expect a file
die();
}
die($fpr->asXML());
}
Update
Regarding the comment
Using return, exit or die is already explained in detail in this question php-exit-or-return-which-is-better, what-are-the-differences-in-die-and-exit-in-php
I need to generate an Excel file with extension .xlsx.
Here is my simple code:
$file = "test.xlsx";
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.$file);
$content = "Col1\tCol2\tCol3\t\n";
$content .= "test1\ttest1\ttest3\t\n";
$content .= "testtest1\ttesttest2\ttesttest3\t\n";
echo $content;
But I get this error when I open the generated file:
Excel cannot open the file 'test.xlsx' because the file format or file extension is not valid.
Any ideas?
SimpleXLSXGen
$books = [
['ISBN', 'title', 'author', 'publisher', 'ctry' ],
[618260307, 'The Hobbit', 'J. R. R. Tolkien', 'Houghton Mifflin', 'USA'],
[908606664, 'Slinky Malinki', 'Lynley Dodd', 'Mallinson Rendel', 'NZ']
];
$xlsx = Shuchkin\SimpleXLSXGen::fromArray( $books );
$xlsx->saveAs('books.xlsx');
// $xlsx->downloadAs('books.xlsx');
After trying a few options, I found that PHP_XLSX_Writer suited my needs.
PHP_XLSX_Writer
-
...designed to be lightweight, minimal memory usage, generates an
Excel-compatible workbook in XLSX format, with basic features supported:
- supports PHP 5.2.1+
- takes 'UTF-8' characters (or encoded input)
- multiple worksheets
- supports currency/date/numeric cell formatting, simple formulas
- supports basic cell styling
- supports writing huge 100K+ row spreadsheets
(Adapted from the library's GitHub repository)
Here's an working example demonstrating a few features on 3 worksheets (tabs):
First create a file called xlsxwriter.class.php containing the code found here.
Create another PHP file (in the same folder) containing:
require('xlsxwriter.class.php');
$fname='my_1st_php_excel_workbook.xlsx';
$header1 = [ 'create_date' => 'date',
'quantity' => 'string',
'product_id' => 'string',
'amount' => 'money',
'description' => 'string' ];
$data1 = [ ['2021-04-20', 1, 27, '44.00', 'twig'],
['2021-04-21', 1, '=C1', '-44.00', 'refund'] ];
$data2 = [ ['2','7','ᑌᑎIᑕᗝᗪᗴ ☋†Ϝ-➑'],
['4','8','😁'] ];
$styles2 = array( ['font-size'=>6],['font-size'=>8],['font-size'=>10],['font-size'=>16] );
$writer = new XLSXWriter();
$writer->setAuthor('Your Name Here');
$writer->writeSheet($data1,'MySheet1', $header1); // with headers
$writer->writeSheet($data2,'MySheet2'); // no headers
$writer->writeSheetRow('MySheet2', $rowdata = array(300,234,456,789), $styles2 );
$writer->writeToFile($fname); // creates XLSX file (in current folder)
echo "Wrote $fname (".filesize($fname)." bytes)<br>";
// ...or instead of creating the XLSX you can just trigger a
// download by replacing the last 2 lines with:
// header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
// header('Content-Disposition: attachment;filename="'.$fname.'"');
// header('Cache-Control: max-age=0');
// $writer->writeToStdOut();
More Information:
GitHub repository
author's website
lots more examples
As others have mentioned, PhpSpreadsheet provides a nice library for this. Assuming you have it installed via composer and the vendor/autoload.php has been included in your project, you can use the function below to generate an xlsx from an array of arrays. I've included extensive comments here to help teach beginners about how PhpSpreadsheet works and what the code is doing:
function writeXLSX($filename, $rows, $keys = [], $formats = []) {
// instantiate the class
$doc = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $doc->getActiveSheet();
// $keys are for the header row. If they are supplied we start writing at row 2
if ($keys) {
$offset = 2;
} else {
$offset = 1;
}
// write the rows
$i = 0;
foreach($rows as $row) {
$doc->getActiveSheet()->fromArray($row, null, 'A' . ($i++ + $offset));
}
// write the header row from the $keys
if ($keys) {
$doc->setActiveSheetIndex(0);
$doc->getActiveSheet()->fromArray($keys, null, 'A1');
}
// get last row and column for formatting
$last_column = $doc->getActiveSheet()->getHighestColumn();
$last_row = $doc->getActiveSheet()->getHighestRow();
// autosize all columns to content width
for ($i = 'A'; $i <= $last_column; $i++) {
$doc->getActiveSheet()->getColumnDimension($i)->setAutoSize(TRUE);
}
// if $keys, freeze the header row and make it bold
if ($keys) {
$doc->getActiveSheet()->freezePane('A2');
$doc->getActiveSheet()->getStyle('A1:' . $last_column . '1')->getFont()->setBold(true);
}
// format all columns as text
$doc->getActiveSheet()->getStyle('A2:' . $last_column . $last_row)->getNumberFormat()->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_TEXT);
if ($formats) {
// if there are user supplied formats, set each column format accordingly
// $formats should be an array with column letter as key and one of the PhpOffice constants as value
// https://phpoffice.github.io/PhpSpreadsheet/1.2.1/PhpOffice/PhpSpreadsheet/Style/NumberFormat.html
// EXAMPLE:
// ['C' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_00, 'D' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_00]
foreach ($formats as $col => $format) {
$doc->getActiveSheet()->getStyle($col . $offset . ':' . $col . $last_row)->getNumberFormat()->setFormatCode($format);
}
}
// write and save the file
$writer = new PhpOffice\PhpSpreadsheet\Writer\Xlsx($doc);
$writer->save($filename);
}
EXAMPLE USAGE:
$rows = [
['sku' => 'A123', 'price' => '99'],
['sku' => 'B456', 'price' => '5.35'],
['sku' => 'C789', 'price' => '17.7']
];
$keys = array_keys(current($rows));
$formats = ['B' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_00];
writeXLSX('pricelist.xlsx', $rows, $keys, $formats);
You can still use previous versions of PHPSpreadsheet if you are using old versions of PHP.
You have to include the version number of PHPSpreadsheet while installing it in your project directory.
This worked for me:
composer require phpoffice/phpspreadsheet:1.8.0
May be the file is not compatible with the version of Excel that is used.
Try with change your file extension 'xlsx' to 'xls and check it's working or not.
if it's working then this file extension(.xlsx) is not compatible with the version of Excel that, you used.
The content is not a valid xlsx content. Try sending your content as a comma separated value content and use xls to open that
As a suggestion, If u can change your content, May be you could try this?
$file = "test.csv";
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.$file);
$content = "Col1,Col2,Col3\n";
$content .= "test1,test1,test3\n";
$content .= "testtest,ttesttest2,testtest3\n";
echo $content;
See my code, here I have made simple xlsx file
<?php
include 'PHPExcel/PHPExcel.php';
include 'PHPExcel/PHPExcel/Writer/Excel2007.php';
$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Hello');
$objPHPExcel->getActiveSheet()->SetCellValue('B1', 'Trudeau');
$objPHPExcel->getActiveSheet()->SetCellValue('C1', 'Fernandes');
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$objWriter->save(str_replace('.php', '.xlsx', __FILE__));
echo " Click here for gerate xlsx file <a href='test.xlsx'>clicking me</a>";
?>
and for me, it's working fine.
How can I download file from s3 in php. The following code not working for me...
Here is my code
upload file should work correct
try {
$s3->putObject([
'Bucket' => $config['s3']['bucket'],//'eliuserfiles',
'Key' => "uploads/{$name}",
'Body' => fopen($tmp_name, 'r+'),
//'SourceFile' => $pathToFile,
'ACL' => 'public-read',
]);
download gives me error
$objInfo = $s3->get_object_headers($config['s3']['bucket'], "uploads/{$name}");
$obj = $s3->get_object($config['s3']['bucket'], "uploads/{$name}");
header('Content-type: ' . $objInfo->header['_info']['content_type']);
echo $obj->body;
error
PHP Catchable fatal error: Argument 2 passed to Aws\\AwsClient::getCommand() must be of the type array, string given, called in /php_workspace/s3_php/vendor/aws/aws-sdk-php/src/AwsClient.php on line 167 and defined in /php_workspace/s3_php/vendor/aws/aws-sdk-php/src/AwsClient.php on line 211, referer: http://localhost/upload.php
Simple way to do this:
include Amazon S3 PHP Class in you're project.
instantiate the class:
1. OO method (e,g; $s3->getObject(...)):
$s3 = new S3($awsAccessKey, $awsSecretKey);
2. Statically (e,g; S3::getObject(...)):
S3::setAuth($awsAccessKey, $awsSecretKey);
Then get Objects:
// Return an entire object buffer:
$object = S3::getObject($bucket, $uri));
var_dump($object);
Usually, the most efficient way to do this is to save the object to a file or resource
<?php
// To save it to a file (unbuffered write stream):
if (($object = S3::getObject($bucket, $uri, "/tmp/savefile.txt")) !== false) {
print_r($object);
}
// To write it to a resource (unbuffered write stream):
$fp = fopen("/tmp/savefile.txt", "wb");
if (($object = S3::getObject($bucket, $uri, $fp)) !== false) {
print_r($object);
}
?>
S3 Class -With Examples
S3 Class -Documentation
You can try this :
$bucket= "bucket-name";
$filetodownload = "name-of-the-file";
$resultbool = $s3->doesObjectExist ($bucket, $filetodownload );
if ($resultbool) {
$result = $client->getObject ( [
'Bucket' => $bucket,
'Key' => $filetodownload
] );
}
else
{
echo "file not found";die;
}
header ( "Content-Type: {$result['ContentType']}" );
header ( "Content-Disposition: attachment; filename=" . $filetodownload );
header ('Pragma: public');
echo $result ['Body'];
die ();