How to ignore first row (header row) on insert using PhpOffice\PhpSpreadsheet - phpspreadsheet

I am looking for a way to ignore first row which is the header row when inserting data into mysql database using PhpOffice\PhpSpreadsheet.I have followed this but not workingSkip First Row in PHPSpreadsheet ImportMy problem is how to ignore the header row?
Below is my clean code...
use Phppot\DataSource;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
require_once ('./vendor/autoload.php');
if (isset($_POST["import"])) {
$allowedFileType = [
'application/vnd.ms-excel',
'text/xls',
'text/xlsx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
];
if (in_array($_FILES["file"]["type"], $allowedFileType)) {
$date = date('Y-m-d');
$targetPath = 'uploads/'.$date." ".$_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], $targetPath);
$Reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
if($Reader) {
$Reader->setReadDataOnly(true);
$spreadSheet = $Reader->load($targetPath);
$sheetData = $spreadSheet->getActiveSheet()->toArray();
// Loop through the rows from xlsx file for insert
foreach($sheetData as $row) {
// get columns in a contigeous order from xlsx file
$regno = isset($row[0]) ? $row[0] : "";
$fullname = isset($row[1]) ? $row[1] : "";
$course = isset($row[2]) ? $row[2] : "";
$status = 1;
$pin = strtoupper(substr(md5(mt_rand()), 0, 10));
// Insert into db
$fieUploaded = $conn->itStudentsFileUpload($regno,$fullname,$course,$pin,$current_session,$status);
// If all is well send success message
if ($fieUploaded) {
echo "Success";
}
}
}
} else {
$type = "error";
$message = "Invalid File Type. Upload Excel File.";
}
}

After several tests, I solve the problem as follows:
class FirstRowFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter
{
public function readCell($column, $row, $worksheetName = '') {
// Return true for rows after first row
return $row > 1;
}
}
$Reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xlsx");
$filterRow = new FirstRowFilter();
$Reader->setReadFilter($filterRow);
$spreadSheet = $Reader->load($targetPath);
$sheetData = $spreadSheet->getActiveSheet()->toArray();
Note:
If you have additional fields that are not from the excel file eg. date, you need to check for emptiness of the first row from the excel file and then insert if not empty to ignore inserting empty values.

Related

How to use "content disposition attachment" in OpenXml

I have an ASP.NET MVC 4 site that creates an Excel file using OPEN XML SDK. My controller method generates the OPEN XML Excel document and is downloading it.
But the user should see the Excel file in the browser.
I know
Response.AddHeader("content-disposition", "attachment; filename=" + fileName + "");
is responsible for it. But I don't know how to implement this in openXnl method. I am not using http response here. Or how can I use it? Please help me on this
This is my Excel generating method, and I tried to implement AddHeader "content-disposition" but nothing works:
public static void GenerateExcelOpenXML(string FolderPath, DataSet tableSet)
{
WorkbookPart wBookPart = null;
var datetime = DateTime.Now.ToString().Replace("/", "_").Replace(":", "_");
string FilePath = FolderPath + "Report_" + datetime + ".xlsx";
using (SpreadsheetDocument spreadsheetDoc = SpreadsheetDocument.Create(FilePath, SpreadsheetDocumentType.Workbook))
{
wBookPart = spreadsheetDoc.AddWorkbookPart();
wBookPart.Workbook = new Workbook();
uint sheetId = 1;
spreadsheetDoc.WorkbookPart.Workbook.Sheets = new Sheets();
Sheets sheets = spreadsheetDoc.WorkbookPart.Workbook.GetFirstChild<Sheets>();
WorkbookStylesPart wbsp = wBookPart.AddNewPart<WorkbookStylesPart>();
wbsp.Stylesheet = CreateStylesheet();
wbsp.Stylesheet.Save();
foreach (DataTable table in tableSet.Tables)
{
WorksheetPart wSheetPart = wBookPart.AddNewPart<WorksheetPart>();
Sheet sheet = new Sheet() { Id = spreadsheetDoc.WorkbookPart.GetIdOfPart(wSheetPart),
SheetId = sheetId, Name = table.TableName };
sheets.Append(sheet);
SheetData sheetData = new SheetData();
wSheetPart.Worksheet = new Worksheet();
Row headerRow = new Row();
Columns columns = new Columns();
int ColumnNumber = 1;
foreach (DataColumn column in table.Columns)
{
Cell cell = new Cell();
cell.DataType = CellValues.String;
cell.CellValue = new CellValue(column.ColumnName);
cell.StyleIndex = 2;
headerRow.AppendChild(cell);
Column column1 = new Column();
column1.Width = 30;
column1.Min = Convert.ToUInt32(ColumnNumber);
column1.Max = Convert.ToUInt32(ColumnNumber);
column1.CustomWidth = true;
columns.AppendChild(column1);
ColumnNumber = ColumnNumber + 1;
}
wSheetPart.Worksheet.AppendChild(columns);
sheetData.AppendChild(headerRow);
foreach (DataRow dr in table.Rows)
{
Row row = new Row();
foreach (DataColumn column in table.Columns)
{
Cell cell = new Cell();
cell.DataType = CellValues.String;
cell.CellValue = new CellValue(dr[column].ToString());
cell.StyleIndex = 1;
row.AppendChild(cell);
}
sheetData.AppendChild(row);
}
sheetId++;
wSheetPart.Worksheet.AppendChild(sheetData);
// sheetData.AddHeader("content-disposition", "attachment; filename=" + fileName + "");
// how can I implement here?
}
}
}

How to read both .xsl and .xlsx using POI?

I have tried POI versions
1.poi-src-3.9-20121203 also with
2.poi-bin-3.10-beta2-20130904
But not able to read .xls file
Getting below error
"
org.apache.poi.POIXMLException: org.apache.poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]"
Note:I am able to read .xlsx file.
This is for .xlsx
try {
// Get the workbook object for XLSX file
XSSFWorkbook wBook = new XSSFWorkbook(new FileInputStream(path));
// Get first sheet from the workbook
XSSFSheet sheet = (XSSFSheet) wBook.getSheetAt(0);
XSSFRow row;
XSSFCell cell;
// Iterate through each rows from first sheet
Iterator<org.apache.poi.ss.usermodel.Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
StringBuffer data = new StringBuffer();
row = (XSSFRow) rowIterator.next();
// For each row, iterate through each columns
Iterator<Cell> cellIterator = row.cellIterator();
int count = 0;
while (cellIterator.hasNext()) {
count++;
cell = (XSSFCell) cellIterator.next();
if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC)
{
data.append(cell.getRawValue()+ ";");
}else if(cell.getCellType() == Cell.CELL_TYPE_BOOLEAN)
{
data.append(cell.getBooleanCellValue() + ";");
} else if(cell.getCellType() == Cell.CELL_TYPE_STRING)
{
data.append(cell.getStringCellValue() + ";");
}
else if(cell.getCellType() == Cell.CELL_TYPE_BLANK)
{
data.append("" + ";");
}
else
{
data.append(cell + ";");
}
}
String finalStr = data.toString().substring(0, (data.length()-1));
System.out.print(finalStr);
}
} catch (Exception ioe) {
ioe.printStackTrace();
}
Thia is for .xls
try {
// Get the workbook object for XLS file
HSSFWorkbook wBook = new HSSFWorkbook(new FileInputStream(path));
// Get first sheet from the workbook
HSSFSheet sheet = (HSSFSheet) wBook.getSheetAt(0);
HSSFRow row;
HSSFCell cell;
// Iterate through each rows from first sheet
Iterator<org.apache.poi.ss.usermodel.Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
StringBuffer data = new StringBuffer();
row = (HSSFRow) rowIterator.next();
// For each row, iterate through each columns
Iterator<Cell> cellIterator = row.cellIterator();
int count = 0;
while (cellIterator.hasNext()) {
count++;
cell = (HSSFCell) cellIterator.next();
if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC)
{
data.append(cell.getRawValue()+ ";");
}else if(cell.getCellType() == Cell.CELL_TYPE_BOOLEAN)
{
data.append(cell.getBooleanCellValue() + ";");
} else if(cell.getCellType() == Cell.CELL_TYPE_STRING)
{
data.append(cell.getStringCellValue() + ";");
}
else if(cell.getCellType() == Cell.CELL_TYPE_BLANK)
{
data.append("" + ";");
}
else
{
data.append(cell + ";");
}
}
String finalStr = data.toString().substring(0, (data.length()-1));
System.out.print(finalStr);
}
} catch (Exception ioe) {
ioe.printStackTrace();
}
Try using org.apache.poi.ss.usermodel.Workbook. It can be used for both .xls and .xlsx file
Workbook workbook = null;
if (suffix.equalsIgnoreCase("xls")) {
workbook = (Workbook) new HSSFWorkbook(new POIFSFileSystem(
new FileInputStream(assetFile)));
} else if (suffix.equalsIgnoreCase("xlsx")) {
InputStream inp = new FileInputStream(assetFile);
workbook = new XSSFWorkbook(inp);
inp.close();
}
You need poi-ooxml to read xlsx format too.
Add this Maven dependency
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
For xls use
Workbook = new HSSFWorkbook(new FileInputStream(new File("fileName")));
For xlsx use
Workbook = workbook = new XSSFWorkbook(new FileInputStream(new File("fileName")));
If you don't know the file format before reading and sometimes finding .xls or .xlsx file extension may not be always good enough to find the actual file format. In that case do like this
Workbook workbook;
try {
workbook = new HSSFWorkbook(new FileInputStream(new File("fileName")));
System.out.println(" Reading XLS file");
} catch (OfficeXmlFileException e) {
System.out.println(" Reading XLSX file");
workbook = new XSSFWorkbook(new FileInputStream(new File("fileName")));
}
Rest is all the same .xls and .xlsx
An easier way to create workbook by autodetecting the input is
Workbook workbook = WorkbookFactory.create(new File("fileName"));

Checking how many fields have changed upon saving a form

I am saving records in a transaction using symfony1.4 and Doctrine.
The rows inserted are coming from a CSV file which is updated regularly. I have already got a method that checks if the records in the CSV match that in the DB and do not insert.
What I'm ideally wanting to do though, is to set a user flash telling them how many rows have been updated whenever they import the CSV file.
$conn = ProductTable::getInstance()->getConnection();
$conn->beginTransaction();
try {
$row = 1;
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
if ($row > 1) {
$values = array(
'blah' => null
);
$obj= ProductTable::getInstance()->findOrCreateNewProduct(
$values['blah']
);
$obj->merge($values);
$obj->save($conn);
}
$row++;
}
$conn->commit();
} catch (Doctrine_Exception $e) {
$conn->rollback();
throw $e;
}
I'm wondering how I'd get these updated fields. Is it in the actions.class.php or is it in the actual form.class.php file?
Thanks
On the you can call a Doctrine_Record::getModified() which will give you an array of fields modified (with their values though that doesnt matter for you). Then you can call count on the returned array and keep a cumulative total outside your loop.
$conn = ProductTable::getInstance()->getConnection();
$conn->beginTransaction();
$nbModified = 0;
try {
$row = 1;
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
if ($row > 1) {
$values = array(
'blah' => null
);
$obj= ProductTable::getInstance()->findOrCreateNewProduct(
$values['blah']
);
$obj->merge($values);
$nbModified += count($obj->getModified());
$obj->save($conn);
}
$row++;
}
$conn->commit();
// return $nbModified or otherwise do something with it here
} catch (Doctrine_Exception $e) {
$conn->rollback();
// youre rolling back so just for consistency set $nbModified to zero
$nbModified = 0;
throw $e;
}

How do I get an in-memory chart (or image) into an in-memory OpenXML document?

I'm having a nightmare of a time trying to add a Chart to a MemoryStream in-memory.
I'm creating a Word document on the fly using OpenXML and I have a chart that is also being dynamically generated from data in the database.
I get the template from the database as a byte array, passing that into a method that also takes a business object that holds a bunch of data to populate bookmarks held within that template.
Here's the method:
public Stream Parse(byte[] array, AudiometryReport AudReport)
{
using (MemoryStream Stream = new MemoryStream())
{
Stream.Write(array, 0, (int)array.Length);
Stream.Position = 0;
using (document = WordprocessingDocument.Open(Stream, true))
{
XDocument doc = document.MainDocumentPart.GetXDocument();
List<XElement> bookmarks = doc.Descendants()
.Where(n => n.NodeType == XmlNodeType.Element && n.Name.LocalName == "bookmarkStart")
.ToList();
PropertyInfo[] reportInfo = AudReport.GetType().GetProperties();
foreach (XElement bm in bookmarks)
{
try
{
if (bm.LastAttribute.Value == "AudiometryChart")
{
string partId = InsertImage(document.MainDocumentPart);
var element = AddImageToDocument(document.MainDocumentPart, partId);
//var element = InsertImageXElement(partId);
//bm.ReplaceWith(new XElement(w + "r", element));
}
else
{
string val = reportInfo.Single(x => x.Name == bm.LastAttribute.Value).GetValue(AudReport, null).ToString();
bm.ReplaceWith(new XElement(w + "r",
new XElement(w + "t", val)));
}
}
catch
{ }
}
document.MainDocumentPart.PutXDocument();
//foreach (BookmarkStart bm in (IEnumerable<BookmarkStart>)document.MainDocumentPart.Document.Descendants<BookmarkStart>())
//{
// if (bm.Name == "AudiometryChart")
// {
// // Insert the chart object here.
// //AddImage(document);
// }
// populateStaffDetails(AudReport.Report.Employee, bm);
// populateAudiometryDetails(AudReport, bm);
//}
}
MemoryStream s = new MemoryStream();
Stream.WriteTo(s);
s.Position = 0;
return s;
}
}
The InsertImage image takes the MainDocumentPart and attaches a new ImagePart from the image I stream from the database. I pass the ID of that part back to the calling method.
private string InsertImage(MainDocumentPart docPart)
{
//DrawingsPart dp = docPart.AddNewPart<DrawingsPart>();
//ImagePart part = dp.AddImagePart(ImagePartType.Png, docPart.GetIdOfPart(dp));
ImagePart part = docPart.AddImagePart(ImagePartType.Png);
Chart cht = new ChartBuilder().DoChart(Data, new string[] { "Left", "Right", "Normal" });
using (MemoryStream ms = new MemoryStream())
{
cht.SaveImage(ms, ChartImageFormat.Png);
ms.Position = 0;
part.FeedData(ms);
}
//int count = dp.ImageParts.Count<ImagePart>();
int count = docPart.ImageParts.Count<ImagePart>();
return docPart.GetIdOfPart(part);
}
The last part is some serious nastiness that is allegdly required to add one image to one word document, but what the hell - here it is anyway:
private Run AddImageToDocument(MainDocumentPart docPart, string ImageRelId)
{
string ImageFileName = "Audiometry Chart Example";
string GraphicDataUri = "http://schemas.openxmlformats.org/drawingml/2006/picture";
long imageLength = 990000L;
long imageHeight = 792000L;
var run = new Run(
new Drawing(
new wp.Inline(
new wp.Extent() { Cx = imageLength, Cy = imageHeight },
new wp.EffectExtent()
{
LeftEdge = 19050L,
TopEdge = 0L,
RightEdge = 9525L,
BottomEdge = 0L
},
new wp.DocProperties()
{
Id = (UInt32Value)1U,
Name = "Inline Text Wrapping Picture",
Description = ImageFileName
},
new wp.NonVisualGraphicFrameDrawingProperties(
new a.GraphicFrameLocks() { NoChangeAspect = true }),
new a.Graphic(
new a.GraphicData(
new pic.Picture(
new pic.NonVisualPictureProperties(
new pic.NonVisualDrawingProperties() { Id = (UInt32Value)0U, Name = ImageFileName },
new pic.NonVisualPictureDrawingProperties()),
new pic.BlipFill(
new a.Blip() { Embed = ImageRelId },
new a.Stretch(
new a.FillRectangle())),
new pic.ShapeProperties(
new a.Transform2D(
new a.Offset() { X = 0L, Y = 0L },
new a.Extents() { Cx = imageLength, Cy = imageHeight }),
new a.PresetGeometry(
new a.AdjustValueList()) { Preset = a.ShapeTypeValues.Rectangle }))
) { Uri = GraphicDataUri }))
{
DistanceFromTop = (UInt32Value)0U,
DistanceFromBottom = (UInt32Value)0U,
DistanceFromLeft = (UInt32Value)0U,
DistanceFromRight = (UInt32Value)0U
}
));
return run;
}
So I've solved issues where the memory stream was causing problems by closing prematurely and probably a dozen other unnecessary amateur garden path problems but that image will just not show up in my document. Frustrating. Suggestions or divine inspiration very welcome right now.
(this question has been heavily edited so some answers may not relate to the wording of this question).
I've just tested your AddImageToDocument function in a small test
scenario using the following code:
string partId = ...
Run element = AddImageToDocument(newdoc.MainDocumentPart, partId);
Paragraph p = new Paragraph() { RsidParagraphAddition = "00EA6221", RsidRunAdditionDefault = "008D25CC" };
p.AppendChild(element);
newdoc.MainDocumentPart.Document.Body.Append(p);
// Save the word document here...
Everything works as expected and the image shows up in the word document.
Then I've come to the conclusion that the problem in your code must be the replacement of the bookmarkStart tag and the conversion
of the Run (containing the image) to an XElement.
So, I've modified your code in the following way (using XElement.Parse to convert
an OpenXmlElement to a XElement):
foreach (XElement bm in bookmarks)
{
try
{
if (bm.LastAttribute.Value == "AudiometryChart")
{
string partId = InsertImage(document.MainDocumentPart);
Run element = AddImageToDocument(document.MainDocumentPart, partId);
bm.ReplaceWith(XElement.Parse(element.OuterXml)); // Use XElement.Parse to convert an OpenXmlElement to an XElement.
}
else
{
... }
}
}
catch
{
}
}
The image now shows up in the word document.
Then I've analyzed the word document using the
OpenXml SDK productivity tool and found that the bookmarkEnd tags still exist in the document.
To remove those tags use the following code:
List<XElement> bookmarksEnd = doc.Descendants()
.Where(n => n.NodeType == XmlNodeType.Element && n.Name.LocalName == "bookmarkEnd")
.ToList();
foreach (XElement x in bookmarksEnd)
{
x.Remove();
}
Edit 3: :o)
Ok, I found the problem.
If you initialize the document's MemoryStream with the doc content, the buffer will be fixed in size and not editable. Just changed the init to write the doc content after creation and all seemd to work fine.
//using (MemoryStream stream = new MemoryStream (docxFile))
using (MemoryStream stream = new MemoryStream ())
{
stream.Write (docxFile, 0, docxFile.Length);
stream.Position = 0;
using (WordprocessingDocument docx = WordprocessingDocument.Open (stream, true))
{
[....]
Cheers

ActionScript retrieval from PHP and returns null value

I am trying to retrieve data from database through php scripts and display in flash using actionscript 3.
For actionscript 3, I have 2 functions:
private var postArrayTxt:Array;
public function stampTwo() {
// constructor code
var stampNumber1:MovieClip = new stamp1();
var stampNumber2:MovieClip = new stamp2();
var stampNumber3:MovieClip = new stamp3();
postArrayTxt = new Array();
postArrayTxt[0] = stampNumber1;
postArrayTxt[1] = stampNumber2;
postArrayTxt[2] = stampNumber3;
trace("All stamps works");
retrieveDetailsFromDB();
}
The data retrieved from database will be displayed in the various movieclips where it will be calling retrieveDetailsFromDB().
public function retrieveDetailsFromDB():void {
var myLoader:URLLoader = new URLLoader();
myLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
myLoader.load(new URLRequest("http://localhost/Converse/stampGalore/tryout.php"));
myLoader.addEventListener(Event.COMPLETE, onDataLoad);
// Error Handling
myLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
myLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
// Could be an error or just a message
myLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
function onDataLoad(evt:Event): void {
//var loader:Loader = new Loader();
//stamp221.addChild(loader);
//loader.load(new URLRequest(evt.target.data.facebookRemarks));
var delimiter:String = "|^_^|";
var stamp:String = evt.target.data.databaseRemarks;
trace(stamp);
var stampRemarkArr:Array = new Array();
stampRemarkArr = stamp.split(delimiter);
for (var i:Number=0; i<stampRemarkArr.length; i++) {
postArrayTxt[i].text = String(stampRemarkArr[i]);
trace("ended");
}
}
// error callbacks
function onIOError(evt:IOErrorEvent) {
trace("IOError: " + evt.text);
}
function onHTTPStatus(evt:HTTPStatusEvent) {
trace("HTTPStatus: " + evt.status);
}
function onSecurityError(evt:SecurityErrorEvent) {
trace("SecurityError: " + evt.text);
}
}
Last but not least, this is my php script.
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
include_once "mysqli.connect.php";
$sql = "SELECT remarks FROM stamp";
$result = $mysqli->query($sql);
if ($mysqli->errno)
{
error_log($mysqli->error);
return;
}
$facebook = "";
$counter = 0;
while ($row = $result->fetch_array())
{
$database = $row["remarks"];
$delimiter = "|^_^|";
if ($counter == 0) {
$facebook .=$database;
} else {
//Use a delimiter "|^_^|" to seperate the records
$facebook .= $delimiter . $database;
}
$counter++;
}
$mysqli->close();
echo "databaseRemarks=" . $facebook;
?>
if I were to run the php script itself, the data could be retrieved from database. However, if I run in Flash, it returns a null value. Please help me as I have wasted a lot of time on this retrieve function. Thank you
This won't work:
var stamp:String = evt.target.data.databaseRemarks;
Flash doesn't know in which format is your data so you need to parse it first. So first read the data:
var rawData:String = evt.currentTarget.data;
Then parse it:
var parsedData:* = someFunctionToParseYourData(rawData);

Resources