Reading an Excel sheet which contains an image fails - phpspreadsheet

Using the following code, I want to open an existing Excel sheet:
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Helper\Sample;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$inputFileName = $_SERVER['DOCUMENT_ROOT'].$my_file;
$spreadsheet = $reader->load($inputFileName);
$sheet = $spreadsheet->getActiveSheet();
// ...Here i fill out some cells
// And then save the file with the same name (to overwrite)
$writer = new Xlsx($spreadsheet);
$writer->save($inputFileName);
But the following fault message is displayed:
Fatal error: Uncaught PhpOffice\PhpSpreadsheet\Writer\Exception:
File zip:///[...]/output/ciclo_pm_3_71_285_395.xlsx#xl/media/image1.jpeg
does not exist in [...]/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet
/Writer/Xlsx/ContentTypes.php:186 Stack trace: #0 [...]/vendor/phpoffice
/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/ContentTypes.php(126):
PhpOffice\PhpSpreadsheet\Writer
\Xlsx\ContentTypes->getImageMimeType('zip:///www/htdo...') #1 /[...]
/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php(223):
PhpOffice\PhpSpreadsheet\Writer
\Xlsx\ContentTypes->writeContentTypes(Object(PhpOffice\PhpSpreadsheet
\Spreadsheet), false) #2 [...]/ajax_stueli_einlesen.php(350):
PhpOffice\PhpSpreadsheet\Writer\Xlsx->save('/www/htdocs/w00...') #3 {main}
thrown in [...]/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer
/Xlsx/ContentTypes.php on line 186
When I remove the image from the Excel sheet, it works.
The fault seems to occur whem (over)writing the file.
Why does PHPSpreadsheet say "file not exists"? The file is part of the Excel-Sheet, so it DOES exists, doesn't it?
I'm helpless... ;-(
Can anyone help me?

I just had very same issue with the latest version of the PhpOffice\PhpSpreadsheet package.
As it turned out and as Daniel suggested, the issue happened, because I was trying to overwrite the template spreadsheet.
As soon as I created a new one, the problem vanished.

Related

How to avoid Excel "bad format error" when saving spreadsheet

Using PHPSpreadsheet saving XLSX format works OK running the default code
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save("filename.xlsx");
But if I want to have the user to select the target directory using
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="filename.xlsx"');
header('Cache-Control: max-age=0');
$writer = IOFactory::createWriter($spreadSheet, 'Xlsx');
$writer->save('php://output');
The file saves OK but Excel 2016 does not want to open it. Excel returns the following error
Excel Error
I looked through all documentation and posts but cannot find the solution.
Thanks !
Edit: Just in case, this solution does not work for me.
Edit 2: The sample provided Simple Download Xlsx works perfectly, but when doing a copy/paste for my spreadsheet, Chrome gives me a
Resource interpreted as Document but transferred with MIME type application/octet-stream
Edit 3: Used
ob_end_flush(); to clean any left over header in my code.
The file now saves OK, but needs repair when opening in Excel. Why ?
Thanks
Solution:
Bug from PhpSpreadsheet.
When using
header("Content-Type: application/vnd.ms-excel");
i.e. compatibility mode for Excel, the file opens OK.

Errors on System.IO.FileStream CSV file creation and System.IO.File.Delete

In an old VB.NET code (VS 2008) I use this code:
If System.IO.File.Exists(sFilePath) Then
System.IO.File.Delete(sFilePath)
End If
Dim Fs As New System.IO.FileStream(sFilePath, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write)
Fs.Close()
If the file exists then on this line:
System.IO.File.Delete(sFilePath)
I get this error:
The process cannot access the file because it is being used by another process.
When I manually remove the file, then on this line:
Dim Fs As New System.IO.FileStream(sFilePath, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write)
I get the error:
The file already exists
Although it doesn't.
The code always (for 8 years now) worked perfectly. Nothing in this part of the code has been changed.
So what is going on here?

Adding one more row to existing excel file in ruby

I am trying to simply add one more row to an existing excel file using spreadsheet gem.
test_url = "#{Rails.root}/data/Skipped_Records.xls"
if File.exists?(test_url)
book = Spreadsheet.open(test_url)
else
book = Spreadsheet::Workbook.new
book.create_worksheet
end
sheet = book.worksheet(0)
last_index = sheet.row(-1).idx
sheet.row(last_index + 1).concat [index, error]
book.write "#{Rails.root}/data/Skipped_Records.xls"
In first run the file is getting created fine.
But after second run, while opening the file LibreOffice says
Unknown or unsupported excel file format.
I am trying to migrate excel data into rails application using rake task. While doing it few rows are skipped because of certain errors. I am trying to log these skipped records.
Please help.

How to make a xls file a datasource for JasperReports?

I have a web page that returns a xls file.
I'm trying to use the output of the page as a datasource for JasperReports.
Right now I have something like
JRXlsDataSource ds = new JRXlsDataSource(JRLoader.getLocationInputStream("http://192.168.20.19/people/XLS.jsf"));
but I get this error
net.sf.jasperreports.engine.JRException: jxl.read.biff.BiffException: The input file was not found
How can I read the stream and then use it in the JasperPrint object?
Please refer the link below, it would provide a complete idea of XLS datasource for jasper report
http://jasperreports.sourceforge.net/sample.reference/xlsdatasource/index.html

Open XML SDK: opening a Word template and saving to a different file-name

This one very simple thing I can't find the right technique. What I want is to open a .dotx template, make some changes and save as the same name but .docx extension. I can save a WordprocessingDocument but only to the place it's loaded from. I've tried manually constructing a new document using the WordprocessingDocument with changes made but nothing's worked so far, I tried MainDocumentPart.Document.WriteTo(XmlWriter.Create(targetPath)); and just got an empty file.
What's the right way here? Is a .dotx file special at all or just another document as far as the SDK is concerned - should i simply copy the template to the destination and then open that and make changes, and save? I did have some concerns if my app is called from two clients at once, if it can open the same .dotx file twice... in this case creating a copy would be sensible anyway... but for my own curiosity I still want to know how to do "Save As".
I would suggest just using File.IO to copy the dotx file to a docx file and make your changes there, if that works for your situation. There's also a ChangeDocumentType function you'll have to call to prevent an error in the new docx file.
File.Copy(#"\path\to\template.dotx", #"\path\to\template.docx");
using(WordprocessingDocument newdoc = WordprocessingDocument.Open(#"\path\to\template.docx", true))
{
newdoc.ChangeDocumentType(WordprocessingDocumentType.Document);
//manipulate document....
}
While M_R_H's answer is correct, there is a faster, less IO-intensive method:
Read the template or document into a MemoryStream.
Within a using statement:
open the template or document on the MemoryStream.
If you opened a template (.dotx) and you want to store it as a document (.docx), you must change the document type to WordprocessingDocumentType.Document. Otherwise, Word will complain when you try to open the document.
Manipulate your document.
Write the contents of the MemoryStream to a file.
For the first step, we can use the following method, which reads a file into a MemoryStream:
public static MemoryStream ReadAllBytesToMemoryStream(string path)
{
byte[] buffer = File.ReadAllBytes(path);
var destStream = new MemoryStream(buffer.Length);
destStream.Write(buffer, 0, buffer.Length);
destStream.Seek(0, SeekOrigin.Begin);
return destStream;
}
Then, we can use that in the following way (replicating as much of M_R_H's code as possible):
// Step #1 (note the using declaration)
using MemoryStream stream = ReadAllBytesToMemoryStream(#"\path\to\template.dotx");
// Step #2
using (WordprocessingDocument newdoc = WordprocessingDocument.Open(stream, true)
{
// You must do the following to turn a template into a document.
newdoc.ChangeDocumentType(WordprocessingDocumentType.Document);
// Manipulate document (completely in memory now) ...
}
// Step #3
File.WriteAllBytes(#"\path\to\template.docx", stream.GetBuffer());
See this post for a comparison of methods for cloning (or duplicating) Word documents or templates.

Resources