PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/magmi/plugins/extra/itemprocessors/imageprocessor/imageitattributeemprocessor.php

https://bitbucket.org/jit_bec/shopifine
PHP | 692 lines | 576 code | 54 blank | 62 comment | 59 complexity | 7040813caa66b542676db98d295676cf MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. class ImageAttributeItemProcessor extends Magmi_ItemProcessor
  3. {
  4. protected $forcename=null;
  5. protected $magdir=null;
  6. protected $imgsourcedir=null;
  7. protected $errattrs=array();
  8. protected $_lastnotfound="";
  9. protected $_lastimage="";
  10. protected $_handled_attributes=array();
  11. protected $_img_baseattrs=array("image","small_image","thumbnail");
  12. protected $_active=false;
  13. protected $_newitem;
  14. public function initialize($params)
  15. {
  16. //declare current class as attribute handler
  17. $this->registerAttributeHandler($this,array("frontend_input:(media_image|gallery)"));
  18. $this->magdir=Magmi_Config::getInstance()->getMagentoDir();
  19. $this->imgsourcedir=realpath($this->magdir."/".$this->getParam("IMG:sourcedir"));
  20. if($this->imgsourcedir==false)
  21. {
  22. $this->imgsourcedir=$this->getParam("IMG:sourcedir");
  23. }
  24. $this->forcename=$this->getParam("IMG:renaming");
  25. foreach($params as $k=>$v)
  26. {
  27. if(preg_match_all("/^IMG_ERR:(.*)$/",$k,$m))
  28. {
  29. $this->errattrs[$m[1][0]]=$params[$k];
  30. }
  31. }
  32. }
  33. public function getPluginInfo()
  34. {
  35. return array(
  36. "name" => "Image attributes processor",
  37. "author" => "Dweeves",
  38. "version" => "1.0.22",
  39. "url"=>"http://sourceforge.net/apps/mediawiki/magmi/index.php?title=Image_attributes_processor"
  40. );
  41. }
  42. public function handleGalleryTypeAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
  43. {
  44. //do nothing if empty
  45. if($ivalue=="")
  46. {
  47. return false;
  48. }
  49. //use ";" as image separator
  50. $images=explode(";",$ivalue);
  51. //for each image
  52. foreach($images as $imagefile)
  53. {
  54. //trim image file in case of spaced split
  55. $imagefile=trim($imagefile);
  56. //handle exclude flag explicitely
  57. $exclude=$this->getExclude($imagefile,false);
  58. $infolist=explode("::",$imagefile);
  59. $label=null;
  60. if(count($infolist)>1)
  61. {
  62. $label=$infolist[1];
  63. $imagefile=$infolist[0];
  64. }
  65. unset($infolist);
  66. //copy it from source dir to product media dir
  67. $imagefile=$this->copyImageFile($imagefile,$item,array("store"=>$storeid,"attr_code"=>$attrcode));
  68. if($imagefile!==false)
  69. {
  70. //add to gallery
  71. $targetsids=$this->getStoreIdsForStoreScope($item["store"]);
  72. $vid=$this->addImageToGallery($pid,$storeid,$attrdesc,$imagefile,$targetsids,$label,$exclude);
  73. }
  74. }
  75. unset($images);
  76. //we don't want to insert after that
  77. $ovalue=false;
  78. return $ovalue;
  79. }
  80. public function removeImageFromGallery($pid,$storeid,$attrdesc)
  81. {
  82. $t=$this->tablename('catalog_product_entity_media_gallery');
  83. $tv=$this->tablename('catalog_product_entity_media_gallery_value');
  84. $sql="DELETE $tv.* FROM $tv
  85. JOIN $t ON $t.value_id=$tv.value_id AND $t.entity_id=? AND $t.attribute_id=?
  86. WHERE $tv.store_id=?";
  87. $this->delete($sql,array($pid,$attrdesc["attribute_id"],$storeid));
  88. }
  89. public function getExclude(&$val,$default=true)
  90. {
  91. $exclude=$default;
  92. if($val[0]=="+" || $val[0]=="-")
  93. {
  94. $exclude=$val[0]=="-";
  95. $val=substr($val,1);
  96. }
  97. return $exclude;
  98. }
  99. public function handleImageTypeAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
  100. {
  101. //remove attribute value if empty
  102. if($ivalue=="")
  103. {
  104. $this->removeImageFromGallery($pid,$storeid,$attrdesc);
  105. return "__MAGMI_DELETE__";
  106. }
  107. //add support for explicit exclude
  108. $exclude=$this->getExclude($ivalue,true);
  109. //else copy image file
  110. $imagefile=$this->copyImageFile($ivalue,$item,array("store"=>$storeid,"attr_code"=>$attrcode));
  111. $ovalue=$imagefile;
  112. //add to gallery as excluded
  113. if($imagefile!==false)
  114. {
  115. $label=null;
  116. if(isset($item[$attrcode."_label"]))
  117. {
  118. $label=$item[$attrcode."_label"];
  119. }
  120. $targetsids=$this->getStoreIdsForStoreScope($item["store"]);
  121. $vid=$this->addImageToGallery($pid,$storeid,$attrdesc,$imagefile,$targetsids,$label,$exclude,$attrdesc["attribute_id"]);
  122. }
  123. return $ovalue;
  124. }
  125. public function handleVarcharAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
  126. {
  127. //if it's a gallery
  128. switch($attrdesc["frontend_input"])
  129. {
  130. case "gallery":
  131. $ovalue=$this->handleGalleryTypeAttribute($pid,$item,$storeid,$attrcode,$attrdesc,$ivalue);
  132. break;
  133. case "media_image":
  134. $ovalue=$this->handleImageTypeAttribute($pid,$item,$storeid,$attrcode,$attrdesc,$ivalue);
  135. break;
  136. default:
  137. $ovalue="__MAGMI_UNHANDLED__";
  138. }
  139. return $ovalue;
  140. }
  141. /**
  142. * imageInGallery
  143. * @param int $pid : product id to test image existence in gallery
  144. * @param string $imgname : image file name (relative to /products/media in magento dir)
  145. * @return bool : if image is already present in gallery for a given product id
  146. */
  147. public function getImageId($pid,$attid,$imgname,$refid=null)
  148. {
  149. $t=$this->tablename('catalog_product_entity_media_gallery');
  150. $sql="SELECT $t.value_id FROM $t ";
  151. if($refid!=null)
  152. {
  153. $vc=$this->tablename('catalog_product_entity_varchar');
  154. $sql.=" JOIN $vc ON $t.entity_id=$vc.entity_id AND $t.value=$vc.value AND $vc.attribute_id=?
  155. WHERE $t.entity_id=?";
  156. $imgid=$this->selectone($sql,array($refid,$pid),'value_id');
  157. }
  158. else
  159. {
  160. $sql.=" WHERE value=? AND entity_id=? AND attribute_id=?";
  161. $imgid=$this->selectone($sql,array($imgname,$pid,$attid),'value_id');
  162. }
  163. if($imgid==null)
  164. {
  165. // insert image in media_gallery
  166. $sql="INSERT INTO $t
  167. (attribute_id,entity_id,value)
  168. VALUES
  169. (?,?,?)";
  170. $imgid=$this->insert($sql,array($attid,$pid,$imgname));
  171. }
  172. else
  173. {
  174. $sql="UPDATE $t
  175. SET value=?
  176. WHERE value_id=?";
  177. $this->update($sql,array($imgname,$imgid));
  178. }
  179. return $imgid;
  180. }
  181. /**
  182. * reset product gallery
  183. * @param int $pid : product id
  184. */
  185. public function resetGallery($pid,$storeid,$attid)
  186. {
  187. $tgv=$this->tablename('catalog_product_entity_media_gallery_value');
  188. $tg=$this->tablename('catalog_product_entity_media_gallery');
  189. $sql="DELETE emgv,emg FROM `$tgv` as emgv
  190. JOIN `$tg` AS emg ON emgv.value_id = emg.value_id AND emgv.store_id=?
  191. WHERE emg.entity_id=? AND emg.attribute_id=?";
  192. $this->delete($sql,array($storeid,$pid,$attid));
  193. }
  194. /**
  195. * adds an image to product image gallery only if not already exists
  196. * @param int $pid : product id to test image existence in gallery
  197. * @param array $attrdesc : product attribute description
  198. * @param string $imgname : image file name (relative to /products/media in magento dir)
  199. */
  200. public function addImageToGallery($pid,$storeid,$attrdesc,$imgname,$targetsids,$imglabel=null,$excluded=false,$refid=null)
  201. {
  202. $gal_attinfo=$this->getAttrInfo("media_gallery");
  203. $tg=$this->tablename('catalog_product_entity_media_gallery');
  204. $tgv=$this->tablename('catalog_product_entity_media_gallery_value');
  205. $vid=$this->getImageId($pid,$gal_attinfo["attribute_id"],$imgname,$refid);
  206. if($vid!=null)
  207. {
  208. #get maximum current position in the product gallery
  209. $sql="SELECT MAX( position ) as maxpos
  210. FROM $tgv AS emgv
  211. JOIN $tg AS emg ON emg.value_id = emgv.value_id AND emg.entity_id = ?
  212. WHERE emgv.store_id=?
  213. GROUP BY emg.entity_id";
  214. $pos=$this->selectone($sql,array($pid,$storeid),'maxpos');
  215. $pos=($pos==null?0:$pos+1);
  216. #insert new value (ingnore duplicates)
  217. $vinserts=array();
  218. $data=array();
  219. foreach($targetsids as $tsid)
  220. {
  221. $vinserts[]="(?,?,?,?,".($imglabel==null?"NULL":"?").")";
  222. $data=array_merge($data,array($vid,$tsid,$pos,$excluded?1:0));
  223. if($imglabel!=null)
  224. {
  225. $data[]=$imglabel;
  226. }
  227. }
  228. if(count($data)>0)
  229. {
  230. $sql="INSERT INTO $tgv
  231. (value_id,store_id,position,disabled,label)
  232. VALUES ".implode(",",$vinserts)."
  233. ON DUPLICATE KEY UPDATE label=VALUES(`label`)";
  234. $this->insert($sql,$data);
  235. }
  236. unset($vinserts);
  237. unset($data);
  238. }
  239. }
  240. public function parsename($info,$item,$extra)
  241. {
  242. $matches=array();
  243. while(preg_match("|\{item\.(.*?)\}|",$info,$matches))
  244. {
  245. foreach($matches as $match)
  246. {
  247. if($match!=$matches[0])
  248. {
  249. if(isset($item[$match]))
  250. {
  251. $rep=$item[$match];
  252. }
  253. else
  254. {
  255. $rep="";
  256. }
  257. $info=str_replace($matches[0],$rep,$info);
  258. }
  259. }
  260. }
  261. while(preg_match("|\{magmi\.(.*?)\}|",$info,$matches))
  262. {
  263. foreach($matches as $match)
  264. {
  265. if($match!=$matches[0])
  266. {
  267. if(isset($extra[$match]))
  268. {
  269. $rep=$extra[$match];
  270. }
  271. else
  272. {
  273. $rep="";
  274. }
  275. $info=str_replace($matches[0],$rep,$info);
  276. }
  277. }
  278. }
  279. unset($matches);
  280. return $info;
  281. }
  282. public function getPluginParams($params)
  283. {
  284. $pp=array();
  285. foreach($params as $k=>$v)
  286. {
  287. if(preg_match("/^IMG(_ERR)?:.*$/",$k))
  288. {
  289. $pp[$k]=$v;
  290. }
  291. }
  292. return $pp;
  293. }
  294. public function fillErrorAttributes(&$item)
  295. {
  296. foreach($this->errattrs as $k=>$v)
  297. {
  298. $this->addExtraAttribute($k);
  299. $item[$k]=$v;
  300. }
  301. }
  302. public function getTargetName($fname,$item,$extra)
  303. {
  304. $cname=$fname;
  305. if(isset($this->forcename) && $this->forcename!="")
  306. {
  307. $matches=array();
  308. $m=preg_match("/(.*)\.(jpg|png|gif)$/i",$cname,$matches);
  309. if($m)
  310. {
  311. $extra["imagename"]=$cname;
  312. $extra["imagename.ext"]=$matches[2];
  313. $extra["imagename.noext"]=$matches[1];
  314. }
  315. else
  316. {
  317. $uid=uniqid("img",true);
  318. $extra=array("imagename"=>"$uid.jpg","imagename.ext"=>"jpg","imagename.noext"=>$uid);
  319. }
  320. $cname=$this->parsename($this->forcename,$item,$extra);
  321. unset($matches);
  322. }
  323. $cname=strtolower(preg_replace("/%[0-9][0-9|A-F]/","_",rawurlencode($cname)));
  324. return $cname;
  325. }
  326. public function createUrlContext($url)
  327. {
  328. if(function_exists("curl_init"))
  329. {
  330. $handle = curl_init(str_replace(" ","%20",$url));
  331. //add support for https urls
  332. curl_setopt($handle, CURLOPT_SSL_VERIFYPEER ,false);
  333. }
  334. return $handle;
  335. }
  336. public function destroyUrlContext($context)
  337. {
  338. if($context!=false)
  339. {
  340. curl_close($context);
  341. }
  342. unset($context);
  343. }
  344. //Url testing
  345. public function Urlexists($url,$context)
  346. {
  347. //optimized lookup through curl
  348. if($context!==false)
  349. {
  350. /* head */
  351. curl_setopt($context, CURLOPT_HEADER, TRUE);
  352. curl_setopt( $context, CURLOPT_RETURNTRANSFER, true );
  353. curl_setopt( $context, CURLOPT_CUSTOMREQUEST, 'HEAD' );
  354. curl_setopt( $context, CURLOPT_NOBODY, true );
  355. /* Get the HTML or whatever is linked in $url. */
  356. $response = curl_exec($context);
  357. /* Check for 404 (file not found). */
  358. $httpCode = curl_getinfo($context, CURLINFO_HTTP_CODE);
  359. $exists = ($httpCode==200);
  360. /* retry on error */
  361. if($httpCode==503 or $httpCode==403)
  362. {
  363. /* wait for a half second */
  364. usleep(500000);
  365. $response = curl_exec($context);
  366. $httpCode = curl_getinfo($context, CURLINFO_HTTP_CODE);
  367. $exists = ($httpCode==200);
  368. }
  369. }
  370. else
  371. {
  372. $fname=$url;
  373. $h=@fopen($fname,"r");
  374. if($h!==false)
  375. {
  376. $exists=true;
  377. fclose($h);
  378. }
  379. unset($h);
  380. }
  381. return $exists;
  382. }
  383. public function saveImage($imgfile,$target,$context)
  384. {
  385. if($context==false)
  386. {
  387. if(!@copy($this->getImageFSPath($imgfile),$target))
  388. {
  389. return false;
  390. }
  391. }
  392. else
  393. {
  394. $fp = @fopen($target, 'wb');
  395. if($fp!==false)
  396. {
  397. curl_setopt($context, CURLOPT_RETURNTRANSFER, false);
  398. curl_setopt( $context, CURLOPT_CUSTOMREQUEST, 'GET' );
  399. curl_setopt( $context, CURLOPT_NOBODY, false);
  400. curl_setopt($context, CURLOPT_FILE, $fp);
  401. curl_setopt($context, CURLOPT_HEADER, 0);
  402. curl_setopt($context,CURLOPT_FAILONERROR,true);
  403. if(!ini_get('safe_mode'))
  404. {
  405. curl_setopt($context, CURLOPT_FOLLOWLOCATION, 1);
  406. }
  407. curl_exec($context);
  408. @fclose($fp);
  409. if(curl_getinfo($context,CURLINFO_HTTP_CODE)>=400)
  410. {
  411. $errors=array("type"=>"download error","message"=>curl_error($ch));
  412. $this->fillErrorAttributes($item);
  413. $this->log("error copying $target : {$errors["type"]},{$errors["message"]}","warning");
  414. unset($errors);
  415. @unlink($target);
  416. return false;
  417. }
  418. return true;
  419. }
  420. else
  421. {
  422. $errors= error_get_last();
  423. $this->fillErrorAttributes($item);
  424. $this->log("error copying $target : {$errors["type"]},{$errors["message"]}","warning");
  425. unset($errors);
  426. return false;
  427. }
  428. }
  429. return true;
  430. }
  431. public function getImageFSPath($imgfile,$rp=false)
  432. {
  433. $first=$imgfile[0];
  434. $tfile=($first=="/"?substr($imgfile,1):$imgfile);
  435. $fspath=$this->imgsourcedir.DIRECTORY_SEPARATOR.$tfile;
  436. return $rp?realpath($fspath):$fspath;
  437. }
  438. /**
  439. * copy image file from source directory to
  440. * product media directory
  441. * @param $imgfile : name of image file name in source directory
  442. * @return : name of image file name relative to magento catalog media dir,including leading
  443. * directories made of first char & second char of image file name.
  444. */
  445. public function copyImageFile($imgfile,&$item,$extra)
  446. {
  447. if($imgfile==$this->_lastnotfound)
  448. {
  449. if($this->_newitem){
  450. $this->fillErrorAttributes($item);
  451. };
  452. return false;
  453. }
  454. $checkexist= ($this->getParam("IMG:existingonly")=="yes");
  455. $curlh=false;
  456. $bimgfile=$this->getTargetName(basename($imgfile),$item,$extra);
  457. //source file exists
  458. $i1=$bimgfile[0];
  459. $i2=$bimgfile[1];
  460. $l1d="$this->magdir/media/catalog/product/$i1";
  461. $l2d="$l1d/$i2";
  462. $te="$l2d/$bimgfile";
  463. $result="/$i1/$i2/$bimgfile";
  464. /* test for same image */
  465. if($result==$this->_lastimage)
  466. {
  467. return $result;
  468. }
  469. /* test if imagefile comes from export */
  470. if(!file_exists("$te") || $this->getParam("IMG:writemode")=="override")
  471. {
  472. $exists=false;
  473. $fname=$imgfile;
  474. if(preg_match("|.*?://.*|",$imgfile))
  475. {
  476. $imgfile=str_replace($bimgfile,urlencode($bimgfile),$imgfile);
  477. $curlh=$this->createUrlContext($imgfile);
  478. //only check existence on with HEAD ping if enabled
  479. if($this->getParam("IMG:predlcheck","yes")=="yes")
  480. {
  481. $exists=$this->Urlexists($imgfile,$curlh);
  482. }
  483. else
  484. {
  485. //assume existing on remote
  486. $exists=true;
  487. }
  488. }
  489. else
  490. {
  491. $exists=($this->getImageFSPath($imgfile,true)!==false);
  492. }
  493. if(!$exists)
  494. {
  495. $this->log("$fname not found, skipping image","warning");
  496. $this->fillErrorAttributes($item);
  497. $this->_lastnotfound=$imgfile;
  498. $this->destroyUrlContext($curlh);
  499. return false;
  500. }
  501. if($exists)
  502. {
  503. /* test if 1st level product media dir exists , create it if not */
  504. if(!file_exists("$l1d"))
  505. {
  506. $tst=@mkdir($l1d,Magmi_Config::getInstance()->getDirMask());
  507. if(!$tst)
  508. {
  509. $errors= error_get_last();
  510. $this->log("error creating $l1d: {$errors["type"]},{$errors["message"]}","warning");
  511. unset($errors);
  512. $this->destroyUrlContext($curlh);
  513. return false;
  514. }
  515. }
  516. /* test if 2nd level product media dir exists , create it if not */
  517. if(!file_exists("$l2d"))
  518. {
  519. $tst=@mkdir($l2d,Magmi_Config::getInstance()->getDirMask());
  520. if(!$tst)
  521. {
  522. $errors= error_get_last();
  523. $this->log("error creating $l2d: {$errors["type"]},{$errors["message"]}","warning");
  524. unset($errors);
  525. $this->destroyUrlContext($curlh);
  526. return false;
  527. }
  528. }
  529. if(!$this->saveImage($imgfile,"$l2d/$bimgfile",$curlh))
  530. {
  531. $errors=error_get_last();
  532. $this->fillErrorAttributes($item);
  533. $this->log("error copying $l2d/$bimgfile : {$errors["type"]},{$errors["message"]}","warning");
  534. unset($errors);
  535. $this->destroyUrlContext($curlh);
  536. return false;
  537. }
  538. $this->destroyUrlContext($curlh);
  539. @chmod("$l2d/$bimgfile",Magmi_Config::getInstance()->getFileMask());
  540. }
  541. }
  542. $this->_lastimage=$result;
  543. /* return image file name relative to media dir (with leading / ) */
  544. return $result;
  545. }
  546. public function updateLabel($attrdesc,$pid,$sids,$label)
  547. {
  548. $tg=$this->tablename('catalog_product_entity_media_gallery');
  549. $tgv=$this->tablename('catalog_product_entity_media_gallery_value');
  550. $vc=$this->tablename('catalog_product_entity_varchar');
  551. $sql="UPDATE $tgv as emgv
  552. JOIN $tg as emg ON emg.value_id=emgv.value_id AND emg.entity_id=?
  553. JOIN $vc as ev ON ev.entity_id=emg.entity_id AND ev.value=emg.value and ev.attribute_id=?
  554. SET label=?
  555. WHERE emgv.store_id IN (".implode(",",$sids).")";
  556. $this->update($sql,array($pid,$attrdesc["attribute_id"],$label));
  557. }
  558. public function processItemAfterId(&$item,$params=null)
  559. {
  560. if(!$this->_active)
  561. {
  562. return true;
  563. }
  564. $this->_newitem=$params["new"];
  565. $pid=$params["product_id"];
  566. foreach($this->_img_baseattrs as $attrcode)
  567. {
  568. //if only image/small_image/thumbnail label is present (ie: no image field)
  569. if(isset($item[$attrcode."_label"]) && !isset($item[$attrcode]))
  570. {
  571. //force label update
  572. $attrdesc=$this->getAttrInfo($attrcode);
  573. $this->updateLabel($attrdesc,$pid,$this->getItemStoreIds($item,$attr_desc["is_global"]),$item[$attrcode."_label"]);
  574. unset($attrdesc);
  575. }
  576. }
  577. //Reset media_gallery
  578. $galreset=!(isset($item["media_gallery_reset"])) || $item["media_gallery_reset"]==1;
  579. $forcereset = (isset($item["media_gallery_reset"])) && $item["media_gallery_reset"]==1;
  580. if( (isset($item["media_gallery"]) && $galreset) || $forcereset)
  581. {
  582. $gattrdesc=$this->getAttrInfo("media_gallery");
  583. $sids=$this->getItemStoreIds($item,$gattrdesc["is_global"]);
  584. foreach($sids as $sid)
  585. {
  586. $this->resetGallery($pid,$sid,$gattrdesc["attribute_id"]);
  587. }
  588. }
  589. return true;
  590. }
  591. public function processColumnList(&$cols,$params=null)
  592. {
  593. //automatically add modified attributes if not found in datasource
  594. //automatically add media_gallery for attributes to handle
  595. $imgattrs=array_intersect(array_merge($this->_img_baseattrs,array('media_gallery')),$cols);
  596. if(count($imgattrs)>0)
  597. {
  598. $this->_active=true;
  599. $cols=array_unique(array_merge(array_keys($this->errattrs),$cols,$imgattrs));
  600. }
  601. else
  602. {
  603. $this->log("no image attributes found in datasource, disabling image processor","startup");
  604. }
  605. return true;
  606. }
  607. //Cleanup gallery from removed images if no more image values are present in any store
  608. public function endImport()
  609. {
  610. if(!$this->_active)
  611. {
  612. return;
  613. }
  614. $attids=array();
  615. foreach($this->_img_baseattrs as $attrcode)
  616. {
  617. $inf=$this->getAttrInfo($attrcode);
  618. if(count($inf)>0)
  619. {
  620. $attids[]=$inf["attribute_id"];
  621. }
  622. }
  623. if(count($attids)>0)
  624. {
  625. $tg=$this->tablename('catalog_product_entity_media_gallery');
  626. $tgv=$this->tablename('catalog_product_entity_media_gallery_value');
  627. $sql="DELETE emg.* FROM $tg as emg
  628. LEFT JOIN (SELECT emg.value_id,count(emgv.value_id) as cnt FROM $tgv as emgv JOIN $tg as emg ON emg.value_id=emgv.value_id GROUP BY emg.value_id ) as t1 ON t1.value_id=emg.value_id
  629. WHERE attribute_id IN (".implode(",",$attids).") AND t1.cnt IS NULL";
  630. $this->delete($sql);
  631. }
  632. else
  633. {
  634. $this->log("Unexpected problem in image attributes retrieval","warning");
  635. }
  636. unset($attids);
  637. }
  638. }