> * * ----------------------------------------------------------------------------- * * See main.inc.php for release information * * AIP classe => manage integration in administration interface * * ----------------------------------------------------------------------------- */ if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); } include_once('amd_root.class.inc.php'); include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php'); include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/ajax.class.inc.php'); include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/genericjs.class.inc.php'); class AMD_AIP extends AMD_root { protected $tabsheet; protected $ajax; protected $jpegMD; /** * * constructor needs the prefix of piwigo's tables and the location of plugin * * @param String $prefixeTable * @param String $filelocation */ function __construct($prefixeTable, $filelocation) { parent::__construct($prefixeTable, $filelocation); $this->load_config(); $this->init_events(); $this->tabsheet = new tabsheet(); $this->tabsheet->add('metadata', l10n('g003_metadata'), $this->page_link.'&fAMD_tabsheet=metadata'); $this->tabsheet->add('database', l10n('g003_database'), $this->page_link.'&fAMD_tabsheet=database'); $this->ajax = new Ajax(); $this->jpegMD=new JpegMetaData(); } function __destruct() { unset($this->tabsheet); unset($this->ajax); unset($this->jpegMD); } /* * --------------------------------------------------------------------------- * Public classe functions * --------------------------------------------------------------------------- */ /** * manage the plugin integration into piwigo's admin interface */ public function manage() { global $template, $page; $template->set_filename('plugin_admin_content', dirname(__FILE__)."/admin/amd_admin.tpl"); $this->initRequest(); $this->returnAjaxContent(); $this->tabsheet->select($_REQUEST['fAMD_tabsheet']); $this->tabsheet->assign(); $selected_tab=$this->tabsheet->get_selected(); $template->assign($this->tabsheet->get_titlename(), "[".$selected_tab['caption']."]"); $template_plugin["AMD_VERSION"] = "".$this->plugin_name." ".l10n('g003_version').AMD_VERSION; $template_plugin["AMD_PAGE"] = $_REQUEST['fAMD_tabsheet']; $template_plugin["PATH"] = AMD_PATH; $template->assign('plugin', $template_plugin); if($_REQUEST['fAMD_tabsheet']=='database') { $this->displayDatabase(); } elseif($_REQUEST['fAMD_tabsheet']=='metadata') { $this->displayMetaData($_REQUEST['fAMD_page']); } $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content'); } /** * initialize events call for the plugin */ public function init_events() { add_event_handler('loc_end_page_header', array(&$this->css, 'apply_CSS')); } /** * --------------------------------------------------------------------------- * Private & protected functions * --------------------------------------------------------------------------- */ /** * manage the ajax requests * this function function determine if there is an ajax call, manage the * request and returns the content of the request * * no params are given, the function works with the "$_REQUEST" var * * @return String */ protected function returnAjaxContent() { global $ajax, $template; if(isset($_REQUEST['ajaxfct'])) { //$this->debug("AJAXFCT:".$_REQUEST['ajaxfct']); $result="
".l10n('g002_error_invalid_ajax_call')."
"; switch($_REQUEST['ajaxfct']) { case 'makeStatsGetList': $result=$this->ajax_amd_makeStatsGetList($_REQUEST['selectMode'], $_REQUEST['numOfItems']); break; case 'makeStatsDoAnalyze': $result=$this->ajax_amd_makeStatsDoAnalyze($_REQUEST['imagesList']); break; case 'makeStatsConsolidation': $result=$this->ajax_amd_makeStatsConsolidation(); break; case 'makeStatsGetStatus': $result=$this->ajax_amd_makeStatsGetStatus(); break; case 'showStatsGetListTags': $result=$this->ajax_amd_showStatsGetListTags($_REQUEST['orderType'], $_REQUEST['filterType'], $_REQUEST['excludeUnusedTag'], $_REQUEST['selectedTagOnly']); break; case 'showStatsGetListImages': $result=$this->ajax_amd_showStatsGetListImages($_REQUEST['tagId'], $_REQUEST['orderType']); break; case 'updateTagSelect': $result=$this->ajax_amd_updateTagSelect($_REQUEST['numId'], $_REQUEST['tagSelected']); break; case 'groupGetList': $result=$this->ajax_amd_groupGetList(); break; case 'groupDelete': $result=$this->ajax_amd_groupDelete($_REQUEST['id']); break; case 'groupGetNames': $result=$this->ajax_amd_groupGetNames($_REQUEST['id']); break; case 'groupSetNames': $result=$this->ajax_amd_groupSetNames($_REQUEST['id'], $_REQUEST['listNames']); break; case 'groupSetOrder': $result=$this->ajax_amd_groupSetOrder($_REQUEST['listGroup']); break; case 'groupGetTagList': $result=$this->ajax_amd_groupGetTagList($_REQUEST['id']); break; case 'groupSetTagList': $result=$this->ajax_amd_groupSetTagList($_REQUEST['id'], $_REQUEST['listTag']); break; case 'groupGetOrderedTagList': $result=$this->ajax_amd_groupGetOrderedTagList($_REQUEST['id']); break; case 'groupSetOrderedTagList': $result=$this->ajax_amd_groupSetOrderedTagList($_REQUEST['id'], $_REQUEST['listTag']); break; } $this->ajax->return_result($result); } } /** * if empty, initialize the $_REQUEST var * * if not empty, check validity for the request values * */ private function initRequest() { //initialise $REQUEST values if not defined if($this->getNumOfPictures()==0) { $defautTabsheet="database"; } else { $defautTabsheet="metadata"; } if(!isset($_REQUEST['fAMD_tabsheet'])) { $_REQUEST['fAMD_tabsheet']=$defautTabsheet; } if($_REQUEST['fAMD_tabsheet']!="metadata" and $_REQUEST['fAMD_tabsheet']!="database") { $_REQUEST['fAMD_tabsheet']=$defautTabsheet; } if($_REQUEST['fAMD_tabsheet']=="metadata" and !isset($_REQUEST['fAMD_page'])) { $_REQUEST['fAMD_page']="select"; } if($_REQUEST['fAMD_tabsheet']=="metadata" and !($_REQUEST['fAMD_page']=="select" or $_REQUEST['fAMD_page']=="display")) { $_REQUEST['fAMD_page']="select"; } /* * check ajax */ if(isset($_REQUEST['ajaxfct'])) { /* * check makeStatsGetList values */ if($_REQUEST['ajaxfct']=="makeStatsGetList" and !isset($_REQUEST['selectMode'])) { $_REQUEST['selectMode']="notAnalyzed"; } if($_REQUEST['ajaxfct']=="makeStatsGetList" and !($_REQUEST['selectMode']=="notAnalyzed" or $_REQUEST['selectMode']=="all")) { $_REQUEST['selectMode']="notAnalyzed"; } if($_REQUEST['ajaxfct']=="makeStatsGetList" and !isset($_REQUEST['numOfItems'])) { $_REQUEST['numOfItems']=25; } /* * check makeStatsDoAnalyze values */ if($_REQUEST['ajaxfct']=="makeStatsDoAnalyze" and !isset($_REQUEST['imagesList'])) { $_REQUEST['imagesList']=""; } /* * check makeStatsConsolidate values */ if($_REQUEST['ajaxfct']=="makeStatsConsolidate" and !isset($_REQUEST['step'])) { $_REQUEST['step']="*"; } /* * check showStatsGetListTags values */ if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['orderType'])) { $_REQUEST['orderType']="tag"; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !($_REQUEST['orderType']=="tag" or $_REQUEST['orderType']=="num")) { $_REQUEST['orderType']="tag"; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['filterType'])) { $_REQUEST['filterType']=""; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !($_REQUEST['filterType']=="" or $_REQUEST['filterType']=="magic" or $_REQUEST['filterType']=="exif" or $_REQUEST['filterType']=="xmp" or $_REQUEST['filterType']=="iptc")) { $_REQUEST['filterType']=""; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['excludeUnusedTag'])) { $_REQUEST['excludeUnusedTag']="n"; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !($_REQUEST['excludeUnusedTag']=="y" or $_REQUEST['excludeUnusedTag']=="n" )) { $_REQUEST['excludeUnusedTag']="n"; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['selectedTagOnly'])) { $_REQUEST['selectedTagOnly']="n"; } if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !($_REQUEST['selectedTagOnly']=="y" or $_REQUEST['selectedTagOnly']=="n" )) { $_REQUEST['selectedTagOnly']="n"; } /* * check showStatsGetListImagess values */ if($_REQUEST['ajaxfct']=="showStatsGetListImages" and !isset($_REQUEST['orderType'])) { $_REQUEST['orderType']="num"; } if($_REQUEST['ajaxfct']=="showStatsGetListImages" and !($_REQUEST['orderType']=="value" or $_REQUEST['orderType']=="num")) { $_REQUEST['orderType']="num"; } if($_REQUEST['ajaxfct']=="showStatsGetListImages" and !isset($_REQUEST['tagId'])) { $_REQUEST['tagId']="*"; } /* * check showStatsGetListImagess values */ if($_REQUEST['ajaxfct']=="updateTagSelect" and !isset($_REQUEST['numId'])) { $_REQUEST['numId']=""; } if($_REQUEST['ajaxfct']=="updateTagSelect" and !isset($_REQUEST['tagSelected'])) { $_REQUEST['tagSelected']=""; } /* * check groupDelete values */ if($_REQUEST['ajaxfct']=="groupDelete" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } /* * check groupSetOrder values */ if($_REQUEST['ajaxfct']=="groupSetOrder" and !isset($_REQUEST['listGroup'])) { $_REQUEST['listGroup']=""; } /* * check groupGetNames values */ if($_REQUEST['ajaxfct']=="groupGetNames" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } /* * check groupSetNames values */ if($_REQUEST['ajaxfct']=="groupSetNames" and !isset($_REQUEST['listNames'])) { $_REQUEST['listNames']=""; } if($_REQUEST['ajaxfct']=="groupSetNames" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } /* * check groupGetTagList values */ if($_REQUEST['ajaxfct']=="groupGetTagList" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } /* * check groupSetTagList values */ if($_REQUEST['ajaxfct']=="groupSetTagList" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } if($_REQUEST['ajaxfct']=="groupSetTagList" and !isset($_REQUEST['listTag'])) { $_REQUEST['listTag']=""; } /* * check groupGetOrderedTagList values */ if($_REQUEST['ajaxfct']=="groupGetOrderedTagList" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } /* * check groupSetOrderedTagList values */ if($_REQUEST['ajaxfct']=="groupSetOrderedTagList" and !isset($_REQUEST['id'])) { $_REQUEST['id']=""; } if($_REQUEST['ajaxfct']=="groupSetOrderedTagList" and !isset($_REQUEST['listTag'])) { $_REQUEST['listTag']=""; } } } //init_request /** * manage adviser profile * * @return Boolean : true if user is adviser, otherwise false (and push a * message in the error list) */ protected function adviser_abort() { if(is_adviser()) { $this->display_result(l10n("g003_adviser_not_allowed"), false); return(true); } return(false); } /** * display and manage the database page * * the function automatically update the AMD tables : * - add new pictures in the AMD image table (assuming image is not analyzed * yet) * - remove deleted pictures in the AMD image & image_tags table * * @return String : the content of the page */ private function displayDatabase() { global $template, $page; /* * insert new image (from piwigo images table) in the AMD images table, with * statut 'not analyzed' */ $sql="INSERT INTO ".$this->tables['images']." SELECT id, 'n', 0 FROM ".IMAGES_TABLE." WHERE id NOT IN (SELECT imageId FROM ".$this->tables['images'].")"; pwg_query($sql); /* * delete image who are in the AMD images table and not in the piwigo image * table */ $sql="DELETE FROM ".$this->tables['images']." WHERE imageId NOT IN (SELECT id FROM ".IMAGES_TABLE.")"; pwg_query($sql); /* * delete metdata for images that are not in the AMD image table */ $sql="DELETE FROM ".$this->tables['images_tags']." WHERE imageId NOT IN (SELECT imageId FROM ".$this->tables['images'].")"; pwg_query($sql); $template->set_filename('body_page', dirname(__FILE__).'/admin/amd_database.tpl'); $datas=array( 'urlRequest' => $this->page_link, 'NumberOfItemsPerRequest' => $this->my_config['amd_NumberOfItemsPerRequest'], ); $template->assign("datas", $datas); $template->assign_var_from_handle('AMD_BODY_PAGE', 'body_page'); } // displayDatabase /** * display and manage the metadata page * the page have two tabsheet : * - select tag management, to manage tags to be selected on the galerie * - display tag management, to choose how the tags are displayed * * @param String $tab : the selected tab on the stat page */ protected function displayMetaData($tab) { global $template, $user; $template->set_filename('body_page', dirname(__FILE__).'/admin/amd_metadata.tpl'); $statTabsheet = new tabsheet('statTabsheet', $this->tabsheet->get_titlename()); $statTabsheet->select($tab); $statTabsheet->add('select', l10n('g003_select'), $this->page_link.'&fAMD_tabsheet=metadata&fAMD_page=select'); $statTabsheet->add('display', l10n('g003_display'), $this->page_link.'&fAMD_tabsheet=metadata&fAMD_page=display'); $statTabsheet->assign(); if($tab=="select") { $template->assign('sheetContent', $this->displayMetaDataSelect()); } else { $template->assign('sheetContent', $this->displayMetaDataDisplay()); } $template->assign_var_from_handle('AMD_BODY_PAGE', 'body_page'); } /** * display and manage the metadata page allowing to make tags selection * * @return String : the content of the page */ protected function displayMetaDataSelect() { global $template; $template->set_filename('sheet_page', dirname($this->filelocation).'/admin/amd_metadata_select.tpl'); $datas=array( 'urlRequest' => $this->page_link, 'config_GetListTags_OrderType' => $this->my_config['amd_GetListTags_OrderType'], 'config_GetListTags_FilterType' => $this->my_config['amd_GetListTags_FilterType'], 'config_GetListTags_ExcludeUnusedTag' => $this->my_config['amd_GetListTags_ExcludeUnusedTag'], 'config_GetListTags_SelectedTagOnly' => $this->my_config['amd_GetListTags_SelectedTagOnly'], 'config_GetListImages_OrderType' => $this->my_config['amd_GetListImages_OrderType'] ); $template->assign('datas', $datas); return($template->parse('sheet_page', true)); } /** * display and manage the metadata page allowing to choose tags order * * @return String : the content of the page */ protected function displayMetaDataDisplay() { global $user, $template; //$local_tpl = new Template(AMD_PATH."admin/", ""); $template->set_filename('sheet_page', dirname($this->filelocation).'/admin/amd_metadata_display.tpl'); $datas=array( 'urlRequest' => $this->page_link, 'selectedTags' => Array(), 'groups' => Array(), 'tagByGroup' => Array(), ); $sql="SELECT st.tagId, st.order, st.groupId, ut.numId FROM ".$this->tables['selected_tags']." st LEFT JOIN ".$this->tables['used_tags']." ut ON ut.tagId = st.tagId ORDER BY st.groupId ASC, st.order ASC, st.tagId ASC"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_assoc($result)) { if($row['groupId']==-1) { $datas['selectedTags'][]=Array( 'numId' => $row['numId'], 'tagId' => $row['tagId'] ); } else { $datas['tagByGroup'][]=Array( 'numId' => $row['numId'], 'tagId' => $row['tagId'], 'group' => $row['groupId'], 'order' => $row['order'] ); } } } $sql="SELECT g.groupId, gn.name FROM ".$this->tables['groups']." g LEFT JOIN ".$this->tables['groups_names']." gn ON g.groupId = gn.groupId WHERE gn.lang = '".$user['language']."' ORDER BY g.order;"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_assoc($result)) { $datas['groups'][]=Array( 'id' => $row['groupId'], 'name' => $row['name'] ); } } $template->assign('datas', $datas); return($template->parse('sheet_page', true)); } /** * this function analyze tags from a picture, and insert the result into the * database * * NOTE : only implemented tags are analyzed and stored * * @param String $fileName : filename of picture to analyze * @param Integer $imageId : id of image in piwigo's database */ protected function analyzeImageFile($fileName, $imageId) { /* * the JpegMetaData object is instancied in the constructor */ $this->jpegMD->load($fileName, Array( 'filter' => JpegMetaData::TAGFILTER_IMPLEMENTED, 'optimizeIptcDateTime' => true) ); $sqlInsert=""; $massInsert=array(); $nbTags=0; foreach($this->jpegMD->getTags() as $key => $val) { $value=$val->getLabel(); if($val->isTranslatable()) $translatable="y"; else $translatable="n"; if($value instanceof DateTime) { $value=$value->format("Y-m-d H:i:s"); } elseif(is_array($value)) { /* * array values are stored in a serialized string */ $value=serialize($value); } $sql="SELECT numId FROM ".$this->tables['used_tags']." WHERE tagId = '$key'"; $result=pwg_query($sql); if($result) { $numId=-1; while($row=mysql_fetch_assoc($result)) { $numId=$row['numId']; } if($numId>0) { $nbTags++; if($sqlInsert!="") $sqlInsert.=", "; $sqlInsert.="($imageId, '$numId', '".addslashes($value)."')"; $massInsert[]=array( 'imageId' => $imageId, 'numId' => $numId, 'value' => addslashes($value) ); } } } /*if($sqlInsert!="") { $sqlInsert="INSERT INTO ".$this->tables['images_tags']." VALUES ".$sqlInsert; pwg_query($sqlInsert); }*/ mass_inserts($this->tables['images_tags'], array('imageId', 'numId', 'value'), $massInsert); $sql="UPDATE ".$this->tables['images']." SET analyzed = 'y', nbTags=".$nbTags." WHERE imageId=$imageId;"; pwg_query($sql); return("$imageId=$nbTags;"); } /** * returns the number of pictures analyzed * * @return Integer */ protected function getNumOfPictures() { $numOfPictures=0; $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']." WHERE analyzed='y';"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_row($result)) { $numOfPictures=$row[0]; } } return($numOfPictures); } /* * --------------------------------------------------------------------------- * ajax functions * --------------------------------------------------------------------------- */ /** * return a list of picture Id * * picture id are separated with a space " " * picture id are grouped in blocks of 'amd_NumberOfItemsPerRequest' items and * are separated with a semi-colon ";" * * client side just have to split blocks, and transmit it to the server * * There is two mode to determine the pictures being analyzed : * - "all" : analyze all the images * - "notAnalyzed" : analyze only the images not yet analyzed * * @param String $mode * @param Integer $nbOfItems : number of items per request * @return String : list of image id to be analyzed, separated with a space * "23 78 4523 5670" */ private function ajax_amd_makeStatsGetList($mode, $nbOfItems) { $returned=""; $this->my_config['amd_NumberOfItemsPerRequest']=$nbOfItems; $this->save_config(); $sql="SELECT imageId FROM ".$this->tables['images']; if($mode=="notAnalyzed") { $sql.=" WHERE analyzed='n'"; } else { pwg_query("UPDATE ".$this->tables['images']." SET analyzed='n', nbTags=0"); pwg_query("UPDATE ".$this->tables['used_tags']." SET numOfImg=0"); pwg_query("DELETE FROM ".$this->tables['images_tags']); } $result=pwg_query($sql); if($result) { $i=0; while($row=mysql_fetch_row($result)) { $returned.=$row[0]; $i++; if($i>=$nbOfItems) { $returned.=";"; $i=0; } else { $returned.=" "; } } } return(trim($returned).";"); } /** * extract metadata from images * * @param String $imageList : list of image id to be analyzed, separated with * a space * "23 78 4523 5670" * @return String : list of the analyzed pictures, with number of tags found * for each picture * "23=0;78=66;4523=33;5670=91;" */ private function ajax_amd_makeStatsDoAnalyze($imagesList) { $list=explode(" ", trim($imagesList)); $returned=""; if(count($list)>0) { // $path = path of piwigo's on the server filesystem $path=dirname(dirname(dirname(__FILE__))); $sql="SELECT id, path FROM ".IMAGES_TABLE." WHERE id IN (".implode(", ", $list).")"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_assoc($result)) { /* * in some case (in a combination of some pictures), when there is too * much pictures to analyze in the same request, a fatal error occurs * with the message : "Allowed memory size of XXXXX bytes exhausted" * * * tracking memory leak is not easy... :-( * */ //echo "analyzing:".$row['id']."\n"; //$mem1=memory_get_usage(); //echo "memory before analyze:".$mem1."\n"; $returned.=$this->analyzeImageFile($path."/".$row['path'], $row['id']); //echo $returned."\n"; //$mem2=memory_get_usage(); //echo "memory after analyze:".$mem2." (".($mem2-$mem1).")\n"; } } } return($returned); } /** * do some consolidation on database to optimize other requests * */ private function ajax_amd_makeStatsConsolidation() { $sql="UPDATE ".$this->tables['used_tags']." ut, (SELECT COUNT(imageId) AS nb, numId FROM ".$this->tables['images_tags']." GROUP BY numId) nb SET ut.numOfImg = nb.nb WHERE ut.numId = nb.numId;"; pwg_query($sql); } /** * returns a list of formated string, separated with a semi-colon : * - number of current analyzed pictures + number of current analyzed tags * for the analyzed pictures * - number of pictures not analyzed * - number of pictures without tag * * @return String */ private function ajax_amd_makeStatsGetStatus() { $numOfMetaData=0; $numOfPictures=0; $numOfPicturesNotAnalyzed=0; $sql="SELECT COUNT(imageId), SUM(nbTags) FROM ".$this->tables['images']." WHERE analyzed='y';"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_row($result)) { $numOfPictures=$row[0]; $numOfMetaData=$row[1]; } } $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']." WHERE analyzed='n';"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_row($result)) { $numOfPicturesNotAnalyzed=$row[0]; } } $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']." WHERE nbTags=0;"; $result=pwg_query($sql); if($result) { while($row=mysql_fetch_row($result)) { $numOfPicturesWithoutTags=$row[0]; } } return(sprintf(l10n("g003_numberOfAnalyzedPictures"), $numOfPictures, $numOfMetaData).";". sprintf(l10n("g003_numberOfNotAnalyzedPictures"), $numOfPicturesNotAnalyzed).";". sprintf(l10n("g003_numberOfPicturesWithoutTags"), $numOfPicturesWithoutTags)); } /** * return a formatted