Magento importing images - image

I am getting stuck with images not displaying with their products. When I create a product and insert an image with that product manually through (manage products) the image shows which is great.
However we have over 1000 product images which need to be uploaded, (all the product information is already up I just need to add the images)
I have exported the products CSV file and the working image address is /n/g/image1.jpg
I have then copied that but change the image to image2.jpg, image3.jpg etc. I then uploaded the new images into that folder directory on our server thinking that's enough.
I then upload the CSV file blow the cache and reindex the data however no new images show and worse the working image doesn't display.
I have filled in image, small_image and thumbnail details in the CSV. All images are correctly sized etc.
Further more can allow tell me where I can just have 1 image folder in the directory where all my images are stored?
Thanks
I'm using Magento version 1.7.0.2

First of all your image should store in media>import directory
then in your csv file just write in image column /imagename.jpg
it will find same imagename in import directory, if image exist then it will upload the image
EDIT
if you don't have import directory then simply create it

I'm sorry to say, but there is more going on behind the scenes with magento images that it simply putting a filename in the database and linking to your image. The cache generation alone is pretty complex. I believe you are going to have a hard time doing it the way you are attempting.
That being said, I do have a suggestion. Since your images are already on the server, I suggest you write a simple php script to tell magento to attach them to the product image. This could be automated, but i'll give you a small example below...
To attach an image, you would simply navigate to the url like this
http://yoursite.com/imageattacher.php?sku=YOURSKU&image=yourimagefilename.jpg
The script would be like this... create a file in your magento ROOT and call it imageattacher.php. Upload your images to the magento media import directory. I have not tested this but it should work.
<?php
// Initialize magento for use outside of core
umask(0);
require_once 'app/Mage.php';
Mage::app('admin');
// Get the variables from the URL
$sku = $_GET["sku"];
$imageName = $_GET["image"];
// get the image from the import dir
$import = Mage::getBaseDir('media') . DS . 'import/' . $imageName;
// Load the product by sku
$product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
// if the product exists, attempt to add the image to it for all three items
if ($product->getId() > 0)
{
// Add the images and set them for their respective usage (the radio button in admin)
$product->addImageToMediaGallery($import,array('image', 'small_image', 'thumbnail'),false,false);
// Make the changes stick
$product->save();
}
?>
See this http://www.danneh.org/2012/05/creating-products-programmatically-magento/

The issue in the end was that there wasn't an import folder under the media directory. The images were uploaded to this folder. The image column in the CSV was changed to /image1.jpg which allowed them to show on the website.

I had to import a bunch of Magento product images recently which were all named by SKU (eg 123456.jpg). This is the script I used to import them, parts of which are based on CarComp's answer. It will only work for numeric SKUs (eg 123456) but could be fairly easily modified to cater for alphanumeric ones.
<?php
require_once(__DIR__ . "/app/Mage.php");
Mage::app('admin');
class Sku_ImageLoader {
private $_uploadDir;
private $_imagePaths;
public function setUploadDirectory($dir = null) {
if (empty($dir)) {
if (isset($this->_uploadDir)) return $this;
$dir = 'upload';
}
$this->_uploadDir = Mage::getBaseDir('media') . DS . $dir;
// mkdir($this->_uploadDir . DS . "/loaded", 0770);
return $this;
}
public function load() {
$this->setUploadDirectory();
// Match product images like 123456.jpg
$pattern = '[0-9][0-9][0-9][0-9][0-9][0-9].{jpg,gif,png}';
chdir($this->_uploadDir);
$this->_imagePaths = glob($pattern, GLOB_BRACE);
return $this;
}
public function showFiles() {
$this->load();
echo "\r\n\r\nSorry, I wasn't able to upload the following image files in " . $this->_uploadDir . "\r\n\r\n<pre>\r\n";
print_r($this->_imagePaths);
return $this;
}
private function _addImage($path) {
$sku = (string)intval($path);
try {
echo "Loading SKU: {$sku} ... ";
$product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
// if the product exists, attempt to add the image to it for all three items
if (strpos(get_class($product), 'Catalog_Model_Product') !== false && $product->getId() > 0) {
$product->addImageToMediaGallery($path,array('image', 'small_image', 'thumbnail'),false,false);
$product->save();
echo " ok \r\n";
return true;
}
} catch (Exception $e) {
echo "Exception thrown for {$sku}: " . $e->getMessage() . "\r\n";
}
echo " (FAILED) \r\n";
return false;
}
private function _moveImage($path) {
// rename($path, 'loaded' . DS . $path);
unlink($path);
}
public function import() {
echo "<pre>\r\n";
if (!isset($this->_imagePaths)) $this->load();
foreach ($this->_imagePaths as $path) {
if ($this->_addImage($path)) {
$this->_moveImage($path);
}
}
return $this;
}
}
$u = new Sku_ImageLoader();
$u->import()->showFiles();
?>

Related

Safety in laravel file upload

I have a simple question.. Is it safe to have a app that has a file upload system for users to send images to our project, and store those files in this directory?
$file->move(public_path('../storage/app/public/files'), $name);
Or is it better to store in:
$file->move(public_path('files'), $name);
This way it stores the file in the "files" directory inside the public directory.
That would be ok and also depends on your app and number of users but I recommend to change the name of the file and also you can accept only JPG or PNG file for more security for changing the name of the file you can do it like this :
$image_name = rand() . '.' . $image->getClientOriginalExtension();
$image->move(public_path('images'), $image_name);
with this function you can get all data from db for that id then you can show whatever you want in the blade
public function show($id)
{
$data = YOUR_MODEL::findOrFail($id);
return view('view', compact('data'));
}

Replace Old image with new image in laravel

CONTROLLER
public function updateproduct(Request $request, $id)
{
// dd($request->all());
$request->validate([
'name'=>'required',
'description'=>'required',
'price'=>'required|numeric',
'quantity'=>'required|numeric',
]);
$product = Product::where('id', $id)->first();
if(is_null($product)) {
$product = new Product();
}
$product->name=$request->name;
$product->description=$request->description;
$product->price=$request->price;
$product->quantity=$request->quantity;
if($request->hasfile('images')){
$existingimages = Image::where(['product_id'=> $product->id, 'source'=> 1])->get();
if($existingimages->count() > 0)
foreach($existingimages as $existingimage) {
$filename = public_path().'files/'.$existingimage->name;
if(file_exists($filename)){
unlink($filename);
$existingimage->delete();
}
}
foreach($request->file('images') as $file){
$name = rand(1,9999).'.'.$file->getClientOriginalName().$file->getClientOriginalExtension();
if($file->move(public_path().'/files/', $name)){
$updateImage = Image::firstWhere('product_id', $product->id);
$updateImage->images = $name;
$updateImage->source = 1;
$updateImage->save();
}
}
}
Please check updated question. Request you to correct me if I wrong. Right now it only updates 1 image and other images remains same. please help me with this.
Your code is somewhat confusing, I'm afraid.
Your request appears to allow for multiple images to be uploaded. Here :
if(file_exists($imagePath)){
unlink($imagePath);
}
you look like you're trying to delete any images that already exist, but when you store upload images you're assigning them a random name (which Laravel can already handle for you, by the way, so there's no need to do it yourself) so you're unlikely to be actually deleting them because there'll likely be no file at that location anyway.
Nowhere does your code actually delete any existing images from the database. Essentially what you want to do is :
If the upload has images, retrieve all the existing images for that product.
Delete the physical files for those existing images.
Delete the database entries for those existing images.
Upload your new images and save their details to the database.
Translating that into code means :
if($request->hasfile('images')){
// Delete any existing image files and database entries.
$existingimages = Image::where('product_id', $product->id)->get();
if($existingimages->count() > 0)
foreach($existingimages as $existingimage) {
$filename = public_path().'files/'.$existingimage->name;
unlink($filename);
$existingimage->delete();
}
}
// Carry on with your upload
}
It adds new images because you are using the Image::create method. If I understood correctly, you want to modify the images of your products in the image table.
Try to modify your code like :
$updateImage = Image::firstWhere('product_id', $product->id);
$updateImage->images = $name;
$updateImage->source = 1;
$updateImage->save();

Magento 2.3. - custom import module with Magmi Integration

I'm trying to write a magento modulo for importing products from a csv file. I would like to use Magmi to achieve the import. I tried the following code but it doesn't work.
namespace My\Module\Controller\Adminhtml\Home;
require_once(dirname(__FILE__) . "/../../../../../../../lib/magmi/inc/magmi_defs.php");
require_once(dirname(__FILE__) . "/../../../../../../../lib/magmi/integration/inc/magmi_datapump.php");
class Import extends \Magento\Backend\App\Action{
public function execute()
{
// getting data from a casv file
for ($items as $item){
$dp = Magmi_DataPumpFactory::getDataPumpInstance("productimport");
$dp->beginImportSession("default", "xcreate");
$item = "product field array";
$run = $dp->ingest($item);
$dp->endImportSession();
}
}
}
I receive errors on the Magmi classes "class not found". I tried also different code but the only way a think it can works is using class file named, e.g. Datapump.php with e defined class named Datapump. But I cannot rewrite all files of magmi to make it works, so maybe I'm doing something wrong.
Though not an ideal solution. But you can try this.
1) Make below changes in file magmi/integration/inc/magmi_datapump.php
Change the class name from 'Magmi_DataPumpFactory' to 'Magmi_DataPump'
This is needed because Magento 2 interprets Factory keyword in a different way.
2) Now create an autoloader file
app/code/Vendor/Module/magmi-autoloader.php
<?php
$mapping = array(
'Magmi_Defs' => BP . '/magmi/inc/magmi_defs.php"',
'Magmi_DataPump' => BP . '/magmi/integration/inc/magmi_datapump.php'
);
spl_autoload_register(function ($class) use ($mapping) {
if (isset($mapping[$class])) {
require $mapping[$class];
}
}, true);
3) Now change relative paths in below file to absolute path. Since while running magmi classes through Magento, it will be not able to read paths relative to magmi directory.
magmi/inc/magmi_defs.php
<?php
// change below define variables to their absolute paths according to your project's root directory
define("MAGMI_BASEDIR", dirname(dirname(__FILE__)));
define("MAGMI_INCDIR", MAGMI_BASEDIR . '/inc');
define("MAGMI_INTEGRATION_INCDIR", MAGMI_BASEDIR . '/integration/inc');
define("MAGMI_PLUGIN_DIR", MAGMI_BASEDIR.'/plugins');
define("MAGMI_ENGINE_DIR", MAGMI_BASEDIR . '/engines');
.
.
//other code
.
.
4) Now change your controller file as below
<?php
namespace Vendor\Module\Controller\Adminhtml\Home;
require BP.'/app/code/Vendor/Module/magmi-autoloader.php';
class Import extends \Magento\Backend\App\Action
{
public function execute()
{
// getting data from a csv file
$dp = \Magmi_DataPump::getDataPumpInstance("productimport");
// move this outside the loop to prevent mysql max_connection error
$dp->beginImportSession("default", "xcreate");
for ($items as $item){
$item = "product field array";
$run = $dp->ingest($item);
}
$dp->endImportSession();
}
}

How to get original size image url in magento 2.0

I am pretty new in Magento 2.0 and I have been struggling to find out solution. My first question, which I didn't figure out yet, how to reach specific function? Beacuse I noticed that many people use those in Magento 1.+:
Mage::helper('cms/page')->
or
Mage::getModel('catalog/product_media_config')
(e.g Get original image url Magento (1.6.1.0))
but I can't use them in Magento 2.0. If that kind of using is not available in last version anymore, what can I use it as an alternative method to reach functions?
As for another question, I am unable to get original sized image in grid.phtml (catalog listing). Here is how to get images:
<?php
echo $block->getImage($_item, $image)->getImageUrl();
echo $block->getImage($_item, $image)->getWidth();
echo $block->getImage($_item, $image)->getHeight();
?>
And the result like that:
http://192.168.1.4/magento/pub/media/catalog/product/cache/1/small_image/240x300/beff4985b56e3afdbeabfc89641a4582/t/h/thumbnail_1.jpg240300
As I mentioned above, I want to get original sized image url instead of small_image. I hope I explained my problems. If anyone has any idea, please let me know it. Thank you!
Use the below function to get the Media base url for a particular store:
function getMediaBaseUrl() {
$om = \Magento\Framework\App\ObjectManager::getInstance();
$storeManager = $om->get('Magento\Store\Model\StoreManagerInterface');
$currentStore = $storeManager->getStore();
return $currentStore->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
}
Using getMediaBaseUrl() function we can find image url in Magento2:
echo $block->getMediaBaseUrl() .'catalog/product'. $_product->getImage();
1) Quick Solution by directly writing media directory path
echo $block->getUrl().'pub/media/catalog/product' . $_product->getImage();
2) Getting media directory path using StoreManager class object
namespace YourNamespace\YourModule\Block;
class YourModule extends \Magento\Framework\View\Element\Template
{
protected $_storeManager;
public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager,
...
)
{
$this->_storeManager = $storeManager;
...
}
public function getMediaBaseUrl()
{
return $this->_storeManager
->getStore()
->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
}
}
And then in your module's template (.phtml) file, you can write as:
echo $block->getMediaBaseUrl() . $_product->getImage();

Magento - re-importing of products

I have a script that pulls in data from a 3rd party file. My import simply parses and inserts rows, which is working fine.
The problem comes with images.
When the import script runs, it first deletes all the current items and then the import begins, inserting all products and images into the gallery.
On the first import, everything is fine, the images go in and I see them on the frontend no problem. The problem comes with everytime I then re-import these products, it doesn't seem to delete all images, as when the products re-import, I see, for example the 4 images correct, then then loads of blank rows, like images should be there, but can't be found.
I don't want to see these blank lines, but I'm not sure why they are there.
Could it be because the images for the product are already in the catalogue?
I am really unsure what and why this is doing what it is.
Thanks
EDIT:
My code is:
require_once('app/Mage.php');
$app = Mage::app('default');
$product = Mage::getSingleton('catalog/product');
$txt_file = file_get_contents('test.txt');
$rows = explode("\n", $txt_file);
array_shift($rows);
foreach($rows as $row => $data)
{
//get row data
$row_data = explode('^', $data);
$info[$row]['uniqueid'] = $row_data[0];
$info[$row]['client'] = $row_data[1];
$info[$row]['make'] = $row_data[2];
$info[$row]['model'] = $row_data[3];
$info[$row]['adtext'] = $row_data[4];
//display images
$row_images = explode(',', $info[$row]['picturereference']);
foreach($row_images as $row_image)
{
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS . 'import/' . $row_image, array('image', 'small_image','thumbnail'), false, false);
}
$product->setStoreId(Mage::app()->getStore(true)->getWebsite()->getId());
$product->setWebsiteIds(array(Mage::app()->getStore(true)->getWebsite()->getId()));
$product->setId($info[$row]['id']);
$product->setSku(strtolower($info[$row]['make']).'-'.strtolower($info[$row]['model']));
$product->setName($info[$row]['make']);
$product->setDescription($info[$row]['adtext']);
try {
$product->save();
echo "Saved";
}
catch (Exception $ex) {
echo "<pre>".$ex."</pre>";
}
}
Is this because the addImageToMediaGallery is called on each iteration and adding all images to each product?
Thanks
Ok so I figured out my problem
Inside the foreach I moved the call to the getSingleton and I added the the following: $product = Mage::getModel('catalog/product');
I then, after each iteration, unset the following:
unset($product);
unset($info);
unset($stockData);
unset($row_images);
This seemed to fix my script and now imports each products images into the proper product rather than importing other and adding random blank entries
Thanks all
A few files you'll want to examine to break down addImageToMediaGallery and determine what exactly its doing.
app/code/core/Mage/Catalog/Model/Product.php - Contains the method your using, breaking it down more you'll find...
app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php - Contains more of the "bits and pieces" of addImageToMediaGallery like addImage etc.
Some possibilities to try would be either
A) determine if the files already exist and are attached to the product and ignoring them upon a second round of import. Perhaps looking for different file stamp. getMediaGalleryImages within Product.php.
B) clear the media files associated with the products BEFORE importing again? clearMediaAttribute and removeImage within Media.php.
I would also try the $move option set to true within your addImageToMediaGallery call as well.
/**
* Add image to media gallery
*
* #param string $file file path of image in file system
* #param string|array $mediaAttribute code of attribute with type 'media_image',
* leave blank if image should be only in gallery
* #param boolean $move if true, it will move source file
* #param boolean $exclude mark image as disabled in product page view
*/
public function addImageToMediaGallery($file, $mediaAttribute=null, $move=false, $exclude=true)
{
Another option would be to try to specify null for the second param, if you note the PHPDoc comments, leaving it blank will only be for the gallery which sounds like what you are wanting...
foreach($row_images as $row_image)
{
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS . 'import/' . $row_image, null, false, false);
}
Let me know if any of these help.
Give something like this a try:
//Check if gallery attribute exists then remove all images if it exists
//Get products gallery attribute
$attributes = $product->getTypeInstance()->getSetAttributes();
if (isset($attributes['media_gallery'])) {
$gallery = $attributes['media_gallery'];
//Get the images
$galleryData = $product->getMediaGallery();
foreach($galleryData['images'] as $image){
//If image exists
if ($gallery->getBackend()->getImage($product, $image['file'])) {
$gallery->getBackend()->removeImage($product, $image['file']);
}
}
}
This blog posting may also help, as its where I got the code snippet form also:
http://www.sharpdotinc.com/mdost/2010/03/02/magento-import-multiple-images-or-remove-images-durring-batch-import/

Resources