Using an existing spreadsheet as a template PHPspreadsheet - phpspreadsheet

Objective
I want to use an existing Excel sheet, as a template to create an invoice.
Cell styling, such as coloring have to be included
An image (logo) has to be included
Standard data such as company address has to be included
I've read something about cfspreadsheet, but I'm not entirely sure how to use it.
Question A:
Is there a way to use a template file? Or do you know any alternatives?
Question B
Is it possible to use $_POST data with this library?
Example
$data = $_POST['example'];
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', '$data');

I am not 100% sure, but according to PhpSpreadsheet's doc, you can read a local file (your pre-made template) with :
$inputFileName = './sampleData/example1.xls';
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($inputFileName);
Or in case you already know the file type (.xlsx or .xsl) :
$inputFileType = 'Xls'; // Xlsx - Xml - Ods - Slk - Gnumeric - Csv
$inputFileName = './sampleData/example1.xls';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
You can also wrap all of that in a try catch if you want.
Then you just have to make changes the same way you would populate a Spreadsheet you created, populating cells with data you get from pretty much where you want with php, examples :
Classic variable $foo = 'bar';
$_GET / $_POST / $_REQUEST
From a Database

Related

PhpSpreadsheet: write entire workbook to file

I am reading an .xls template, and writing some data to the first sheet. When saving, I wish a copy of the entire workbook to be saved, but only the first sheet is being included.
How to save the entire workbook to file?
Existing code:
$template_file_type = IOFactory::identify($path);
$reader = IOFactory::createReader($template_file_type);
$excel_obj = $reader->load($path);
$excel_obj->setActiveSheetIndex(0);
$sheet = $excel_obj->getActiveSheet();
// writing to sheet
$objWriter = new Xlsx($excel_obj);
$objWriter->save($target_dir);
(Am aware I am reading .xls and writing .xlsx, but I haven't had trouble with that before...)

PHPSpreadsheet Fails to Save Line Chart Loaded From Template (Locked by 'another user')

I am running into a problem where phpspreadsheet will not write out a line chart from an xlsx file I'm using as a template.
I get two error messages when opening the spreadsheet:
We found a problem with some content in 'Hello World.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of the workbook, click Yes
Hello World.xlsx is locked for editing
by 'another user'
Open 'Read-Only' or click 'Notify' to open read-only and receive notification when the document is no longer in use.
<?php
// ... snip
$reader = IOFactory::createReader($inputFileType);
$reader->setIncludeCharts(true);
$spreadsheet = $reader->load($inputFileName);
// ... snip
// populate chart data
$sheet = $spreadsheet->getSheetByName('Ratios');
// reverse order, so populate "backwards"
for($endingRow = 14; ($endingRow > 1) && ($row = $last13Ratios->nextRecord()); $endingRow--) {
$sheet->setCellValue('A'.$endingRow, $row->date);
$sheet->setCellValue('B'.$endingRow, $row->percent60/100);
$sheet->setCellValue('C'.$endingRow, $row->percent90/100);
$helper->log(print_r($row));
}
// ... snip
$writer = new XlsxWriter($spreadsheet);
$writer->setIncludeCharts(true);
$callStartTime = microtime(true);
$writer->save($saveFileName);
$helper->logWrite($writer, $saveFileName, $callStartTime);
$spreadsheet->disconnectWorksheets();
die();
If I put fake data in the template, it appears to work. But I don't want fake data, just in case something goes haywire. Better to have no information than wrong information.
The short answer is to put a space ' in the upper left cell of the section being used for data in the template.
Note that the data type appears to make a difference, also: a date instead of a string will fail.
Be sure to use the single quote mark to designate it as a string, otherwise excel will ignore the space when you save it.

How to read Microsoft Word Binary Data from database and convert it to readable text

I'm working in a java application called Mirth where I need to read a saved word document that is saved in a database table in a Microsoft word binary data format. Currently I can retrieve data from column in my java application but I need to convert this to readable text or XML or HTML format.
Looking online there is a java library call Aspose.words but I can't find any methods that would read in this binary data and convert it to something readable. Has anyone use Aspose.words before to do a task like this or does anyone have an alternative solution
Load document from Database
You can load the Word document using ByteArrayInputStream, if it's in a database table. Please refer to http://www.aspose.com/docs/display/wordsjava/How+to++Load+and+Save+a+Document+to+Database for an article that explains saving and reading a Word document to/from database. I have copied the relevant code from there.
public static Document readFromDatabase(String fileName) throws Exception
{
// Create the SQL command.
String commandString = "SELECT * FROM Documents WHERE FileName='" + fileName + "'";
// Retrieve the results from the database.
ResultSet resultSet = executeQuery(commandString);
// Check there was a matching record found from the database and throw an exception if no record was found.
if(!resultSet.isBeforeFirst())
throw new IllegalArgumentException(MessageFormat.format("Could not find any record matching the document \"{0}\" in the database.", fileName));
// Move to the first record.
resultSet.next();
// The document is stored in byte form in the FileContent column.
// Retrieve these bytes of the first matching record to a new buffer.
byte[] buffer = resultSet.getBytes("FileContent");
// Wrap the bytes from the buffer into a new ByteArrayInputStream object.
ByteArrayInputStream newStream = new ByteArrayInputStream(buffer);
// Read the document from the input stream.
Document doc = new Document(newStream);
// Return the retrieved document.
return doc;
}
Read text
Once the file is loaded, you can read it's paragraphs, tables, images etc using DOM, see the related documentation at http://www.aspose.com/docs/display/wordsjava/Programming+with+Documents.
But, if you just want to get all the text from a document, you can do it easily by calling toString() method as below
System.out.println(doc.toString(SaveFormat.TEXT));
I work with Aspose as Developer Evangelist.

New Google Spreadsheets publish limitation

I am testing the new Google Spreadsheets as there is a new feature I really need: the 200 sheets limit has been lifted (more info here: https://support.google.com/drive/answer/3541068).
However, I can't publish a spreadsheet to CSV like you can in the old version. I go to 'File>Publish to the web' and there is no more options to publish 'all sheets' or certain sheets and you can't specify cell ranges to publish to CSV etc.
This limitation is not mentioned in the published 'Unsupported Features' documentation found at: https://support.google.com/drive/answer/3543688
Is there some other way this gets enabled or has it in fact been left out of the new version?
My use case is: we retrieve Bigquery results into the spreadsheets, we publish the sheets as a CSV automatically using the "publish automatically on update" feature which then produces the CSV URL which gets placed into charting tools that read the CSV URL to generate the visuals.
Does anyone know how to do this?
The new Google spreadsheets use a different URL (just copy your <KEY>):
New sheet : https://docs.google.com/spreadsheets/d/<KEY>/pubhtml
CSV file : https://docs.google.com/spreadsheets/d/<KEY>/export?gid=<GUID>&format=csv
The GUID of your spreadsheet relates to the tab number.
/!\ You have to share your document using the Anyone with the link setting.
Here is the solution, just write it like this:
https://docs.google.com/spreadsheets/d/<KEY>/export?format=csv&id=<KEY>
I know it's weird to write the KEY twice, but it works perfectly. A teammate from work discovered this by opening the excel file in Google Docs, then File -> Download as -> Comma separated values. Then, in the downloads section of the browser appears a link to the CSV file, like this:
https://docs.google.com/spreadsheets/d/<KEY>/export?format=csv&id=<KEY>&gid=<SOME NUMBER>
But it doesn't work in this format, what my friend did was remove "&gid=<SOME NUMBER>" and it worked! Hope it helps everyone.
If you enable "Anyone with the link sharing" for spreadsheet, here is a simple method to get range of cells or columns (or whatever your feel like) export in format of HTML, CSV, XML, JSON via the query:
https://docs.google.com/spreadsheet/tq?key=YOUR-KEY&gid=1&tq=select%20A,%20B&tqx=reqId:1;out:html;%20responseHandler:webQuery
For tq variable read query language reference.
For tqx variable read request format reference.
Downside to this is that your doc is still availble in full via the public link, but if you want to export/import data to say Excel this is a perfect way.
It's not going to help everyone, but I've made a PHP script to read the HTML into an array.
I've added converting back to a CSV at the end. Hopefully this will help some people who have access to PHP.
$html_link = "https://docs.google.com/spreadsheets/d/XXXXXXXXXX/pubhtml";
$local_html = "sheets.html";
$file_contents = file_get_contents($html_link);
file_put_contents($local_html,$file_contents);
$dom = new DOMDocument();
$html = #$dom->loadHTMLFile($local_html); //Added a # to hide warnings - you might remove this when testing
$dom->preserveWhiteSpace = false;
$tables = $dom->getElementsByTagName('table');
$rows = $tables->item(0)->getElementsByTagName('tr');
$cols = $rows->item(0)->getElementsByTagName('td'); //You'll need to edit the (0) to reflect the row that your headers are in.
$row_headers = array();
foreach ($cols as $i => $node) {
if($i > 0 ) $row_headers[] = $node->textContent;
}
foreach ($rows as $i => $row){
if($i == 0 ) continue;
$cols = $row->getElementsByTagName('td');
$row = array();
foreach ($cols as $j => $node) {
$row[$row_headers[$j]] = $node->textContent;
}
$table[] = $row;
}
//Convert to csv
$csv = "";
foreach($table as $row_index => $row_details){
$comma = false;
foreach($row_details as $value){
$value_quotes = str_replace('"', '""', $value);
$csv .= ($comma ? "," : "") . ( strpos($value,",")===false ? $value_quotes : '"'.$value_quotes.'"' );
$comma = true;
}
$csv .= "\r\n";
}
//Save to a file and/or output
file_put_contents("result.csv",$csv);
print $csv;
Here is another temporary, non-PHP workaround:
Go to an existing NEW google sheet
Go to "File -> New -> Spreadsheet"
Under "File -> Publish to the web..." now has the option to publish a csv version
I believe this is actually creating an old Google sheet but for my purposes (importing google sheet data from clients or myself into R for statistical analysis) it works until they hopefully update this feature.
I posted this in a Google Groups forum also, please find it here:
https://productforums.google.com/forum/#!topic/docs/An-nZtjaupU
The correct URL for downloading a Google spreadsheet as CSV is:
https://docs.google.com/spreadsheets/export?id=<ID>&exportFormat=csv
The current answers do not work anylonger. The following has worked for me:
Do File -> "Publish to the web" and select 'start publishing' and the format. I choose text (which is TSV)
Now just copy the URL there which will be similar to https://docs.google.com/spreadsheet/pub?key=YOUR_KEY&single=true&gid=0&output=txt
That new feature appears to have disappeared. I don't see any option to publish a csv/tsv version. I can download tsv/csv with the export, but that's not available to other people with merely the link (it redirects them to a google docs sign-in form).
I found a fix! So I discovered that old spreadsheets before this change were still allowing only publishing certain sheets. So I made a copy of an old spreadsheet, cleared the data out, copy and pasted my current info into it and now I'm happily publishing just a single sheet of my large spreadsheet. Yay
I was able to implement a query to the result, see this table
https://docs.google.com/spreadsheets/d/1LhGp12rwqosRHl-_N_N8eTjTwfFsHHIBHUFMMyhLaaY/gviz/tq?tq=select+A,B,I,J,K+where+B%3E=4.5&pli=1
the spreadsheet fetches data from earthquake, but I just want to select MAG 4.5+ earthquakes so it makes the query and the columns, just a problem:
I cannot parse the result, I tried to decode as json but was not able to parse it.
I would like to be able to show this as HTML or CSV or how to parse this ? for example to be able to plot it on a Google Map.

Create and download word file from template in MVC

I have kept a word document (.docx) in one of the project folders which I want to use as a template.
This template contains custom header and footer lines for user. I want to facilitate user to download his own data in word format. For this, I want to write a function which will accept user data and referring the template it will create a new word file replacing the place-holders in the template and then return the new file for download (without saving it to server). That means the template needs to be intact as template.
Following is what I am trying. I was able to replace the placeholder. However, I am not aware of how to give the created content as downloadable file to user. I do not want to save the new content again in the server as another word file.
public void GenerateWord(string userData)
{
string templateDoc = HttpContext.Current.Server.MapPath("~/App_Data/Template.docx");
// Open the new Package
Package pkg = Package.Open(templateDoc, FileMode.Open, FileAccess.ReadWrite);
// Specify the URI of the part to be read
Uri uri = new Uri("/word/document.xml", UriKind.Relative);
PackagePart part = pkg.GetPart(uri);
XmlDocument xmlMainXMLDoc = new XmlDocument();
xmlMainXMLDoc.Load(part.GetStream(FileMode.Open, FileAccess.Read));
xmlMainXMLDoc.InnerXml = ReplacePlaceHoldersInTemplate(userData, xmlMainXMLDoc.InnerXml);
// Open the stream to write document
StreamWriter partWrt = new StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write));
xmlMainXMLDoc.Save(partWrt);
partWrt.Flush();
partWrt.Close();
pkg.Close();
}
private string ReplacePlaceHoldersInTemplate(string toReplace, string templateBody)
{
templateBody = templateBody.Replace("#myPlaceHolder#", toReplace);
return templateBody;
}
I believe that the below line is saving the contents in the template file itself, which I don't want.
xmlMainXMLDoc.Save(partWrt);
How should I modify this code which can return the new content as downloadable word file to user?
I found the solution Here!
This code allows me to read the template file and modify it as I want and then to send response as downloadable attachment.

Resources