Create attributes from CSV as a loop - php

I am writing a script to create Magento attributes programatically, pulling the data from a CSV. Not sure I have the actual loop correct that pulls the data from the CSV - was hoping for some expert guidance on the logic?
<?php
$fh = fopen("attributes.csv", "r");
$i = 0;
while (($l = fgetcsv($fh, 1024, ",")) !== FALSE) {
$i++;
if($i == 1) continue; //ignoring the headers, so skip row 0
$data['label'] = trim($l[2]);
$data['input'] = trim($l[3]);
$data['type'] = trim($l[2]);
//Create the attribute
$data=array(
'type'=>$data['type'],
'input'=>'text',
'label'=>$data['label'],
'global'=>Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'is_required'=>'0',
'is_comparable'=>'0',
'is_searchable'=>'0',
'is_unique'=>'1',
'is_configurable'=>'1',
'use_defined'=>'1'
);
$model->addAttribute('catalog_product','test_attribute',$data);
}
?>
I basically just want it to grab the attribute data from the CSV, and for each row in the CSV run the code to create it (using the label and name as specified in the CSV - im guessing I am missing something obvious in the loop? (just really learning what I'm doing!)

You reset the $data array in each loop, after inserting the values from CSV, so the CSV-content gets lost. Try this
$fh = fopen("attributes.csv", "r");
$i = 0;
$attributes=array(); //!!
while (($l = fgetcsv($fh, 1024, ",")) !== FALSE) {
$i++;
if($i == 1) continue; //ignoring the headers, so skip row 0
$data=array();
$data['label'] = trim($l[2]);
$data['input'] = trim($l[3]);
$data['type'] = trim($l[2]);
$data['global']=Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL;
$data['is_required']='0';
$data['is_comparable']='0';
$data['is_searchable']='0';
$data['is_unique']='1';
$data['is_configurable']='1';
$data['use_defined']='1';
//insert $data to the attributes array
$attributes[]=$data;
//or
$model->addAttribute('catalog_product','test_attribute',$data);
}

Related

How to sort a CSV file by a column and then sort by a second column, then saving the CSV file

I'm looking to read a CSV export file with PHP. I have access to the File Path Variable called $file_path.
How would I sort the CSV export file by a specific column and then sort it again by a second column? and then save the CSV file to the same file name and file path.
UPDATE:
I got it to read the CSV, then sort it and also save it to the CSV. However, it's also sorting the headers. I am trying to use array_shift and array_unshift but when I use array_shift with a multi-layer array, I am getting an error. (unshift works fine though).
function wp_all_export_after_export($export_id, $exportObj)
{
// Check whether "Secure Mode" is enabled in All Export -> Settings
$is_secure_export = PMXE_Plugin::getInstance()->getOption('secure');
if (!$is_secure_export) {
$filepath = get_attached_file($exportObj->attch_id);
} else {
$filepath = wp_all_export_get_absolute_path($exportObj->options['filepath']);
}
$handle = fopen($filepath, 'r') or die('cannot read file');
$binNumber = array();
$category = array();
$rows = array();
$header = array();
//build array of binNumbers, Categories, and array of rows
while (false != ( $row = fgetcsv($handle, 0, ',') )) {
$binNumber[] = $row[3];
$category[] = $row[1];
$rows[] = $row;
}
fclose($handle);
$header = $rows[0];
array_shift($rows);
//sort array of rows by BinNumber & then Category using our arrays
array_multisort($binNumber,SORT_ASC, $category, SORT_ASC, $rows);
array_unshift($rows,$header);
$file = fopen($filepath,"w");
foreach ($rows as $line) {
fputcsv($file, $line);
}
fclose($file);
}
add_action('pmxe_after_export', 'wp_all_export_after_export', 10, 2);

PHP update big CSV files efficently

so basically my objective here is pretty simple. I have an big CSV inventory file with about 400k lines/items and I am receiving a csvstock file every couple minutes. I am trying to find an efficent and fast way to transfer the new stock count from the gathered stock-feed and update the stock on my inventory file. I created an array from the stock-feed, looping trough my inventory csv file and if the sku from the stock-feed matches with a sku of my inventory file, I am replacing the stock count from the stock-feed to my inventory file.
But the efficency here is really bad, takes years to update those 400k lines.
Any idea for a good efficent way to update my inventory csv with the data from my stock-feed?
Maybe PHP is not the right to work here with, if so, any other tips on how to handle it fast and efficient ?
That is my stinky code so far:
<?php
$rows = array_map('str_getcsv', file('stock-feed.csv') , [","]);
$header = array_shift($rows);
$csv = array();
foreach ($rows as $row)
{
$csv[] = array_combine($header, $row);
}
$row = 1;
$filedone = fopen("updatedStockInventory.csv", "w");
$fileName = "Inventory.csv";
$file = fopen($fileName, "r");
while (($column = fgetcsv($file, 10000, "|")) !== false)
{
if ($row == 0)
{
}
else
{
$key = array_search($column[2], array_column($csv, 'sku'));
$stock = $csv[$key]['stock'];
if ($key != "")
{
//Write line with new stock count
}
else
{
//skip
}
fputs($filedone, $line);
}
$row++;
}
?>

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);
....

PHP get string from CSV for a duplicate entry

I have this big file containing SWIFT numbers and bank names. I'm using the following php function for reading and comparing data:
function csv_query($blz) {
$cdata = -1;
$fp = fopen(DIR_WS_INCLUDES . 'data/swift.csv', 'r');
while ($data = fgetcsv($fp, 1024, ",")) {
if ($data[0] == $blz){
$cdata = array ('blz' => $data[0],
'bankname' => $data[7]);
// 'prz' => $data[2]
}
}
return $cdata;
}
The csv files looks like that:
"20730054",1,"UniCredit Bank - HypoVereinsbank (ex VereinWest)","21423","Winsen (Luhe)","UniCredit Bk ex VereinWest",,"HYVEDEMM324","68","013765","M",1,"20030000"
"20750000",1,"Sparkasse Harburg-Buxtehude","21045","Hamburg","Spk Harburg-Buxtehude","52002","NOLADE21HAM","00","011993","U",0,"00000000"
"20750000",2,"Sparkasse Harburg-Buxtehude","21605","Buxtehude","Spk Harburg-Buxtehude","52002",,"00","011242","U",0,"00000000"
As you can see from the code, I need the first and the eight string. If the first string has no duplicates everything is ok, but if it has, most likely the eighth field of the duplicate will be empty and I get no result back. So I want to ask how to display that eighth field of the first result if the line has a duplicate.
I guess this will solve your problem :
function csv_query($blz) {
$cdata = -1;
$fp = fopen(DIR_WS_INCLUDES . 'data/swift.csv', 'r');
$counter = 0; // add this line
while ($data = fgetcsv($fp, 1024, ",")) {
if ($data[0] == $blz && !$counter) { //change this line
$cdata = array(
'blz' => $data[0],
'bankname' => $data[7]
);
$counter++; //add this line
}
}
return $cdata;
}

PHP: How can I get the contents of a CSV file into a MySQL database row by row?

How can I get the contents of a CSV file into a MySQL database row by row? Ive tried a few methods but can never get more than one row returned, using fgetcsv. One method I've tried that seemed to come so close to working:
$fileName = $_FILES['SpecialFile']['name'];
$tmpName = $_FILES['SpecialFile']['tmp_name'];
$fileSize = $_FILES['SpecialFile']['size'];
if(!$fileSize)
{
echo "File is empty.\n";
exit;
}
$fileType = $_FILES['SpecialFile']['type'];
$file = fopen($tmpName, 'r');
if(!$file)
{
echo "Error opening data file.\n";
exit;
}
while(!feof($file))
{
$data = str_replace('"','/"',fgetcsv($file, filesize($tmpName), ","));
$linemysql = implode("','",$data);
$query = "INSERT INTO $databasetable VALUES ('$linemysql')";
return mysql_query($query);
}
fclose($file);
only enters one row, but if I print_r $data it returns all the rows. How do I get it to insert all th rows?
Another method:
$data = str_getcsv($csvcontent,"\r\n","'","");
foreach($data as &$Row)
{
$linearray = str_getcsv($Row,',',''); //parse the items in rows
$linemysql = implode("','",$linearray);
echo $query = "INSERT INTO $databasetable VALUES ('$linemysql')";
}
This almost works too, but there is text within the csv that also contains new lines, so I dont know howto split the actual rows and not the new lines in the text as well.??
this function return an array from csv file
function CSVImport($file) {
$handle = fopen($file, 'r');
if (!$handle)
die('Cannot open file.');
$rows = array();
//Read the file as csv
while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
$rows[] = $data
}
fclose($handle);
return $rows;
}
// this will return an array
// make some logic to read the array and save it
$csvArray = CSVImport($tmpName);
if (count($csvArray)) {
foreach ($csvArray as $key => $value) {
// $value is a row of adata
}
}
I think this is what you are looking for.
function getCSVcontent($filePath) {
$csv_content = fopen($filePath, 'r');
while (!feof($csv_content)) {
$rows[] = fgetcsv($csv_content,1000,";");
}
fclose($csv_content);
return $rows;
}
Make sure that you new line separator is ";" or give the correct one to fgetcsv(). Regards.

Categories