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.
Related
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']);
}
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 am using PHP to create a simple .csv from database entries in Laravel, here's a little sample of the code:
$file = fopen(storage_path('file.csv'), 'w');
//$printer = array from database
foreach ($printer as $row) {
fputcsv($file, $row);
}
fclose($file);
//$formname = Object values
$headers = array(
'Content-Type: text/csv',
'Content-Length: ' . filesize(storage_path('file.csv')),
'Content-Disposition: attachment; filename="'.$formname->name.'.csv"'
);
return Response::download(storage_path('file.csv'), $formname->name.'.csv', $headers);
All pretty standard and work's fine for me, but my Client is using OS X 10.9.3 & Safari 7.0.4 and each download is given a .txt extension and I can't find a way to stop it from either server or client side. (so it downloads as file.csv.txt)
I have searched Google but can only find other users with the problem - no solution, the code above is already edited using suggestions found on Stackoverflow:
1. laravel adding .txt on the downloaded file
2. How to use the CSV MIME-type?
Can anyone tell me where this problem arises and how to fix it?
And is there anywhere I can test the download as I only have Windows and the testing websites I use only provide visual renders.
Also: The client has assured me he can download .csv's from other sources without this problem
As I can see Symfony iterates through the headers as key-value pairs:
public function __construct(array $headers = array())
{
foreach ($headers as $key => $values) {
$this->set($key, $values);
}
}
And then sets them this way:
if (true === $replace || !isset($this->headers[$key])) {
$this->headers[$key] = $values;
} else {
$this->headers[$key] = array_merge($this->headers[$key], $values);
}
So if you only have values in the $headers array with numeric indexes, the result might be unexpected. Try to change your code to this:
$headers = array(
'Content-Type' => 'text/csv',
'Content-Length' => filesize(storage_path('file.csv')),
'Content-Disposition' => 'attachment; filename="'.$formname->name.'.csv"'
);
I am trying to write APIC picture to mp3 file with getid3. here is the code;
$cover = "/home/user/public_html/artwork/cover.jpg";
$TagData['attached_picture'][]=array(
'picturetypeid'=>2, // Cover. More: module.tag.id3v2.php -> function APICPictureTypeLookup
'description'=>'cover', // text field
'mime'=>'image/jpeg', // Mime type image
'data'=>$cover // Image data
);
but it doesnt work. image size is around 1.5 MB. should i resize it or sth ?
where am i wrong ?
Thanks
Looking at the demo they have on their website: http://www.getid3.org/source/demo.write.phps
snippet of code:
$fd = fopen($_FILES['userfile']['tmp_name'], 'rb')
$APICdata = fread($fd, filesize($_FILES['userfile']['tmp_name']));
fclose ($fd);
$imagetypes = array(1=>'gif', 2=>'jpeg', 3=>'png');
if (isset($imagetypes[$APIC_imageTypeID])) {
$TagData['attached_picture'][0]['data'] = $APICdata;
$TagData['attached_picture'][0]['picturetypeid'] = $_POST['APICpictureType'];
$TagData['attached_picture'][0]['description'] = $_FILES['userfile']['name'];
$TagData['attached_picture'][0]['mime'] = 'image/'.$imagetypes[$APIC_imageTypeID];
}
Seems like the data key needs to be the image content, not just the path to the image file.
So in your case, it should be something like:
$cover = "/home/user/public_html/artwork/cover.jpg";
$fd = fopen($cover, 'rb')
$APICdata = fread($fd, filesize($coverFile));
fclose ($fd);
$TagData['attached_picture'][]=array(
'picturetypeid'=>2, // Cover. More: module.tag.id3v2.php -> function APICPictureTypeLookup
'description'=>'cover', // text field
'mime'=>'image/jpeg', // Mime type image
'data'=>$APICdata // Image data
);
Note: This is just after a quick glance at the demo code, I have not used this library or tested this code.
GetID3 needs the content of the file to be send for the data, not the file path. Then only it will be able to embed them into the file. Try
$cover = "/home/user/public_html/artwork/cover.jpg";
$TagData['attached_picture'][]=array(
'picturetypeid'=>2, // Cover. More: module.tag.id3v2.php -> function APICPictureTypeLookup
'description'=>'cover', // text field
'mime'=>'image/jpeg', // Mime type image
'data'=> file_get_contents($cover) // Image data; not the file name
);
tested and working :)
I found this in the source code:
case 'APIC':
// 4.14 APIC Attached picture
// Text encoding $xx
// MIME type <text string> $00
// Picture type $xx
// Description <text string according to encoding> $00 (00)
// Picture data <binary data>
So picture data must be binary.
The solution is here: getid3 demo
This one is working for me for long time:
$TagData = array(); //your other tags
$fd = fopen($albumPath, 'rb');
$APICdata = fread($fd, filesize($albumPath));
fclose($fd);
if($APICdata) {
$TagData += array(
'attached_picture' => array(0 => array(
'data' => $APICdata,
'picturetypeid' => '0x03',
'description' => 'cover',
'mime' => image_type_to_mime_type($albumExifType)
))
);
}
//and write the tags to file
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info#getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// //
// /demo/demo.simple.write.php - part of getID3() //
// Sample script showing basic syntax for writing tags //
// See readme.txt for more details //
// ///
/////////////////////////////////////////////////////////////////
//die('Due to a security issue, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in '.$_SERVER['PHP_SELF']);
$TextEncoding = 'UTF-8';
$albumPath = "img/img.jpg"; // path to your image
require_once('../getid3/getid3.php');
// Initialize getID3 engine
$getID3 = new getID3;
$getID3->setOption(array('encoding'=>$TextEncoding));
require_once('../getid3/write.php');
// Initialize getID3 tag-writing module
$tagwriter = new getid3_writetags;
//$tagwriter->filename = '/path/to/file.mp3';
$tagwriter->filename = 'uploads/problem.mp3';
//$tagwriter->tagformats = array('id3v1', 'id3v2.3');
$tagwriter->tagformats = array('id3v2.3');
// set various options (optional)
$tagwriter->overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data (experimental)
$tagwriter->remove_other_tags = false; // if true removes other tag formats (e.g. ID3v1, ID3v2, APE, Lyrics3, etc) that may be present in the file and only write the specified tag format(s). If false leaves any unspecified tag formats as-is.
$tagwriter->tag_encoding = $TextEncoding;
$tagwriter->remove_other_tags = true;
// populate data array
$TagData = array(
'title' => array('My Song'),
'artist' => array('My Song'),
'album' => array('My Song'),
'year' => array('20015'),
'genre' => array('My Song'),
'comment' => array('My Song'),
'track' => array('01'),
);
$fd = fopen($albumPath, 'rb');
$APICdata = fread($fd, filesize($albumPath));
fclose($fd);
if($APICdata) {
$TagData += array(
'attached_picture' => array(0 => array(
'data' => $APICdata,
'picturetypeid' => '0x03',
'description' => 'cover',
'mime' => image_type_to_mime_type(#$albumExifType)
))
);
}
$tagwriter->tag_data = $TagData;
// write tags
if ($tagwriter->WriteTags()) {
echo 'Successfully wrote tags<br>';
if (!empty($tagwriter->warnings)) {
echo 'There were some warnings:<br>'.implode('<br><br>', $tagwriter->warnings);
}
} else {
echo 'Failed to write tags!<br>'.implode('<br><br>', $tagwriter->errors);
}
For anyone who just needd to update their ID3 tags including the Album Art , above code works just fine You need to have getID3 library to work .
This Answer is based on JacopKane's Answer so credit goes to him