How to skip several lines of an Excel file in php? - php

I have an Excel file (xlsx) with several pictures
And I have this php script that allows me to extract the photos contained in it, insert them in a folder and rename them according to the name of the cells in front of each photo.
The script works but I would like to start reading the lines from line 5. I tried with $i <= 3 to skip the first 4 lines but this causes a shift in the picture names. How can I solve my problem?
<?php
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$path = 'C:/wamp64/www/Extract_pictures_Excel/imagetest.xlsx';
$objPHPExcel = PHPExcel_IOFactory::load($path);
$i = 0;
foreach ($objPHPExcel->getActiveSheet()->getDrawingCollection() as $drawing ) {
$i++;
if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG :
$extension = 'png'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg'; break;
}
}
else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
$chemin = 'C:/wamp64/www/Extract_pictures_Excel/images/';
}
$sheet = $objPHPExcel->getActiveSheet();
foreach ($sheet->getDrawingCollection() as $drawing) {
$row = (int)substr($drawing->getCoordinates(), 1);
// retrieve the image data anyway you like
$stylecode = $sheet->getCell('B'.$row)->getValue();
$colorcode = $sheet->getCell('C'.$row)->getValue();
$finalname = $stylecode.'_'.$colorcode;
$myFileName = $chemin.$finalname.'.'.$extension;
file_put_contents($myFileName,$imageContents);
}
}
?>

I think getDrawingCollection() gives you a list of all the drawings on the active sheet, but this list is not directly related to cell coordinates. So skipping some items of this list is not the same as skipping rows.
Not sure how this goes with the old PHPExcel libs, but with current PhpOffice\PhpSpreadsheet, a Drawing or BaseDrawing objects should have their $coordinates property.
Example:
$sheet = $objPHPExcel->getActiveSheet();
foreach ($sheet->getDrawingCollection() as $drawing) {
$row = (int)substr($drawing->getCoordinates(), 1);
// retrieve the image data anyway you like
$stylecode = $sheet->getCell('B'.$row)->getValue();
$colorcode = $sheet->getCell('C'.$row)->getValue();
$finalname = $stylecode.'_'.$colorcode;
...
}
You should parse the $drawing->coordinates in order to retrieve values of it's neighbouring cells.

Related

PHP how to map importer fields to csv first row fields?

I am importing rims from an csv file to a webshop project. nothing for sell, just a personal project for learning how importers work.
I am trying to map my $EANColumn variable to the first row field name in my csv.
So currently i have a csv with the following fields :
EAN;Brand;...and-more-comming
1234-WB;WheelBrand...and-more-comming
5678-BW;BrandWheel...and-more-comming
At the moment in my importer, it works when i map:
$EANColumn = str_replace('’', '', $importData_arr["EAN"]);
And inserting it to my database through an array :
foreach($importData_arr as $importData){
// var_dump($importData);
$insertData = array(
"EAN" =>$EANColumn);
RimsUpload::insertData($insertData);
My complete code for this part is here :
if ($request->input('submit') != null ){
$file = $request->file('file');
// File Details
$filename = $file->getClientOriginalName();
$extension = $file->getClientOriginalExtension();
$tempPath = $file->getRealPath();
$fileSize = $file->getSize();
$mimeType = $file->getMimeType();
// Valid File Extensions
$valid_extension = array("csv");
// 2MB in Bytes
$maxFileSize = 2097152;
// Check file extension
if(in_array(strtolower($extension),$valid_extension)){
// Check file size
if($fileSize <= $maxFileSize){
// File upload location
$location = 'uploads';
// Upload file
$file->move($location,$filename);
// Import CSV to Database
$filepath = url($location."/".$filename);
// Reading file
$file = fopen($filepath,"r");
$importData_arr = array();
$i = 0;
while (($filedata = fgetcsv($file, 1000, ";")) !== FALSE) {
$num = count($filedata );
$EANColumn = str_replace('’', '', $importData_arr["EAN"]);
$BrandColumn = $importData_arr["Brand"];
// Skip first row (Remove below comment if you want to skip the first row)
if($i == 0){
$i++;
continue;
}
for ($c=0; $c < $num; $c++) {
$importData_arr[$i][] = $filedata [$c];
}
$i++;
}
fclose($file);
dump($importData_arr);
// Insert to MySQL database
foreach($importData_arr as $importData){
// var_dump($importData);
$insertData = array(
"EAN" =>$EANColumn,
"Brand"=>$BrandColumn,
"Name"=>$importData[2],
"Size"=>$importData[3],
"PCD"=>$importData[4],
"Offset"=>$importData[5],
"Bore"=>$importData[6],
"Color"=>$importData[7],
"Price"=>$importData[8],
"Stock"=>$importData[9],
"ImageURL"=>$importData[10]);
RimsUpload::insertData($insertData);
}
Session::flash('message','Import Successful.');
}else{
Session::flash('message','File too large. File must be less than 2MB.');
}
}else{
Session::flash('message','Invalid File Extension.');
}
}
// Redirect to index
// return redirect()->action("RimsUploadController#index", [$request]);
return response()->redirectToAction('App\Http\Controllers\RimsUploadController#index', [$request]);
}
But the real problem is that i do not want to map my columns like [0],[1],[2],[3]...
I would like to take them from the first row colum name : ["EAN"],["Brand"],["Name"],["Size"]...
So if EAN is column 1 or column 7, it wont make a difference, since it will detect it by name and not by row number.
So it will then be able to handle files with different column orders.
When trying to do this, i get the error :
Undefined index: EAN on $EANColumn = str_replace('’', '', $importData_arr["EAN"]);
The whole point is to make an easy way to import data from suppliers through csv into mysql. then display it to the webshop site.
Before your while loop, extract the field names from the first row of your csv:
$file = fopen($filepath,"r");
$keys = fgetcsv($file, 1000, ';');
Then, fetch the data lines and combine the $keys array with the data into an associative array:
$importData_arr = [];
while ($line = fgetcsv($file, 1000, ';')) {
$data = array_combine($keys, $line);
// Do something with the data
$data['EAN'] = str_replace('’', '', $data['EAN']);
$importData_arr[] = $data;
}
fclose($file);
You can now access all data fields by their name, independent of the order in the CSV:
foreach($importData_arr as $importData){
echo $importData['EAN'];
}
As long as the field names stay intact, you don't have to change your import code when the field order or count changes.
Here is some simple proposal how to map your data to an array with given keys.
while ($row = fgetcsv($fp, 100, ',')) {
$columnName = ['a','b','c','d','e','f'];
$myRow = array_combine($columnName,$row);
....

Get googlesheet data by passing spreadsheet id and sheet id

I need to get the google sheet data and then to download it as csv. but the issue is I need to get data by sheet id in the url.
I'm using this package "google/apiclient": "^2.0"
Code
$sheets = new \Google_Service_Sheets($client);
//get spreadsheet id from db
$google_sheet_link = TeamGoogleSheet::where('team_id',$team_id)->first();
$url_array = parse_url($google_sheet_link->url);
$path_array = explode("/",$url_array["path"]);
$spreadsheetId = $path_array[3];
\Log::info('Spreadsheet id');
\Log::info($spreadsheetId);
$range = 'Sheet1';
$rows = $sheets->spreadsheets_values->get($spreadsheetId, $range, ['majorDimension' => 'ROWS']);
if (isset($rows['values'])) {
$filename = storage_path("chat_bots.csv");
if (file_exists($filename))
unlink($filename);
$handle = fopen($filename, 'a');
foreach ($rows['values'] as $key => $data) {
fputcsv($handle, $data);
}
fclose($handle);
$headers = array(
'Content-Type' => 'text/csv',
);
return \Response::download($filename, 'chat_bots.csv', $headers);
}
But this requires the sheet name(range attribute) and also only 1 sheet.I want to make it dynamic. we can get sheetid from url, but didn't find a method to retrieve data by passing this sheet id.
$spreadsheet_data = $sheets->spreadsheets->get($spreadsheetId);
//get sheet titles
$work_sheets = [];
$gid_sheet = '';
foreach($spreadsheet_data->getSheets() as $s) {
$work_sheets[] = $s['properties']['title'];
}
if(preg_match("/[#&]gid=([0-9]+)/", $google_sheet_link->url)){
$explode_array = explode("#gid=",$google_sheet_link->url);
$gid = $explode_array[1];
foreach($spreadsheet_data->getSheets() as $s) {
if($s['properties']['sheetId'] == $gid)
$gid_sheet = $s['properties']['title'];
}
}
if($gid_sheet != ''){
$range = $gid_sheet;
}
else{
$range = $work_sheets[0];
}

PHPExcel - load only filtered data

i have file like this
I want to load only two visible row in this example.
I do not know how I can do it.
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($_FILES['plik']['tmp_name']);
$data = $excel->getActiveSheet()->toArray(null, true,true,true);
When loading the file in PHPExcel shows all 8769 rows.
I have to do it in such a way as filtered data will always be different.
Do you know any way to do this?
If you only want visible rows, then you need to write a bit of code that will loop over the rows selecting only those that are visible
Something like:
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($_FILES['plik']['tmp_name']);
$highestColumn = $excel->getActiveSheet()->getHighestColumn();
$data = [];
foreach ($excel->getActiveSheet()->getRowIterator() as $row) {
if ($excel->getActiveSheet()->getRowDimension($row->getIndex())->getVisible()) {
$data[] = $excel->getActiveSheet()
->rangeToArray('A' .$row->getIndex().':'.$highestColumn.$row->getIndex());
}
}
Thanks a lot!
Working great as soon swapped "getIndex ()" to "getRowIndex ()"
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($_FILES['plik']['tmp_name']);
$data = [];
foreach ($excel->getActiveSheet()->getRowIterator() as $row) {
if ($excel->getActiveSheet()->getRowDimension($row->getRowIndex())->getVisible()) {
$data[] = $excel->getActiveSheet()->rangeToArray('A' .$row->getRowIndex().':'.'BB'.$row->getRowIndex());
}
}

PHP Trying to Edit an RSS Feed Title and Description Length, but its not working

Here is my code:
function getThisFeed($feedURL, $source){
$n = array(); //Random Variable to output later
$content = file_get_contents($feedURL); //gets contents of RSS feed
$rss = new SimpleXmlElement($content); //Converts to XML Element
$img = "";
switch ($source){
case "reddit":
$img = "http://dev.dotabattles.com/images/newsThumbs/redditThumb.png";
break;
case "joinDota":
$img = "http://dev.dotabattles.com/images/newsThumbs/joinDotaThumb.png";
break;
case "gosu":
$img = "http://dev.dotabattles.com/images/newsThumbs/gosuThumb.jpg";
break;
default:
$img = "http://dev.dotabattles.com/images/newsThumbs/dotaThumb.png";
}
foreach($rss->channel->item as $entry){
array_push($n, array("title" => substr($entry->title, 0, 50), "fullTitle" => $entry->title, "link" => $entry->link, "description" => $entry->description, "date" => strtotime($entry->pubDate), "img" => $img));
} //Loops through XML element saving the important information
return $n; //returns the full array
}
This is the function that grabs a feed and assigns a thumbnail image to it for display purposes.
function getFullFeed($type = 'all'){
$news = array();
$output = "";
$reddit = getThisFeed("http://reddit.com/r/dota2/.rss", "reddit");
$joinDota = getThisFeed("http://www.joindota.com/feeds/news", "joinDota");
$gosu = getThisFeed("http://www.gosugamers.net/dota2/news/rss", "gosu");
switch ($type) {
case "all":
$news = feedArrayCombine($news, $reddit);
$news = feedArrayCombine($news, $joinDota);
$news = feedArrayCombine($news, $gosu);
usort($news, "cmp");
break;
case "reddit":
$news = $reddit;
break;
case "joinDota":
$news = $joinDota;
break;
case "gosu":
$news = $gosu;
break;
default:
$news = "ERROR";
}
return $news;
}
This function is how I can quickly call different feeds throughout my website.
function editFeed($feed, $titleLimit, $descLimit, $numEntries = null){ //for making small changes in the feed
$news = array();
$newsFeed = $feed;
if ($numEntries) {
for ($i = 0; $i < $numEntries; $i++){
array_push($news, $newsFeed[$i]);
}
$newsFeed = $news;
}
foreach($newsFeed as $f){
$f['title'] = substr($f['title'], 0, $titleLimit);
$f['description'] = substr($f['description'], 0, $descLimit);
}
return $newsFeed;
}
And this final one is how I'm actually trying to edit the feed.
<?php
$news = getFullFeed('gosu');
$news = editFeed($news, 5, 100, 6);
echo printFeed($news);
?>
This is where I've called it on my website. printFeed is just a function that combines bootstrap elements with the feed for display purposes once again.
Everything is showing up, and I'm only getting 6 items in the feed, but the titleLength and descriptionLength are not being changed.

Import an XLSX file into a PHP array

Is it possible to import each line of an XLSX file to a row in a PHP array?
You can use PHPExcel which is available here: https://phpexcel.codeplex.com/releases/view/119187
Here is what I use to read either xls or xlsx to an array:
require_once('/path/to/PHPExcel.php');
$filename = "example.xlsx";
$type = PHPExcel_IOFactory::identify($filename);
$objReader = PHPExcel_IOFactory::createReader($type);
$objPHPExcel = $objReader->load($filename);
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
$worksheets[$worksheet->getTitle()] = $worksheet->toArray();
}
print_r($worksheets);
UPDATE / 2022-02-13:
PhpSpreadsheet has been available for a few years now and has replaced PHPExcel. The following code is more or less the same as above with a couple small improvements:
Converted code to a function or method.
Auto detect filetype.
Added ability to specify how null values, formatting and formulas are handled.
Most importantly, call the destructor and clear memory. Without this last step I was running out of memory all the time after loading large files.
/**
* Create a multidimensional array of worksheets from a filename.
*
* #param mixed $nullValue Value returned in the array entry if a cell doesn't exist
* #param bool $calculateFormulas Should formulas be calculated?
* #param bool $formatData Should formatting be applied to cell values?
*
* #return array
*/
function spreadsheet_to_array($nullValue = null, $calculateFormulas = true, $formatData = false) {
$results = [];
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file);
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
$results[$worksheet->getTitle()] = $worksheet->toArray($nullValue, $calculateFormulas, $formatData);
}
// save memory
$spreadsheet->__destruct();
$spreadsheet = NULL;
unset($spreadsheet);
return $results;
}
I use this:
include 'simplexlsx.class.php';
$xlsx = #(new SimpleXLSX('myFile.xlsx'));
$data = $xlsx->rows();
You can simplexslx from here.
UPDATE
Apparently the link above doesn't work anymore. You can now use this. (Thanks #Basti)
Problem can be solved using PHPExcel library:
$data = [];
$type = PHPExcel_IOFactory::identify($filepath);
$objReader = PHPExcel_IOFactory::createReader($type);
$objPHPExcel = $objReader->load($filepath);
$rowIterator = $objPHPExcel->getActiveSheet()->getRowIterator();
foreach($rowIterator as $row){
$cellIterator = $row->getCellIterator();
foreach ($cellIterator as $cell) {
$data[$row->getRowIndex()][$cell->getColumn()] = $cell->getCalculatedValue();
}
}
where $filepath - path to your xls or xlsx file.
Yes with phpspreadsheet :
include 'vendor/autoload.php';
if($_FILES["import_excel"]["name"] != '')
{
$allowed_extension = array('xls', 'csv', 'xlsx');
$file_array = explode(".", $_FILES["import_excel"]["name"]);
$file_extension = end($file_array);
if(in_array($file_extension, $allowed_extension))
{
$file_name = time() . '.' . $file_extension;
move_uploaded_file($_FILES['import_excel']['tmp_name'], $file_name);
$file_type = \PhpOffice\PhpSpreadsheet\IOFactory::identify($file_name);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($file_type);
$spreadsheet = $reader->load($file_name);
unlink($file_name);
$data = $spreadsheet->getActiveSheet()->toArray();
foreach($data as $row)
{
$insert_data = array(
':test1' => $row[0],
':test2' => $row[1],
':test3' => $row[2],
':test4' => $row[3]
);
};
$query = "
INSERT INTO post
( test1, test2, test3, test4)
VALUES
( :test1, :test2, :test3, :test4)
";
$statement = $connect->prepare($query);
$statement->execute($insert_data);
}
echo "succes";
}else{
echo "only xls,csv,xlsx are allowed";
}
With the new version of PHPSpreadSheet you can simply do that :
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
/*...*/
$reader = new Xlsx();
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load('upload/file.xls');
$sheet = $spreadsheet->getSheet($spreadsheet->getFirstSheetIndex());
$data = $sheet->toArray();
Just be careful, you have all cells as value. For exemple, date is converted to int so you need to convert it
You can use NumberFormat to see all converter.
Exemple to convert an int cell to date :
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
/*....*/
//$value is an integer of a cell value
$value = 44823
$stringDate = NumberFormat::toFormattedString($value, 'YYYY-MM-DD');
// 2022-09-19 is displayed
echo $stringDate;
Found here : https://blog.programster.org/phpspreadsheet-read-excel-file-to-array
More information in the documentation : https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-files/ https://phpspreadsheet.readthedocs.io/en/latest/
Source code of NumberFormat : https://phpoffice.github.io/PhpSpreadsheet/classes/PhpOffice-PhpSpreadsheet-Style-NumberFormat.html
<?php
require_once 'SimpleXLSX.php';
if ( $xlsx = SimpleXLSX::parse('pricelist.xlsx') ) {
print_r( $xlsx->rows() );
} else {
echo SimpleXLSX::parseError();
}
?>
SimpleXLSX

Categories