Excel Export Blank Sheet Problem - excel

I've had some code that has worked for years to export an html table to Excel. It goes like this-
private void ExcelExport ( string core_number )
{
// set response up for excel export
Response.Clear ();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader ( "content-disposition", "attachment;filename=TEST.xls" );
.. loops through generates an simple html table ...
Response.Write ( "</table>" );
Response.Flush ();
Response.End();
}
I noticed Firefox now shows the file as an XML document instead of a Excel document, and when I open the generated document it will parse fail. Also some users report having export problems in some older versions of IE, even though I'm not having any problems in IE on my end (shows as an Excel document and opens properly).
Anyone seen this one before? Thanks for your time.

didn't find an answer, but worked around it for now.

Related

Excel and Libre Office conflict over Open XML output

Open XML is generating .xlsx files that can be read by Open Office, but not by Excel itself.
With this as my starting point( Export DataTable to Excel with Open Xml SDK in c#) I have added code to create a .xlsx file. Attempting to open with Excel, I'm asked if I want to repair the file. Saying yes gets "The workbook cannot be opened or repaired by Microsoft Excel because it's corrupt." After many hours of trying to jiggle the data from my table to make this work, I finally threw up my hands in despair and made a spreadsheet with a single number in the first cell.
Still corrupt.
Renaming it to .zip and exploring shows intact .xml files. On a whim, I took a legit .xlsx file created by Excel, unzipped it, rezipped without changing contents and renamed back to .xlsx. Excel declared it corrupt. So this is clearly not a content issue, but file a format issue. Giving up on Friday, I sent some of the sample files home and opened them there with Libre Office. There were no issues at all. File content was correct and Calc had no problem. I'm using Excel for Office 365, 32 bit.
// ignore the bits (var list) that get data from the database. I've reduced this to just the output of a single header line
List< ReportFilingHistoryModel> list = DB.Reports.Report.GetReportClientsFullHistoryFiltered<ReportFilingHistoryModel>(search, client, report, signature);
MemoryStream memStream = new MemoryStream();
using (SpreadsheetDocument workbook = SpreadsheetDocument.Create(memStream, SpreadsheetDocumentType.Workbook))
{
var workbookPart = workbook.AddWorkbookPart();
workbook.WorkbookPart.Workbook = new Workbook();
workbook.WorkbookPart.Workbook.Sheets = new Sheets();
var sheetPart = workbook.WorkbookPart.AddNewPart<WorksheetPart>();
var sheetData = new SheetData();
sheetPart.Worksheet = new Worksheet(sheetData);
Sheets sheets = workbook.WorkbookPart.Workbook.GetFirstChild<Sheets>();
string relationshipId = workbook.WorkbookPart.GetIdOfPart(sheetPart);
uint sheetId = 1;
if (sheets.Elements<Sheet>().Count() > 0)
{
sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;
}
Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = "History" };
sheets.Append(sheet);
Row headerRow = new Row();
foreach( var s in "Foo|Bar".Split('|'))
{
var cell = new Cell();
cell.DataType = CellValues.Number;
cell.CellValue = new CellValue("5");
headerRow.AppendChild(cell);
}
sheetData.AppendChild(headerRow);
}
memStream.Seek(0, SeekOrigin.Begin);
Guid result = DB.Reports.Report.AddClientHistoryList( "test.xlsx", memStream.GetBuffer(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return Ok(result);
This should just work. I've noticed other stack overflow discussions that direct back to the first link I mentioned above. I seem to be doing it right (and Calc concurs). There have been discussions of shared strings and whatnot, but by using plain numbers I shouldn't be having issues. What am I missing here?
In working on this, I went with the notion that some extraneous junk on the end of a .zip file is harmless. 7-Zip, Windows Explorer and Libre Office all seem to agree (as does some other zip program I used at home whose name escapes me). Excel, however, does not. Using the pointer at memStream.GetBuffer() was fine, but using its length was not. (The preceding Seek() was unnecessary.) Limiting the write of the data to a length equal to the current output position keeps Excel from going off the rails.

QT Excel - Open to Read/Write

I'd like to know what's the best way to open excel file (.xlsx) (Need to write and read or eventually only read)
I've already tried this (it's only test):
void MainWindow::openExcel()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "xls_connection");
db.setDatabaseName("DRIVER={Microsoft Excel Driver (*.xls,*.xlsx,*.xlsm,*.xlsb)};DBQ=" + QString ("C:\\Users\\User\\Desktop\\file.xlsx") );
if(db.open())
{
QSqlQuery query("select * from [" + QString("Sheet1") + "$A1:B5]");
while (query.next())
{
//reading columns
QString column1= query.value(0).toString();
qDebug()<<column1;
}
db.close();
QSqlDatabase::removeDatabase("xls_connection");
}
else
{
qDebug()<<"Failed";
}
}
but it couldn't open such file ("Failed"). I would be glad if anyone could say where's a problem
//Maybe also recommend any good books or tutorials for QT?
To use ODBC for Excel on Windows, the MS Access Database Engine must be downloaded as mentioned in the wiki Note from which this sample code was tested (Win7/ qt4.9 , Win10/ qt 5.7) , then the connection can work. alternatively in the same Qt wiki Content, you can find different ways of opening MS Excel with Qt.
You can use ActivX object to work with excel file -
ActiveX Excel example
Other option to read-write into excel file format (.xlsx) -
QtXlsxWriter

PhpSpreadsheet is corrupting files

I am using PhpSpreadsheet to modify an existing file and send it to the browser, but every time I download the file excel gives me the following error:
We found a problem with some content in filename.xlsx. Do you want us to try and recover as much as we can? If you trust the source of this workbook, click Yes.
I have stripped back everything to the following code. The template file that I am opening is a brand new excel file, with no edits made to it (to avoid the potential that the error already exists in the template). I can open this file from the drive without any issues.
$spreadsheet = IOFactory::load(storage_path() ."\Template - English.xlsx");
// Redirect output to a client’s web browser (Xlsx)
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="filename.xlsx"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
Once I go through the repair process I get the following message from Excel, and everything seems to work fine.
Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded.
**EDIT: **
The same error occurs when I generate a new file using $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
I don't know if you solved your issue but I had the same.
My code looks like this :
$strFilename = sprintf('%s_%s_subscriptions', date('Y-m-d-H-i'), $alias);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$strFilename.'.xlsx"');
header('Cache-Control: max-age=0');
$writer = IOFactory::createWriter($objSpreadsheet, 'Xlsx');
$writer->save('php://output');
And Excel prompt the same error as you. But it looks like PHPSpreadSheet create a buffer and doesn't close it once you save the spreadsheet.
By adding a "die;" after the final line, it solved the issue...
So final code :
$strFilename = sprintf('%s_%s_subscriptions', date('Y-m-d-H-i'), $alias);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$strFilename.'.xlsx"');
header('Cache-Control: max-age=0');
$writer = IOFactory::createWriter($objSpreadsheet, 'Xlsx');
$writer->save('php://output');
die;
Hope it helps !
For me, the problem was generated by the dump () function, which added debug data to "php: // output" during export, the data was interpreted by PHPSpreadshet as part of the excel file
After removing everything worked
Just use exit() at the end.
ob_end_clean();
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
exit();

Export Excel Not Working in IPAD

I am working in the Excel export in c# .net. I am using the below code which is working fine in desktop and laptops.
homeServices = new HomeServices();
string htmlOutput = "";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.ContentType = "application/ms-excel";
HttpContext.Current.Response.Write(#"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">");
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=Export.xls");
HttpContext.Current.Response.Charset = "utf-8";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
htmlOutput = homeServices.ExportHomeData();
HttpContext.Current.Response.Write(htmlOutput);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
But when i use this in IPAD, i am getting the error like
Unable to Read Document. An error occurred while reading the document.
Whether the above code wont support IPAD.
Note : I had searched a lot and i dint find at least a related solution for this issue. For past 3 days i am searching..Kindly do help experts.
The above code will produce output in PC but, with one format warning, same is making problem in IPad.
You can use csv instead of Excel, you won't get error but still it will be opened in excel.
HttpContext.Current.Response.AppendHeader("Content-Type","application/CSV");
HttpContext.Current.Response.AppendHeader("Content-disposition", "attachment; filename=" + fileName + ".CSV");

How to work around the [1] IE bug while saving an excel file from a Web server?

I've noticed that Internet Explorer adds a number in square brackets to files downloaded from the internet (usually [1]). This creates a big problem with downloading Excel spreadsheets as square brackets are not a valid filename character inside Excel worksheet name. That problem is IE specific, others browsers are keeping same file name.
So, if you have a pivot table auto-refreshed on file opening for example, you'll get an error message saying the name "file[1].yourPivotTableName" is not valid.
Is there any solution to that problem ?
EDIT : It seems that whatever the filename suggested by HTTP directives, IE adds [1] in all cases, which cause the problem ! (So, answers about filenames aren't helpful in that case)
EDIT : I've tried some VBA code to save file under another name when it'll open. However, it doesn't work (same error message than before). Do you think there's a way to fix that with VBA ?
I've got it working using VBA provided by this cool guy (think of him fondly).
It renames the file and then reattaches the pivots.
http://php.kennedydatasolutions.com/blog/2008/02/05/internet-explorer-breaks-excel-pivot-tables/
I think that this happens when you open the spreadsheet in IE and IE saves it to a temporary file. And I think it only happens when the spreadsheet's filename has more than one dot in it. Try it with a simple "sample.xls".
Another workaround is to tell users to save the file to the desktop and then open it.
It's a built-in feature in Internet Explorer.
Stop using "Open", start using "Save" in the file-download window, otherwise IE will append "[1]" to filename of the file that it places in some temporary folder.
You could build some .NET application using System.IO.FileSystemWatcher that catches the event of the creation of the downloaded file or something and renames the file.
I have solved this issue by using method where we pass 3 parameters: Filename, file extension(without the .dot) and the HTTP request); then doing the UTF-8 encoding of the filename and extension.
Sample Code:
public static String encoding(String fileName, String extension, HttpServletRequest request)
{
String user = request.getHeader( "user-agent" );
boolean isInternetExplorer = ( user.indexOf( "MSIE" ) > -1 );
String var = "";
try
{
fileName = URLEncoder.encode( fileName, "UTF-8" );
fileName = fileName.trim().replaceAll( "\\+", " " );
extension = URLEncoder.encode( extension, "UTF-8" );
extension = extension.trim().replaceAll( "\\+", " " );
if ( isInternetExplorer )
{
disposition = "attachment; filename=\"" + fileName+"."+extension+"\"";
}
else
{
var = "attachment; filename*=UTF-8''" + fileName+"."+extension;
}
}
catch ( UnsupportedEncodingException ence )
{
var = "attachment; filename=\"" + fileName+"."+extension;
ence.printStackTrace();
}
return var;
}
This worked just fine in my case.
Hope it will help you all.
Actually, the correct .NET-code is as following:
Response.AppendHeader("content-disposition", "attachment;filename=file.xls");
Response.ContentType = "application/vnd.ms-excel";
Note: AppendHeader, not AddHeader, which I think only works in debug web-server and IIS7.
The following has worked for me:
private string EncodeFileName(string fileName)
{
fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", " ");
if (HttpContext.Current.Request.UserAgent.ToLower().Contains("msie"))
{
var res = new StringBuilder();
var chArr = fileName.ToCharArray();
for (var j = 0; j < chArr.Length; j++)
{
if (chArr[j] == '.' && j != fileName.LastIndexOf("."))
res.Append("%2E");
else
res.Append(chArr[j]);
}
fileName = res.ToString();
}
return "\"" + fileName + "\"";
}
You could just make sure that in the options box for the pivot the auto refresh is switched off. Now even when opened from the server the pivot will work perfectly
I have encountered the same problem and came up with (imo) a better solution that does not need any VBA.
If you set "Content-Disposition" header to "attachment; filename=<...>" instead of "inline; filename=<...>" the normal browsers will open dialog that will allow to save or open a file with a filename defined in a header, but Internet Explorer will behave in kind of weird way. It will open file download dialog and if you press Save it will suggest a filename that is defined in the header, but if you press Open it will save file to a temporary folder and open it with a name that is the same as your URN (without 'namespace'), e.g. if your URI is http://server/folder/file.html, so IE will save your file as file.html (no brackets, woo hoo!). This leads us to a solution:
Write a script that handles request from http://server/folder/* and when you need to serve an XLS file just redirect to that script (use your filename instead of asterisk) with Content-Disposition set to inline.
Put these four lines in your code:
response.reset();
response.setHeader("Expires", "0");
response.setHeader("Cache-Control","must-revalidate,post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
Hope this helps.
In .NET I have found from experience only this seems to work for me:
Response.AddHeader("Content-Disposition", "attachment; filename=excel.xls");
Response.AddHeader("Content-Type", "application/vnd.ms-excel");
Response.ContentType = "application/vnd.ms-excel";
The duplication smells, but so far I have never got to the bottom of it (maybe Sebs post explains this). Also the "content-Disposition" value appears very finicky use a : instead of a ; or ommit the space between it and 'filename' and it blows!
Also if you have compression enabled on IIS this may fix things for you:
Response.ClearHeaders()

Resources